diff --git a/Applications/Diffusion/CMakeLists.txt b/Applications/Diffusion/CMakeLists.txt index f6af42f8ae..6844ea78d9 100644 --- a/Applications/Diffusion/CMakeLists.txt +++ b/Applications/Diffusion/CMakeLists.txt @@ -1,103 +1,103 @@ #if(MITK_USE_Python) project(MitkDiffusion) set(DIFFUSIONAPP_NAME MitkDiffusion) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. set(DIFFUSIONIMAGINGAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DIFFUSIONAPP_NAME}.provisioning" CACHE INTERNAL "${DIFFUSIONAPP_NAME} provisioning file" FORCE) # should be identical to the list in /CMake/mitkBuildConfigurationmitkDiffusion.cmake # remember to set plugins which should be automatically toggled in target_libraries.cmake set(_plugins org.commontk.configadmin org.commontk.eventadmin org.blueberry.core.runtime org.blueberry.core.expressions org.blueberry.core.commands org.blueberry.ui.qt org.blueberry.ui.qt.log org.blueberry.ui.qt.help org.mitk.core.services org.mitk.gui.common org.mitk.planarfigure org.mitk.core.ext org.mitk.gui.qt.application org.mitk.gui.qt.ext org.mitk.gui.qt.diffusionimagingapp org.mitk.gui.qt.common org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.datamanager org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.segmentation - org.mitk.gui_qt.multilabelsegmentation +# org.mitk.gui_qt.multilabelsegmentation org.mitk.gui.qt.volumevisualization org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.diffusionimaging.connectomics org.mitk.gui.qt.diffusionimaging.fiberfox org.mitk.gui.qt.diffusionimaging.fiberprocessing org.mitk.gui.qt.diffusionimaging.ivim org.mitk.gui.qt.diffusionimaging.odfpeaks org.mitk.gui.qt.diffusionimaging.preprocessing org.mitk.gui.qt.diffusionimaging.reconstruction org.mitk.gui.qt.diffusionimaging.tractography org.mitk.gui.qt.diffusionimaging.registration # org.mitk.gui.qt.diffusionimaging.python org.mitk.gui.qt.diffusionimaging.denoising # org.mitk.gui.qt.matchpoint.algorithm.browser # org.mitk.gui.qt.matchpoint.algorithm.control # org.mitk.gui.qt.matchpoint.mapper org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.moviemaker org.mitk.gui.qt.basicimageprocessing org.mitk.gui.qt.properties org.mitk.gui.qt.viewnavigator ) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.extapplication ) set(_src_files MitkDiffusion.cpp ) qt5_add_resources(_src_files splashscreen.qrc) mitkFunctionCreateBlueBerryApplication( NAME ${DIFFUSIONAPP_NAME} DESCRIPTION "MITK Diffusion" PLUGINS ${_plugins} EXCLUDE_PLUGINS ${_exclude_plugins} SOURCES ${_src_files} ${_app_options} ) mitk_use_modules(TARGET ${DIFFUSIONAPP_NAME} MODULES MitkAppUtil) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(TARGET ${CMAKE_PROJECT_NAME}-autoload) add_dependencies(${DIFFUSIONAPP_NAME} ${CMAKE_PROJECT_NAME}-autoload) endif() # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) add_dependencies(${DIFFUSIONAPP_NAME} ${MITK_MODULES_ENABLED_PLUGINS}) endif() # endif() # MITK_USE_PYTHON diff --git a/Applications/Diffusion/target_libraries.cmake b/Applications/Diffusion/target_libraries.cmake index f208e9035d..e2b4c14e92 100644 --- a/Applications/Diffusion/target_libraries.cmake +++ b/Applications/Diffusion/target_libraries.cmake @@ -1,35 +1,35 @@ # A list of plug-in targets which should be automatically enabled # (or be available in external projects) for this application set(target_libraries org_blueberry_ui_qt org_blueberry_ui_qt_help org_mitk_planarfigure org_mitk_gui_qt_diffusionimagingapp org_mitk_gui_qt_ext org_mitk_gui_qt_datamanager org_mitk_gui_qt_segmentation - org_mitk_gui_qt_multilabelsegmentation +# org_mitk_gui_qt_multilabelsegmentation org_mitk_gui_qt_volumevisualization org_mitk_gui_qt_diffusionimaging org_mitk_gui_qt_diffusionimaging_connectomics org_mitk_gui_qt_diffusionimaging_fiberfox org_mitk_gui_qt_diffusionimaging_fiberprocessing org_mitk_gui_qt_diffusionimaging_ivim org_mitk_gui_qt_diffusionimaging_odfpeaks org_mitk_gui_qt_diffusionimaging_preprocessing org_mitk_gui_qt_diffusionimaging_reconstruction org_mitk_gui_qt_diffusionimaging_tractography org_mitk_gui_qt_diffusionimaging_registration # org_mitk_gui_qt_diffusionimaging_python org_mitk_gui_qt_diffusionimaging_denoising # org_mitk_gui_qt_matchpoint_algorithm_browser # org_mitk_gui_qt_matchpoint_algorithm_control # org_mitk_gui_qt_matchpoint_mapper org_mitk_gui_qt_imagenavigator org_mitk_gui_qt_moviemaker org_mitk_gui_qt_measurementtoolbox org_mitk_gui_qt_basicimageprocessing org_mitk_gui_qt_viewnavigator ) diff --git a/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/BuildConfigurations/DiffusionAll.cmake b/CMake/BuildConfigurations/DiffusionAll.cmake index 96f0ce462e..3b560dac34 100644 --- a/CMake/BuildConfigurations/DiffusionAll.cmake +++ b/CMake/BuildConfigurations/DiffusionAll.cmake @@ -1,37 +1,37 @@ message(STATUS "Configuring MITK Diffusion with all Plugins") # Enable non-optional external dependencies set(MITK_USE_Vigra ON CACHE BOOL "MITK Use Vigra Library" FORCE) set(MITK_USE_HDF5 ON CACHE BOOL "MITK Use HDF5 Library" FORCE) set(MITK_USE_MatchPoint ON CACHE BOOL "" FORCE) set(MITK_USE_DCMTK ON CACHE BOOL "" FORCE) -set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) -set(MITK_USE_Python ON CACHE BOOL "" FORCE) -set(MITK_USE_BetData ON CACHE BOOL "" FORCE) +#set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) +#set(MITK_USE_Python ON CACHE BOOL "" FORCE) +#set(MITK_USE_BetData ON CACHE BOOL "" FORCE) # Disable all apps but MITK Diffusion set(MITK_BUILD_ALL_APPS OFF CACHE BOOL "Build all MITK applications" FORCE) set(MITK_BUILD_APP_CoreApp OFF CACHE BOOL "Build the MITK CoreApp" FORCE) set(MITK_BUILD_APP_Diffusion ON CACHE BOOL "Build MITK Diffusion" FORCE) # Activate Diffusion Mini Apps set(BUILD_DiffusionCoreCmdApps ON CACHE BOOL "Build commandline tools for diffusion" FORCE) set(BUILD_DiffusionFiberProcessingCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber processing" FORCE) set(BUILD_DiffusionFiberfoxCmdApps ON CACHE BOOL "Build commandline tools for diffusion data simulation (Fiberfox)" FORCE) set(BUILD_DiffusionMiscCmdApps ON CACHE BOOL "Build miscellaneous commandline tools for diffusion" FORCE) set(BUILD_DiffusionQuantificationCmdApps ON CACHE BOOL "Build commandline tools for diffusion quantification (IVIM, ADC, ...)" FORCE) set(BUILD_DiffusionTractographyCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography" FORCE) set(BUILD_DiffusionTractographyEvaluationCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography evaluation" FORCE) set(BUILD_DiffusionConnectomicsCmdApps ON CACHE BOOL "Build commandline tools for diffusion connectomics" FORCE) # Build neither all plugins nor examples set(MITK_BUILD_ALL_PLUGINS OFF CACHE BOOL "Build all MITK plugins" FORCE) set(MITK_BUILD_EXAMPLES OFF CACHE BOOL "Build the MITK examples" FORCE) set(BUILD_TESTING ON CACHE BOOL "Build the MITK tests" FORCE) # Activate in-application help generation set(MITK_DOXYGEN_GENERATE_QCH_FILES ON CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) set(BLUEBERRY_USE_QT_HELP ON CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) # Disable console window set(MITK_SHOW_CONSOLE_WINDOW ON CACHE BOOL "Use this to enable or disable the console window when starting MITK GUI Applications" FORCE) diff --git a/CMake/BuildConfigurations/mitkNavigationModules.cmake b/CMake/BuildConfigurations/mitkNavigationModules.cmake index 456c1c877c..c315c718e0 100644 --- a/CMake/BuildConfigurations/mitkNavigationModules.cmake +++ b/CMake/BuildConfigurations/mitkNavigationModules.cmake @@ -1,38 +1,35 @@ message(STATUS "Configuring MITK Navigation Modules Build") set(MITK_CONFIG_PACKAGES ACVD Qt5 BLUEBERRY ) # Enable open cv and open igt link, which is a necessary configuration set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) # Enable default plugins and the navigation modules set(MITK_CONFIG_PLUGINS org.mitk.gui.qt.datamanager org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.dicom org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.properties org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.planarfigure org.mitk.gui.qt.moviemaker org.mitk.gui.qt.pointsetinteraction org.mitk.gui.qt.registration org.mitk.gui.qt.remeshing org.mitk.gui.qt.viewnavigator org.mitk.gui.qt.imagecropper - org.mitk.gui.qt.igtexamples org.mitk.gui.qt.igttracking - org.mitk.gui.qt.igtlplugin org.mitk.gui.qt.openigtlink org.mitk.gui.qt.ultrasound - org.mitk.gui.qt.toftutorial org.mitk.gui.qt.tofutil ) 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/CTK.cmake b/CMakeExternals/CTK.cmake index 1e4f031a9a..6614b6efd1 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,103 +1,103 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES DCMTK) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) - set(revision_tag 0d43ccf0) + set(revision_tag 0c2a619a) set(ctk_optional_cache_args ) if(MITK_USE_Python) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON -DCTK_ENABLE_Python_Wrapping:BOOL=ON -DCTK_APP_ctkSimplePythonShell:BOOL=ON -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ) else() list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=OFF -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF ) endif() if(NOT MITK_USE_Python) list(APPEND ctk_optional_cache_args -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=d ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND ctk_optional_cache_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() 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() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/CTK_${revision_tag}.tar.gz - URL_MD5 e40466b607529a6d80f0d08b19cc4f05 + URL_MD5 e1f94ba0199eccf335ec2c2b48e155da # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/CTK.patch UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} # The CTK PluginFramework cannot cope with # a non-empty CMAKE_DEBUG_POSTFIX for the plugin # libraries yet. -DCMAKE_DEBUG_POSTFIX:STRING= -DCTK_QT_VERSION:STRING=5 -DQt5_DIR=${Qt5_DIR} -DGit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_LIB_XNAT/Core:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DqRestAPI_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/qRestAPI_c5e4c2a7_patched.tar.gz -DPythonQt_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/PythonQt_e39be131.tar.gz # From https://github.com/kislinsk/PythonQt.git CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(CTK_DIR ${binary_dir}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() 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 461b43dfd6..d0987a8d8b 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,37 +1,37 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) -# set(revision_tag 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/CMakeExternals/QwtCMakeLists.txt b/CMakeExternals/QwtCMakeLists.txt index da0b33e27f..a9b41aecac 100644 --- a/CMakeExternals/QwtCMakeLists.txt +++ b/CMakeExternals/QwtCMakeLists.txt @@ -1,259 +1,258 @@ cmake_minimum_required(VERSION 3.1) project(Qwt) set(${PROJECT_NAME}_MAJOR_VERSION 6) set(${PROJECT_NAME}_MINOR_VERSION 1) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) set(QWT_MOC_HEADERS # General qwt_dyngrid_layout.h qwt_magnifier.h qwt_panner.h qwt_picker.h qwt_text_label.h # QwtPlot qwt_abstract_legend.h qwt_legend.h qwt_legend_label.h qwt_plot.h qwt_plot_renderer.h qwt_plot_canvas.h qwt_plot_panner.h qwt_plot_picker.h qwt_plot_zoomer.h qwt_plot_magnifier.h qwt_sampling_thread.h qwt_scale_widget.h # QwtOpenGL qwt_plot_glcanvas.h # QwtWidgets qwt_abstract_slider.h qwt_abstract_scale.h qwt_analog_clock.h qwt_compass.h qwt_counter.h qwt_dial.h qwt_knob.h qwt_slider.h qwt_thermo.h qwt_wheel.h ) set(QWT_SOURCES # General qwt_abstract_scale_draw.cpp qwt_clipper.cpp qwt_color_map.cpp qwt_column_symbol.cpp qwt_date.cpp qwt_date_scale_draw.cpp qwt_date_scale_engine.cpp qwt_dyngrid_layout.cpp qwt_event_pattern.cpp qwt_graphic.cpp qwt_interval.cpp qwt_interval_symbol.cpp qwt_math.cpp qwt_magnifier.cpp qwt_null_paintdevice.cpp qwt_painter.cpp qwt_painter_command.cpp qwt_panner.cpp qwt_picker.cpp qwt_picker_machine.cpp qwt_pixel_matrix.cpp qwt_point_3d.cpp qwt_point_polar.cpp qwt_round_scale_draw.cpp qwt_scale_div.cpp qwt_scale_draw.cpp qwt_scale_map.cpp qwt_spline.cpp qwt_scale_engine.cpp qwt_symbol.cpp qwt_system_clock.cpp qwt_text_engine.cpp qwt_text_label.cpp qwt_text.cpp qwt_transform.cpp qwt_widget_overlay.cpp # QwtPlot qwt_curve_fitter.cpp qwt_abstract_legend.cpp qwt_legend.cpp qwt_legend_data.cpp qwt_legend_label.cpp qwt_plot.cpp qwt_plot_renderer.cpp qwt_plot_xml.cpp qwt_plot_axis.cpp qwt_plot_curve.cpp qwt_plot_dict.cpp qwt_plot_directpainter.cpp qwt_plot_grid.cpp qwt_plot_histogram.cpp qwt_plot_item.cpp qwt_plot_abstract_barchart.cpp qwt_plot_barchart.cpp qwt_plot_multi_barchart.cpp qwt_plot_intervalcurve.cpp qwt_plot_zoneitem.cpp qwt_plot_tradingcurve.cpp qwt_plot_spectrogram.cpp qwt_plot_spectrocurve.cpp qwt_plot_scaleitem.cpp qwt_plot_legenditem.cpp qwt_plot_seriesitem.cpp qwt_plot_shapeitem.cpp qwt_plot_marker.cpp qwt_plot_textlabel.cpp qwt_plot_layout.cpp qwt_plot_canvas.cpp qwt_plot_panner.cpp qwt_plot_rasteritem.cpp qwt_plot_picker.cpp qwt_plot_zoomer.cpp qwt_plot_magnifier.cpp qwt_plot_rescaler.cpp qwt_point_mapper.cpp qwt_raster_data.cpp qwt_matrix_raster_data.cpp qwt_sampling_thread.cpp qwt_series_data.cpp qwt_point_data.cpp qwt_scale_widget.cpp # QwtSvg qwt_plot_svgitem.cpp # QwtOpenGL qwt_plot_glcanvas.cpp # QwtWidgets qwt_abstract_slider.cpp qwt_abstract_scale.cpp qwt_arrow_button.cpp qwt_analog_clock.cpp qwt_compass.cpp qwt_compass_rose.cpp qwt_counter.cpp qwt_dial.cpp qwt_dial_needle.cpp qwt_knob.cpp qwt_slider.cpp qwt_thermo.cpp qwt_wheel.cpp ) set(_qwt_moc_headers ) foreach(_header ${QWT_MOC_HEADERS}) list(APPEND _qwt_moc_headers src/${_header}) endforeach() set(_qwt_sources ) foreach(_source ${QWT_SOURCES}) list(APPEND _qwt_sources src/${_source}) endforeach() find_package(Qt5Svg REQUIRED) find_package(Qt5OpenGL REQUIRED) find_package(Qt5PrintSupport REQUIRED) find_package(Qt5Concurrent REQUIRED) qt5_wrap_cpp(_qwt_sources ${_qwt_moc_headers}) add_library(qwt SHARED ${_qwt_sources}) target_link_libraries(qwt PUBLIC Qt5::Svg Qt5::OpenGL Qt5::PrintSupport Qt5::Concurrent) target_compile_definitions(qwt PUBLIC QWT_DLL PRIVATE QWT_MAKEDLL) set_target_properties(qwt PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} ) # Build the designer plug-in include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) set(_qwt_designer_sources designer/qwt_designer_plotdialog.cpp designer/qwt_designer_plugin.cpp ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) find_package(Qt5Designer REQUIRED) include_directories(${Qt5Designer_INCLUDE_DIRS}) qt5_wrap_cpp(_qwt_designer_sources designer/qwt_designer_plugin.h designer/qwt_designer_plotdialog.h ) qt5_add_resources(_qwt_designer_sources designer/qwt_designer_plugin.qrc) add_library(qwt_designer_plugin SHARED ${_qwt_designer_sources}) -target_link_libraries(qwt_designer_plugin qwt) -qt5_use_modules(qwt_designer_plugin Designer) +target_link_libraries(qwt_designer_plugin qwt Qt5::Designer) set_target_properties(qwt_designer_plugin PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} COMPILE_DEFINITIONS QWT_DLL) set(${PROJECT_NAME}_LIBRARIES qwt) # Install support install(TARGETS qwt_designer_plugin RUNTIME DESTINATION plugins/designer LIBRARY DESTINATION plugins/designer ) install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin INCLUDES DESTINATION include/${PROJECT_NAME} ) install(DIRECTORY src/ DESTINATION include/${PROJECT_NAME} FILES_MATCHING PATTERN "*.h" ) # Config files configure_file( ${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(EXPORT ${PROJECT_NAME}_TARGETS FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake ) set(config_package_location lib/cmake/${PROJECT_NAME}) install(EXPORT ${PROJECT_NAME}_TARGETS FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${config_package_location} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${config_package_location} ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 228e87e623..bbeefc4676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1337 +1,1347 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.10) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.10/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") mark_as_advanced(MITK_EXTENSION_DIRS) #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2016.11.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTENSION_DIR}) list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_EXTENSION_DIR}) endif() endforeach() #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTestUseLaunchers) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Check miminum Mac OS X version #----------------------------------------------------------------------------- # The minimum supported Mac OS X version is 10.9. If you use a version less than 10.9, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE osx_version) if (osx_version VERSION_LESS "10.9") message(WARNING "Detected OS X version \"${osx_version}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.9) message(WARNING "Detected OS X deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2015 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) message(FATAL_ERROR "Microsoft Visual Studio 2015 Update 3 or newer required") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 14) set(CMAKE_CXX_EXTENSIONS 0) set(CMAKE_CXX_STANDARD ${MITK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED 1) # This is necessary to avoid problems with compile feature checks. # CMAKE_CXX_STANDARD seems to only set the -std=c++14 flag for targets. # However, compile flag checks also need to be done with -std=c++14. # The MITK_CXX14_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++14" MITK_CXX14_FLAG) #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 34) # _src_dir_length_max - strlen(ep/src/ITK-build) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- macro(env_option name doc value) set(_value $ENV{${name}}) if("${_value}" STREQUAL "") set(_value ${value}) endif() option(${name} "${doc}" ${_value}) endmacro() # ----------------------------------------- # General build options option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) env_option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) env_option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) # ----------------------------------------- # Qt version related variables env_option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION 5.6.0) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) set(MITK_QT5_COMPONENTS ${MITK_QT5_COMPONENTS} DBus) endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED) endif() set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) get_filename_component(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) include(${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) endif() endforeach() # ----------------------------------------- # Other MITK_USE_* options not related to # external projects build via the # MITK superbuild env_option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) env_option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) #----------------------------------------------------------------------------- # Build configurations #----------------------------------------------------------------------------- set(_buildConfigs "Custom") file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) foreach(_buildConfigFile ${_buildConfigFiles}) get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_buildConfigFile}) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) # ----------------------------------------- # Custom dependency logic option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") # only windows can't build python in debug mode if(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) set(MITK_USE_Numpy OFF CACHE BOOL "Use Numpy" FORCE) set(MITK_USE_SimpleITK OFF CACHE BOOL "Use SimpleITK" FORCE) elseif(MITK_USE_Python) set(MITK_USE_ZLIB ON) if(NOT MITK_USE_Numpy) message("> Forcing MITK_USE_Numpy to ON because of MITK_USE_Python") set(MITK_USE_Numpy ON CACHE BOOL "Use Numpy" FORCE) endif() if(NOT MITK_USE_SimpleITK) message("> Forcing MITK_USE_SimpleITK to ON because of MITK_USE_Python") set(MITK_USE_SimpleITK ON CACHE BOOL "Use SimpleITK" FORCE) endif() find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) elseif(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) endif() if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() #----------------------------------------------------------------------------- # Pixel type multiplexing #----------------------------------------------------------------------------- # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionTestPlugin) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- # Required and enabled C++14 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() -if(NOT UNIX 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. + + if(DEFINED ${_package}_DIR) + #we store the information because it will be overwritten by find_package + #and would get lost for all EPs that use on Find.cmake instead of config + #files. + set(_temp_EP_${_package}_dir ${${_package}_DIR}) + endif(DEFINED ${_package}_DIR) + find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) + if(DEFINED _temp_EP_${_package}_dir) + set(${_package}_DIR ${_temp_EP_${_package}_dir} CACHE PATH "externaly set dir of the package ${_package}" FORCE) + endif(DEFINED _temp_EP_${_package}_dir) + find_package(${_package} REQUIRED) endif() endif() endif() endforeach() # Ensure that the MITK CMake module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) if(MITK_USE_DCMTK) # Due to the preferred CONFIG mode in find_package calls above, # the DCMTKConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMTK. if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() find_package(DCMTK REQUIRED MODULE) endif() if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() if(MITK_USE_Python) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) if(MITK_USE_Numpy) find_package(Numpy REQUIRED) endif() endif() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_SimpleITK) link_directories(${SimpleITK_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() # Qt support if(MITK_USE_Qt5) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required get_target_property(_qmake_exec Qt5::qmake LOCATION) execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS RESULT_VARIABLE _result OUTPUT_VARIABLE QT_BINARY_DIR ERROR_VARIABLE _error ) string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) if(_result OR NOT EXISTS "${QT_BINARY_DIR}") message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant assistant-qt5 assistant5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE ) if(MITK_USE_BLUEBERRY) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND}) mark_as_advanced(BLUEBERRY_USE_QT_HELP) # Sanity checks for in-application BlueBerry plug-in help generation if(BLUEBERRY_USE_QT_HELP) set(_force_blueberry_use_qt_help_to_off 0) if(NOT DOXYGEN_FOUND) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT MITK_USE_Qt5) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(_force_blueberry_use_qt_help_to_off 1) endif() if(_force_blueberry_use_qt_help_to_off) set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE) endif() endif() if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP) message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON") endif() endif() endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_RENDERING_TESTING OFF "Enable the MITK rendering tests. Requires x-server in Linux.") #Rendering testing does not work for Linux nightlies, thus it is disabled per default #and activated for Mac and Windows. if(WIN32 OR APPLE) set(MITK_ENABLE_RENDERING_TESTING ON) endif() mark_as_advanced( MITK_ENABLE_RENDERING_TESTING ) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Initial cache for ProjectTemplate and PluginGenerator tests configure_file( CMake/mitkTestInitialCache.txt.in ${MITK_BINARY_DIR}/mitkTestInitialCache.txt @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_MODULES_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Modules) get_filename_component(MITK_MODULES_EXTENSION_DIR ${MITK_MODULES_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) set(MITK_MODULES "") include(${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) foreach(mitk_module ${MITK_MODULES}) add_subdirectory(${MITK_MODULES_EXTENSION_DIR}/${mitk_module} Modules/${mitk_module}) endforeach() endif() set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) endforeach() add_subdirectory(Wrapping) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") if(TARGET CoreApp) get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_PLUGINS) set(mitk_plugins_fullpath "") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() set(MITK_PLUGIN_REGEX_LIST "") foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Plugins) get_filename_component(MITK_PLUGINS_EXTENSION_DIR ${MITK_PLUGINS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) set(MITK_PLUGINS "") include(${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PLUGINS_EXTENSION_DIR}/${mitk_plugin}) endforeach() endif() endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb MITK_PLUGIN_REGEX_LIST OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${directory_name}^^${option_name}") endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- if(DOXYGEN_FOUND) add_subdirectory(Documentation) endif() #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # ---------------- Export targets ----------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE) if(deprecated_module) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")") endif() endforeach() # ---------------- External projects ----------------- get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) set(MITK_CONFIG_EXTERNAL_PROJECTS ) #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS}) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} set(MITK_USE_${ep} ${MITK_USE_${ep}}) set(MITK_${ep}_DIR \"${${ep}_DIR}\") set(MITK_${ep}_COMPONENTS ${_components}) ") endforeach() foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(_components) set(_components_arg COMPONENTS \${_components}) else() set(_components_arg) endif() if(_package) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} if(MITK_USE_${ep}) set(${ep}_DIR \${MITK_${ep}_DIR}) if(MITK_${ep}_COMPONENTS) mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS}) else() mitkMacroFindDependency(${_package}) endif() endif()") endif() endforeach() # ---------------- Tools ----------------- configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) # ---------------- Configure files ----------------- configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) +if(MSVC AND TARGET MitkWorkbench) + set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench) +endif() + #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) diff --git a/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/src/mitkArithmeticOperation.cpp b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp index aa4852cd6f..95ce7d1bc8 100644 --- a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp +++ b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp @@ -1,561 +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 std::pow(value, A); + return static_cast(std::pow(value, A)); else - return std::pow(A, value); + 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/Chart/include/QmitkChartData.h b/Modules/Chart/include/QmitkChartData.h index 66c9d2d3b3..350e6604c1 100644 --- a/Modules/Chart/include/QmitkChartData.h +++ b/Modules/Chart/include/QmitkChartData.h @@ -1,98 +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 QmitkC3Data_h #define QmitkC3Data_h #include #include /** \brief This class holds the relevant properties for the chart generation with C3 such as labels and diagram type. * It is derived from QObject, because we need Q_PROPERTIES to send Data via QWebChannel to JavaScript. * \sa The actual data for the chart generation is in QmitkC3xyData! */ class QmitkChartData : public QObject { Q_OBJECT Q_PROPERTY(QVariant m_xAxisLabel READ GetXAxisLabel WRITE SetXAxisLabel NOTIFY SignalXAxisLabelChanged); Q_PROPERTY(QVariant m_yAxisLabel READ GetYAxisLabel WRITE SetYAxisLabel NOTIFY SignalYAxisLabelChanged); Q_PROPERTY(QVariant m_chartTitle READ GetTitle WRITE SetTitle NOTIFY SignalTitleChanged); Q_PROPERTY(QVariant m_LegendPosition READ GetLegendPosition WRITE SetLegendPosition NOTIFY SignalLegendPositionChanged); Q_PROPERTY(QVariant m_ShowLegend READ GetShowLegend WRITE SetShowLegend NOTIFY SignalShowLegendChanged); Q_PROPERTY(QVariant m_YAxisScale READ GetYAxisScale WRITE SetYAxisScale NOTIFY SignalYAxisScaleChanged); Q_PROPERTY(QVariant m_ShowSubchart READ GetShowSubchart WRITE SetShowSubchart NOTIFY SignalShowSubchartChanged); Q_PROPERTY(QVariant m_UsePercentageInPieChart READ GetUsePercentageInPieChart WRITE SetUsePercentageInPieChart NOTIFY SignalUsePercentageInPieChartChanged); Q_PROPERTY(QVariant m_DataPointSize READ GetDataPointSize WRITE SetDataPointSize NOTIFY SignalDataPointSizeChanged); + Q_PROPERTY(QVariant m_StackedData READ GetStackedData WRITE SetStackedData NOTIFY SignalStackedDataChanged); public: QmitkChartData(); void SetAppearance(bool showSubChart = true, bool usePercentageInPieChart = false); Q_INVOKABLE QVariant GetXAxisLabel() const { return m_xAxisLabel; }; Q_INVOKABLE void SetXAxisLabel(const QVariant& label) { m_xAxisLabel = label; emit SignalXAxisLabelChanged(label); }; Q_INVOKABLE QVariant GetYAxisLabel() const { return m_yAxisLabel; }; Q_INVOKABLE void SetYAxisLabel(const QVariant& label) { m_yAxisLabel = label; emit SignalYAxisLabelChanged(label); }; Q_INVOKABLE QVariant GetTitle() const { return m_chartTitle; }; Q_INVOKABLE void SetTitle(const QVariant& title) { m_chartTitle = title; emit SignalTitleChanged(title); }; Q_INVOKABLE QVariant GetLegendPosition() const { return m_LegendPosition; }; Q_INVOKABLE void SetLegendPosition(const QVariant& legendPosition) { m_LegendPosition = legendPosition; emit SignalLegendPositionChanged(legendPosition); }; Q_INVOKABLE QVariant GetShowLegend() const { return m_ShowLegend; }; Q_INVOKABLE void SetShowLegend(const QVariant& show) { m_ShowLegend = show; emit SignalShowLegendChanged(show); }; Q_INVOKABLE QVariant GetYAxisScale() const { return m_YAxisScale; }; Q_INVOKABLE void SetYAxisScale(const QVariant& YAxisScale) { m_YAxisScale = YAxisScale; emit SignalYAxisScaleChanged(YAxisScale); }; Q_INVOKABLE QVariant GetShowSubchart() const { return m_ShowSubchart; }; Q_INVOKABLE void SetShowSubchart(const QVariant& showSubchart) { m_ShowSubchart = showSubchart; emit SignalShowSubchartChanged(showSubchart); }; Q_INVOKABLE QVariant GetUsePercentageInPieChart() const { return m_UsePercentageInPieChart; }; Q_INVOKABLE void SetUsePercentageInPieChart(const QVariant& usePercentageInPieChart) { m_UsePercentageInPieChart = usePercentageInPieChart; emit SignalUsePercentageInPieChartChanged(usePercentageInPieChart); }; Q_INVOKABLE QVariant GetDataPointSize() const { return m_DataPointSize; }; - Q_INVOKABLE void SetDataPointSize(const QVariant& showDataPoints) {if (showDataPoints > 0 ) { m_DataPointSize = 3; } else { m_DataPointSize = 0; } emit SignalDataPointSizeChanged(showDataPoints); }; + Q_INVOKABLE void SetDataPointSize(const QVariant& showDataPoints) { if (showDataPoints > 0) { m_DataPointSize = 3; } else { m_DataPointSize = 0; } emit SignalDataPointSizeChanged(showDataPoints); }; + + Q_INVOKABLE QVariant GetStackedData() const { return m_StackedData; }; + Q_INVOKABLE void SetStackedData(const QVariant& stackedData) { m_StackedData = stackedData; emit SignalStackedDataChanged(m_StackedData); }; signals: void SignalYAxisLabelChanged(const QVariant label); void SignalXAxisLabelChanged(const QVariant label); void SignalLegendPositionChanged(const QVariant legendPosition); void SignalShowLegendChanged(const QVariant show); void SignalYAxisScaleChanged(const QVariant YAxisScale); void SignalTitleChanged(const QVariant title); void SignalShowSubchartChanged(const QVariant showSubchart); void SignalUsePercentageInPieChartChanged(const QVariant usePercentageInPieChart); void SignalDataPointSizeChanged(const QVariant showDataPoints); + void SignalStackedDataChanged(const QVariant stackedData); private: QVariant m_xAxisLabel; QVariant m_yAxisLabel; QVariant m_chartTitle; QVariant m_ShowLegend = true; QVariant m_LegendPosition; QVariant m_ShowSubchart; QVariant m_YAxisScale; QVariant m_UsePercentageInPieChart; QVariant m_numberDatasets; QVariant m_DataPointSize = 0; + QVariant m_StackedData; }; #endif //QmitkC3Data_h diff --git a/Modules/Chart/include/QmitkChartWidget.h b/Modules/Chart/include/QmitkChartWidget.h index 6eed0726a3..1de030388a 100644 --- a/Modules/Chart/include/QmitkChartWidget.h +++ b/Modules/Chart/include/QmitkChartWidget.h @@ -1,219 +1,221 @@ /*=================================================================== 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 QmitkC3jsWidget_h #define QmitkC3jsWidget_h #include #include #include #include /*! \brief QmitkChartWidget is a widget to display various charts based on the javascript chart library C3js. * \details Data is added via AddData1D() or AddData2D().\n * There can be multiple charts (of different types with different properties) created by calling AddData1D or AddData2D multiple times.\n\n * The following chart types are supported: * * line chart: http://c3js.org/samples/simple_multiple.html * * bar chart: http://c3js.org/samples/chart_bar.html * * spline chart: http://c3js.org/samples/chart_spline.html * * pie chart: http://c3js.org/samples/chart_pie.html * * scatter chart: http://c3js.org/samples/chart_scatter.html * * area chart: http://c3js.org/samples/chart_area.html * * area spline chart: http://c3js.org/samples/chart_area.html * * Technical details: The javascript code is embedded in a QWebEngineView. The actual js code is implemented in resource\Chart.js. * \sa http://c3js.org for further information about the used javaScript library. * \warning We had issues with Qt versions <5.10. So we highly encourage to use Qt 5.10 or newer if this module is used. * \ingroup Modules/Chart */ class MITKCHART_EXPORT QmitkChartWidget : public QWidget { Q_OBJECT public: /*! * \brief enum of diagram types. */ enum class ChartType { bar, /*!< bar chart, see http://c3js.org/samples/chart_bar.html */ line, /*!< line chart, see http://c3js.org/samples/simple_multiple.html */ spline, /*!< spline chart (smoothed line chart), see http://c3js.org/samples/chart_spline.html */ pie, /*!< pie chart, see http://c3js.org/samples/chart_pie.html*/ area, /*!< area chart, see http://c3js.org/samples/chart_area.html*/ area_spline, /*!< area-spline chart, see http://c3js.org/samples/chart_area.html*/ scatter /*!< scatter chart, see http://c3js.org/samples/chart_scatter.html*/ }; /*! * \brief enum of chart style (modifies background and line color). */ enum class ChartStyle { darkstyle, /*!< background color: dark gray, line color: blue */ lightstyle /*!< background color: white, line color: blue */ }; enum class LineStyle { solid, dashed }; enum class AxisScale { linear, log }; /*! * \brief enum of legend position. * See http://c3js.org/reference.html#legend-position */ enum class LegendPosition { bottom, right, inset }; explicit QmitkChartWidget(QWidget* parent = nullptr); ~QmitkChartWidget() override; /*! * \brief Adds 1D data to the widget * \details internally, the list is converted to a map with increasing integers keys starting at 0. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData1D(const std::vector& data1D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Adds 2D data to the widget. Call repeatedly for displaying multiple charts. * \details each entry represents a data point: key: value --> x-value: y-value. * \param label the name of the data that is also used as identifier. * \param chartType the chart type that should be used for this data entry * \note the data can be cleared with ClearDiagram() * \note If the label name already exists, the name is replaced with a unique one by concatenating numbers to it. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. */ void AddData2D(const std::map& data2D, const std::string& label, ChartType chartType = ChartType::bar); /*! * \brief Removes data from the widget, works for 1D and 2D Data * \param label the name of the data that is also used as identifier. * \note All data can be cleared with ClearDiagram() * \throws Invalid Argument Exception when the label cannot be found */ void RemoveData(const std::string& label); /*! * \brief Sets the color of one data entry (identifier is previously assigned label) * \details the color name can be "red" or a hex number (#FF0000). * \warning Either define all data entries with a color or no data entry. If a mixed approach is used, * C3 choses the color of the data entry (that could be the same as a user defined color). * \note If an unknown label is given, nothing happens. * \sa https://www.w3schools.com/cssref/css_colors.asp */ void SetColor(const std::string& label, const std::string& colorName); /*! * \brief Sets the line style of one data entry (identifier is previously assigned label) * \details two line styles are possible: LineStyle::solid and LineStyle::dashed. * The default line style is solid. * \note If an unknown label is given, nothing happens. * \warning only sets the line style if the current chart type is ChartType::line. * However, the line style remains also if the chart changes (e.g. new chart type) */ void SetLineStyle(const std::string& label, LineStyle style); /*! * \brief Sets the axis scale to either linear (default) or logarithmic. */ void SetYAxisScale(AxisScale scale); void SetXAxisLabel(const std::string& label); void SetYAxisLabel(const std::string& label); /*! * \brief Sets a title for the chart. */ void SetTitle(const std::string &title); /*! * \brief Changes the chart type for all data entries and reloads the chart */ void SetChartTypeForAllDataAndReload(ChartType type); /*! * \brief Sets the chart type for a data entry * \details for available types, see ChartType * \note If an unknown label is given, nothing happens. * \warning Pie chart is significantly different than the other chart types. Here, the data given by AddData1D is summed. Each entry represents a different category. * \sa DiagramType for available types */ void SetChartType(const std::string& label, ChartType type); /*! * \brief Sets the legend position. * \details Default position is bottom. * \sa LegendPosition for available types */ void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); + void SetStackedData(bool stacked); + /*! * \brief Displays the chart in the widget * \param showSubChart if a subchart is displayed inside the widget or not (see http://c3js.org/samples/options_subchart.html). * \exception if no data has been provided (\sa AddData1D AddData2D) */ void Show(bool showSubChart=false); /*! * \brief Either displays the dataPoints or not * \param showDataPoints if dataPoints are displayed inside the widget or not. * \details: example for not showing points: http://c3js.org/samples/point_show.html * example for showing the points: http://c3js.org/samples/simple_multiple.html */ void SetShowDataPoints(bool showDataPoints); /*! * \brief Clears all data inside and resets the widget. */ void Clear(); /*! * \brief Changes the theme of the widget. */ void SetTheme(ChartStyle themeEnabled); /*! * \brief Reloads the chart in the widget * \details reloading may be needed to display added data in an existing chart * \param showSubChart if a subchart is displayed inside the widget or not. */ void Reload(bool showSubChart); public slots: void OnLoadFinished(bool isLoadSuccessful); signals: void PageSuccessfullyLoaded(); private: class Impl; std::unique_ptr m_Impl; }; #endif diff --git a/Modules/Chart/resource/Chart.js b/Modules/Chart/resource/Chart.js index 437c439153..61eaa967dd 100644 --- a/Modules/Chart/resource/Chart.js +++ b/Modules/Chart/resource/Chart.js @@ -1,236 +1,260 @@ //Based on C3.js (http://c3js.org). See Website for examples! document.body.style.backgroundColor = 'rgb(240, 240, 240)'; var minHeight = 255; var chart; GenerateChart() var chartData; var xValues=[]; var yValues=[]; +var dataLabels=[]; var xs = {}; var dataColors = {}; var chartTypes = {}; var lineStyle = {}; //Is executed when js is loaded first. //Extracts relevant information from chartData in variables window.onload = function() { new QWebChannel(qt.webChannelTransport, function(channel) { chartData = channel.objects.chartData; - var count = 0; + var count = 0; for(var propertyName in channel.objects) { - if (propertyName != 'chartData'){ + if (propertyName != 'chartData') + { var xDataTemp = channel.objects[propertyName].m_XData var yDataTemp = channel.objects[propertyName].m_YData - var dataLabelsTemp; + var dataLabel = channel.objects[propertyName].m_Label + dataLabels.push(dataLabel) + //add label to x array xDataTemp.unshift('x'+count.toString()) - dataLabelsTemp = channel.objects[propertyName].m_Label - - xs[dataLabelsTemp] = 'x'+count.toString() + xs[dataLabel] = 'x' + count.toString() xDataTemp.push(null); //append null value, to make sure the last tick on x-axis is displayed correctly - yDataTemp.unshift(dataLabelsTemp) + yDataTemp.unshift(dataLabel) yDataTemp.push(null); //append null value, to make sure the last tick on y-axis is displayed correctly xValues[count] = xDataTemp yValues[count] = yDataTemp - dataColors[dataLabelsTemp] = channel.objects[propertyName].m_Color - chartTypes[dataLabelsTemp] = channel.objects[propertyName].m_ChartType + dataColors[dataLabel] = channel.objects[propertyName].m_Color + chartTypes[dataLabel] = channel.objects[propertyName].m_ChartType - if (channel.objects[propertyName].m_LineStyleName=="solid"){ - lineStyle[dataLabelsTemp]= '' + if (channel.objects[propertyName].m_LineStyleName == "solid") + { + lineStyle[dataLabel] = '' } - else { - lineStyle[dataLabelsTemp]= [{'style':'dashed'}] + else + { + lineStyle[dataLabel] = [{ 'style': 'dashed' }] } count++; } } - setupChart(chartData) + + setupChart(chartData) }); } //This is necessary to resize the chart, after the size of the parent changed window.onresize = function () { var size = window.innerHeight-(window.innerHeight/100*10); //subtract 5% of height to hide vertical scrool bar if (size < minHeight) { size = minHeight; } chart.resize({ height: size, }); } -function ReloadChart(showSubchart) +function ReloadChart(showSubchart, stackDataString) { chartData.m_ShowSubchart = showSubchart; + chartData.m_StackedData = stackDataString; setupChart(chartData); } function setupChart(chartData) { window.onresize(); GenerateChart(chartData) chart.unload(); //unload data before loading new data //for multiple xy line chart, see http://c3js.org/samples/simple_xy_multiple.html var columns = []; for (var i in xValues){ columns.push(xValues[i]) } for (var i in yValues){ columns.push(yValues[i]) } chart.load({ xs: xs, - columns: columns + columns: columns }); } //Transformation between different chart types //takes the name of the chart type as a parameter //called by QmitkC3jsWidget function transformView(TransformTo) { chart.transform(TransformTo); }; function changeTheme(color) { link = document.getElementsByTagName("link")[0]; if (color == 'dark') { link.href = "Chart_dark.css"; } else { link.href = "Chart.css"; } }; //Here, the chart magic takes place. C3js is called function GenerateChart(chartData) { - if (chartData === undefined) + if (chartData == undefined) { chartData = {} } - //adaption for bar ratio indepenend of amount of data points + + if (dataLabels == undefined) + { + dataLabels = [] + } + + var groupLabels = []; + if (chartData.m_StackedData == true) + { + groupLabels = dataLabels + } + + //adaption for bar ratio independent of amount of data points //otherwise, bars could be covered. var barRatio; - try { + try + { barRatio = 0.8*Math.exp(-0.015*xValues[0].length); } - catch (err){ + catch (err) + { barRatio=0.42 } var formatCharacter; - if (chartData.m_UsePercentageInPieChart==true){ + if (chartData.m_UsePercentageInPieChart == true) + { formatCharacter = '%' } - else{ + else + { formatCharacter = '.1f' } + chart = c3.generate({ title:{ text: chartData.m_diagramTitle, position: 'top-center' }, data: { xs: {}, //use first "column" as x axis values columns: [], //initialize empty. Data will be loaded in function setupChart(chartData) types: chartTypes, selection: { enabled: false, multiple: false, }, colors: dataColors, regions: lineStyle, + groups: [groupLabels] }, legend: { position: chartData.m_LegendPosition, show: chartData.m_ShowLegend }, grid: { y: { lines: [{value:0}] //Draws a horizontal line at y=0 } }, bar: { width: { ratio: barRatio } }, pie:{ label: { format: function (value, ratio, id) { if (chartData.m_UsePercentageInPieChart==true){ return d3.format('%') (ratio); } else{ return value; } } } }, zoom: { enabled: true, }, subchart: { show: chartData.m_ShowSubchart //Shows a subchart that shows the region the primary chart is zoomed in to by overlay. }, axis: { x: { tick: { multiline: false, fit: false, //to make more x labels appear on zoom centered: true, format: d3.format(".1f"), }, label: { text: chartData.m_xAxisLabel, position: 'outer-center' } }, y: { tick: { format: d3.format(formatCharacter) }, label: { text: chartData.m_yAxisLabel, position: 'outer-middle' }, scale: { name: chartData.m_YAxisScale } } }, tooltip: { format: { title: function (x) { return chartData.m_xAxisLabel + ': ' + d3.format(".2f")(x)} }, }, //Style data points in linegraph point: { r: chartData.m_DataPointSize, focus: { expand: { r: chartData.m_DataPointSize + 2 } } }, }); } diff --git a/Modules/Chart/src/QmitkChartData.cpp b/Modules/Chart/src/QmitkChartData.cpp index 2dabbc46aa..975a2cf157 100644 --- a/Modules/Chart/src/QmitkChartData.cpp +++ b/Modules/Chart/src/QmitkChartData.cpp @@ -1,27 +1,30 @@ /*=================================================================== 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 -QmitkChartData::QmitkChartData() : m_ShowSubchart(true), m_YAxisScale("") +QmitkChartData::QmitkChartData() + : m_ShowSubchart(true) + , m_YAxisScale("") + , m_StackedData(false) { } void QmitkChartData::SetAppearance(bool showSubChart, bool usePercentageInPieChart) { m_ShowSubchart = showSubChart; m_UsePercentageInPieChart = usePercentageInPieChart; } \ No newline at end of file diff --git a/Modules/Chart/src/QmitkChartWidget.cpp b/Modules/Chart/src/QmitkChartWidget.cpp index 40372dc85b..9749461c0f 100644 --- a/Modules/Chart/src/QmitkChartWidget.cpp +++ b/Modules/Chart/src/QmitkChartWidget.cpp @@ -1,498 +1,513 @@ /*=================================================================== 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 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) #include #endif #include #include #include "mitkExceptionMacro.h" class QmitkChartWidget::Impl final { public: explicit Impl(QWidget* parent); ~Impl(); Impl(const Impl&) = delete; Impl& operator=(const Impl&) = delete; void AddData1D(const std::vector& data1D, const std::string& label, QmitkChartWidget::ChartType chartType); void AddData2D(const std::map& data2D, const std::string& label, QmitkChartWidget::ChartType chartType); void RemoveData(const std::string& label); void ClearData(); void SetColor(const std::string& label, const std::string& colorName); void SetLineStyle(const std::string& label, LineStyle style); void SetYAxisScale(AxisScale scale); - void SetXAxisLabel(const std::string& label); - void SetYAxisLabel(const std::string& label); void SetTitle(const std::string &title); - void SetLegendPosition(LegendPosition position); + void SetChartType(QmitkChartWidget::ChartType chartType); + void SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType); + void SetLegendPosition(LegendPosition position); void SetShowLegend(bool show); - void SetShowDataPoints(bool showDataPoints = false); + void SetStackedData(bool stacked); void Show(bool showSubChart); - void SetChartType(QmitkChartWidget::ChartType chartType); - void SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType); + void SetShowDataPoints(bool showDataPoints = false); std::string ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const; void ClearJavaScriptChart(); void InitializeJavaScriptChart(); void CallJavaScriptFuntion(const QString& command); private: using ChartxyDataVector = std::vector>; std::string GetUniqueLabelName(const QList& labelList, const std::string& label) const; QmitkChartxyData* GetDataElementByLabel(const std::string& label) const; QList GetDataLabels(const ChartxyDataVector& c3xyData) const; QWebChannel* m_WebChannel; QWebEngineView* m_WebEngineView; QmitkChartData m_C3Data; ChartxyDataVector m_C3xyData; std::map m_ChartTypeToName; std::map m_LegendPositionToName; std::map m_LineStyleToName; std::map m_AxisScaleToName; }; QmitkChartWidget::Impl::Impl(QWidget* parent) : m_WebChannel(new QWebChannel(parent)) , m_WebEngineView(new QWebEngineView(parent)) { //disable context menu for QWebEngineView m_WebEngineView->setContextMenuPolicy(Qt::NoContextMenu); //Set the webengineview to an initial empty page. The actual chart will be loaded once the data is calculated. m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); m_WebEngineView->page()->setWebChannel(m_WebChannel); #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) m_WebEngineView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); #endif connect(m_WebEngineView, SIGNAL(loadFinished(bool)), parent, SLOT(OnLoadFinished(bool))); auto layout = new QGridLayout(parent); layout->setMargin(0); layout->addWidget(m_WebEngineView); parent->setLayout(layout); m_ChartTypeToName.emplace(ChartType::bar, "bar"); m_ChartTypeToName.emplace(ChartType::line, "line"); m_ChartTypeToName.emplace(ChartType::spline, "spline"); m_ChartTypeToName.emplace(ChartType::pie, "pie"); m_ChartTypeToName.emplace(ChartType::area, "area"); m_ChartTypeToName.emplace(ChartType::area_spline, "area-spline"); m_ChartTypeToName.emplace(ChartType::scatter, "scatter"); m_LegendPositionToName.emplace(LegendPosition::bottom, "bottom"); m_LegendPositionToName.emplace(LegendPosition::right, "right"); m_LegendPositionToName.emplace(LegendPosition::inset, "inset"); m_LineStyleToName.emplace(LineStyle::solid, "solid"); m_LineStyleToName.emplace(LineStyle::dashed, "dashed"); m_AxisScaleToName.emplace(AxisScale::linear, ""); m_AxisScaleToName.emplace(AxisScale::log, "log"); } QmitkChartWidget::Impl::~Impl() { } -void QmitkChartWidget::Impl::AddData1D(const std::vector& data1D, const std::string& label, QmitkChartWidget::ChartType chartType) { +std::string CheckForCorrectHex(const std::string& colorName) +{ + std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); + std::smatch match; + + if (!colorName.empty() && colorName.at(0) != '#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) + { + return "#" + colorName; + } + else + { + return colorName; + } +} + +void QmitkChartWidget::Impl::AddData1D(const std::vector& data1D, const std::string& label, QmitkChartWidget::ChartType chartType) +{ std::map transformedData2D; unsigned int count = 0; //transform the 1D data to 2D data for (const auto& ele : data1D) { transformedData2D[count] = ele; count++; } AddData2D(transformedData2D, label, chartType); } void QmitkChartWidget::Impl::AddData2D(const std::map& data2D, const std::string& label, QmitkChartWidget::ChartType chartType) { QMap data2DConverted; for (const auto& aValue : data2D) { data2DConverted.insert(aValue.first, aValue.second); } const std::string chartTypeName(m_ChartTypeToName.at(chartType)); auto definedLabels = GetDataLabels(m_C3xyData); auto uniqueLabel = GetUniqueLabelName(definedLabels, label); if (chartType == ChartType::scatter) { SetShowDataPoints(true); MITK_INFO << "Enabling data points for all because of scatter plot"; } m_C3xyData.push_back(std::make_unique(data2DConverted, QVariant(QString::fromStdString(uniqueLabel)), QVariant(QString::fromStdString(chartTypeName)))); } void QmitkChartWidget::Impl::RemoveData(const std::string& label) { for (ChartxyDataVector::iterator iter = m_C3xyData.begin(); iter != m_C3xyData.end(); ++iter) { if ((*iter)->GetLabel().toString().toStdString() == label) { m_C3xyData.erase(iter); return; } } throw std::invalid_argument("Cannot Remove Data because the label does not exist."); } void QmitkChartWidget::Impl::ClearData() { for (auto& xyData : m_C3xyData) { m_WebChannel->deregisterObject(xyData.get()); } m_C3xyData.clear(); } -std::string CheckForCorrectHex(const std::string& colorName) -{ - std::regex rgx("([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"); - std::smatch match; - - if (!colorName.empty() && colorName.at(0)!='#' && std::regex_search(colorName.begin(), colorName.end(), match, rgx)) - { - return "#" + colorName; - } - else { - return colorName; - } -} - void QmitkChartWidget::Impl::SetColor(const std::string& label, const std::string& colorName) { auto element = GetDataElementByLabel(label); if (element) { auto colorChecked = CheckForCorrectHex(colorName); element->SetColor(QVariant(QString::fromStdString(colorName))); } } void QmitkChartWidget::Impl::SetLineStyle(const std::string& label, LineStyle style) { auto element = GetDataElementByLabel(label); //only has effect with chart type line if (element && element->GetChartType() == QVariant(QString::fromStdString(ConvertChartTypeToString(ChartType::line)))) { const std::string lineStyleName(m_LineStyleToName.at(style)); element->SetLineStyle(QVariant(QString::fromStdString(lineStyleName))); } } void QmitkChartWidget::Impl::SetYAxisScale(AxisScale scale) { const std::string axisScaleName(m_AxisScaleToName.at(scale)); m_C3Data.SetYAxisScale(QString::fromStdString(axisScaleName)); } -QmitkChartxyData* QmitkChartWidget::Impl::GetDataElementByLabel(const std::string& label) const -{ - for (const auto& qmitkChartxyData : m_C3xyData) - { - if (qmitkChartxyData->GetLabel().toString() == label.c_str()) - { - return qmitkChartxyData.get(); - } - } - - MITK_WARN << "label " << label << " not found in QmitkChartWidget"; - return nullptr; -} - -QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector& c3xyData) const -{ - QList dataLabels; - for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) - { - dataLabels.push_back((*element)->GetLabel()); - } - return dataLabels; -} - void QmitkChartWidget::Impl::SetXAxisLabel(const std::string& label) { m_C3Data.SetXAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetYAxisLabel(const std::string& label) { m_C3Data.SetYAxisLabel(QString::fromStdString(label)); } void QmitkChartWidget::Impl::SetTitle(const std::string& title) { m_C3Data.SetTitle(QString::fromStdString(title)); } +void QmitkChartWidget::Impl::SetChartType(QmitkChartWidget::ChartType chartType) +{ + for (auto iterator = m_C3xyData.begin(); iterator != m_C3xyData.end(); ++iterator) + { + SetChartTypeByLabel((*iterator)->GetLabel().toString().toStdString(), chartType); + } + + auto chartTypeName = ConvertChartTypeToString(chartType); + const QString command = QString::fromStdString("transformView('" + chartTypeName + "')"); + CallJavaScriptFuntion(command); +} + +void QmitkChartWidget::Impl::SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType) +{ + auto element = GetDataElementByLabel(label); + if (element) + { + if (chartType == ChartType::scatter) + { + SetShowDataPoints(true); + MITK_INFO << "Enabling data points for all because of scatter plot"; + } + auto chartTypeName = ConvertChartTypeToString(chartType); + element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); + } +} + void QmitkChartWidget::Impl::SetLegendPosition(QmitkChartWidget::LegendPosition legendPosition) { const std::string legendPositionName(m_LegendPositionToName.at(legendPosition)); m_C3Data.SetLegendPosition(QString::fromStdString(legendPositionName)); } void QmitkChartWidget::Impl::SetShowLegend(bool show) { m_C3Data.SetShowLegend(show); } -void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) +void QmitkChartWidget::Impl::SetStackedData(bool stacked) { - if (showDataPoints == true) { - m_C3Data.SetDataPointSize(3); - } - else { - m_C3Data.SetDataPointSize(0); - } + m_C3Data.SetStackedData(stacked); } void QmitkChartWidget::Impl::Show(bool showSubChart) { if (m_C3xyData.empty()) { mitkThrow() << "no data available for display in chart"; } m_C3Data.SetAppearance(showSubChart, m_C3xyData.front()->GetChartType() == QVariant("pie")); InitializeJavaScriptChart(); } -void QmitkChartWidget::Impl::SetChartType(QmitkChartWidget::ChartType chartType) +void QmitkChartWidget::Impl::SetShowDataPoints(bool showDataPoints) { - for (auto iterator = m_C3xyData.begin(); iterator != m_C3xyData.end(); ++iterator) + if (showDataPoints == true) { - SetChartTypeByLabel((*iterator)->GetLabel().toString().toStdString(), chartType); + m_C3Data.SetDataPointSize(3); } - - auto chartTypeName = ConvertChartTypeToString(chartType); - const QString command = QString::fromStdString("transformView('" + chartTypeName + "')"); - CallJavaScriptFuntion(command); -} - -void QmitkChartWidget::Impl::SetChartTypeByLabel(const std::string& label, QmitkChartWidget::ChartType chartType) -{ - auto element = GetDataElementByLabel(label); - if (element) + else { - if (chartType == ChartType::scatter) - { - SetShowDataPoints(true); - MITK_INFO << "Enabling data points for all because of scatter plot"; - } - auto chartTypeName = ConvertChartTypeToString(chartType); - element->SetChartType(QVariant(QString::fromStdString(chartTypeName))); + m_C3Data.SetDataPointSize(0); } } std::string QmitkChartWidget::Impl::ConvertChartTypeToString(QmitkChartWidget::ChartType chartType) const { return m_ChartTypeToName.at(chartType); } -void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString& command) -{ - m_WebEngineView->page()->runJavaScript(command); -} - void QmitkChartWidget::Impl::ClearJavaScriptChart() { m_WebEngineView->setUrl(QUrl(QStringLiteral("qrc:///C3js/empty.html"))); } void QmitkChartWidget::Impl::InitializeJavaScriptChart() { m_WebChannel->registerObject(QStringLiteral("chartData"), &m_C3Data); unsigned count = 0; for (auto& xyData : m_C3xyData) { QString variableName = "xyData" + QString::number(count); m_WebChannel->registerObject(variableName, xyData.get()); count++; } m_WebEngineView->load(QUrl(QStringLiteral("qrc:///C3js/QmitkChartWidget.html"))); } +void QmitkChartWidget::Impl::CallJavaScriptFuntion(const QString& command) +{ + m_WebEngineView->page()->runJavaScript(command); +} + std::string QmitkChartWidget::Impl::GetUniqueLabelName(const QList& labelList, const std::string& label) const { QString currentLabel = QString::fromStdString(label); int counter = 0; while (labelList.contains(currentLabel)) { currentLabel = QString::fromStdString(label + std::to_string(counter)); counter++; } return currentLabel.toStdString(); } +QmitkChartxyData* QmitkChartWidget::Impl::GetDataElementByLabel(const std::string& label) const +{ + for (const auto& qmitkChartxyData : m_C3xyData) + { + if (qmitkChartxyData->GetLabel().toString() == label.c_str()) + { + return qmitkChartxyData.get(); + } + } + + MITK_WARN << "label " << label << " not found in QmitkChartWidget"; + return nullptr; +} + +QList QmitkChartWidget::Impl::GetDataLabels(const ChartxyDataVector& c3xyData) const +{ + QList dataLabels; + for (auto element = c3xyData.begin(); element != c3xyData.end(); ++element) + { + dataLabels.push_back((*element)->GetLabel()); + } + return dataLabels; +} + QmitkChartWidget::QmitkChartWidget(QWidget* parent) : QWidget(parent) , m_Impl(new Impl(this)) { } QmitkChartWidget::~QmitkChartWidget() { } +void QmitkChartWidget::AddData1D(const std::vector& data1D, const std::string& label, ChartType type) +{ + m_Impl->AddData1D(data1D, label, type); +} + void QmitkChartWidget::AddData2D(const std::map& data2D, const std::string& label, ChartType type) { m_Impl->AddData2D(data2D, label, type); } +void QmitkChartWidget::RemoveData(const std::string& label) +{ + m_Impl->RemoveData(label); +} + void QmitkChartWidget::SetColor(const std::string& label, const std::string& colorName) { m_Impl->SetColor(label, colorName); } void QmitkChartWidget::SetLineStyle(const std::string& label, LineStyle style) { m_Impl->SetLineStyle(label, style); } void QmitkChartWidget::SetYAxisScale(AxisScale scale) { m_Impl->SetYAxisScale(scale); } -void QmitkChartWidget::AddData1D(const std::vector& data1D, const std::string& label, ChartType type) -{ - m_Impl->AddData1D(data1D, label, type); -} - -void QmitkChartWidget::RemoveData(const std::string& label) -{ - m_Impl->RemoveData(label); -} - void QmitkChartWidget::SetXAxisLabel(const std::string & label) { m_Impl->SetXAxisLabel(label); } void QmitkChartWidget::SetYAxisLabel(const std::string & label) { m_Impl->SetYAxisLabel(label); } void QmitkChartWidget::SetTitle(const std::string & title) { m_Impl->SetTitle(title); } -void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) -{ - m_Impl->SetShowDataPoints(showDataPoints); -} - void QmitkChartWidget::SetChartTypeForAllDataAndReload(ChartType type) { m_Impl->SetChartType(type); } void QmitkChartWidget::SetChartType(const std::string& label, ChartType type) { m_Impl->SetChartTypeByLabel(label, type); } void QmitkChartWidget::SetLegendPosition(LegendPosition position) { m_Impl->SetLegendPosition(position); } void QmitkChartWidget::SetShowLegend(bool show) { m_Impl->SetShowLegend(show); } +void QmitkChartWidget::SetStackedData(bool stacked) +{ + m_Impl->SetStackedData(stacked); +} + void QmitkChartWidget::Show(bool showSubChart) { m_Impl->Show(showSubChart); } +void QmitkChartWidget::SetShowDataPoints(bool showDataPoints) +{ + m_Impl->SetShowDataPoints(showDataPoints); +} + void QmitkChartWidget::Clear() { m_Impl->ClearData(); m_Impl->ClearJavaScriptChart(); } void QmitkChartWidget::OnLoadFinished(bool isLoadSuccessful) { if(isLoadSuccessful) { emit PageSuccessfullyLoaded(); } } void QmitkChartWidget::SetTheme(ChartStyle themeEnabled) { QString command; if (themeEnabled == ChartStyle::darkstyle) { command = QString("changeTheme('dark')"); } else { command = QString("changeTheme('light')"); } m_Impl->CallJavaScriptFuntion(command); } void QmitkChartWidget::Reload(bool showSubChart) { QString subChartString; + if (showSubChart) { subChartString = "true"; } else { subChartString = "false"; } + const QString command = QString("ReloadChart(" + subChartString + ")"); m_Impl->CallJavaScriptFuntion(command); } 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/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/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/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/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/DiffusionCore/include/mitkDiffusionFunctionCollection.h b/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h index ab1930a3ba..3850182022 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h @@ -1,119 +1,121 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkDiffusionFunctionCollection_h_ #define __mitkDiffusionFunctionCollection_h_ #include #include #include #include #include #include #include namespace mitk{ -class imv +class MITKDIFFUSIONCORE_EXPORT imv { public: + static std::vector< std::pair< itk::Index<3>, double > > IntersectImage(itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef); + template< class TPixelType, class TOutPixelType=TPixelType > static TOutPixelType GetImageValue(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator) { if (interpolator==nullptr) return 0.0; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { if (interpolate) return interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); return interpolator->EvaluateAtIndex(idx); } } else return 0.0; } template< class TPixelType=unsigned char > static bool IsInsideMask(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator, float threshold=0.5) { if (interpolator==nullptr) return false; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { double value = 0.0; if (interpolate) value = interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); value = interpolator->EvaluateAtIndex(idx); } if (value>=threshold) return true; } return false; } }; class MITKDIFFUSIONCORE_EXPORT sh { public: static double factorial(int number); static void Cart2Sph(double x, double y, double z, double* spherical); static double legendre0(int l); static double spherical_harmonic(int m,int l,double theta,double phi, bool complexPart); static double Yj(int m, int k, float theta, float phi, bool mrtrix=true); static vnl_matrix CalcShBasisForDirections(int sh_order, vnl_matrix U, bool mrtrix=true); }; class MITKDIFFUSIONCORE_EXPORT gradients { private: typedef std::vector IndiciesVector; typedef std::map BValueMap; typedef itk::VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType; typedef vnl_vector_fixed GradientDirectionType; public: static std::vector GetAllUniqueDirections(const BValueMap &bValueMap, GradientDirectionContainerType *refGradientsContainer ); static bool CheckForDifferingShellDirections(const BValueMap &bValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer); static vnl_matrix ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder); static vnl_matrix ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer); static mitk::gradients::GradientDirectionContainerType::Pointer CreateNormalizedUniqueGradientDirectionContainer(const BValueMap &bValueMap, const GradientDirectionContainerType * origninalGradentcontainer); }; } #endif //__mitkDiffusionFunctionCollection_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp b/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp index 20e2350431..66f7abfc17 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp @@ -1,282 +1,381 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDiffusionFunctionCollection.h" #include "mitkNumericTypes.h" // Namespace ::SH #include #include #include #include // Namespace ::Gradients #include "itkVectorContainer.h" #include "vnl/vnl_vector.h" +#include +#include + +// Intersect a finite line (with end points p0 and p1) with all of the +// cells of a vtkImageData +std::vector< std::pair< itk::Index<3>, double > > mitk::imv::IntersectImage(itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef) +{ + std::vector< std::pair< itk::Index<3>, double > > out; + if (si == ei) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (sf[i]-ef[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + out.push_back( std::pair< itk::Index<3>, double >(si, len) ); + return out; + } + + double bounds[6]; + + double entrancePoint[3]; + double exitPoint[3]; + + double startPoint[3]; + double endPoint[3]; + + double t0, t1; + for (int i=0; i<3; ++i) + { + startPoint[i] = sf[i]; + endPoint[i] = ef[i]; + + if (si[i]>ei[i]) + { + int t = si[i]; + si[i] = ei[i]; + ei[i] = t; + } + } + + for (int x = si[0]; x<=ei[0]; ++x) + for (int y = si[1]; y<=ei[1]; ++y) + for (int z = si[2]; z<=ei[2]; ++z) + { + bounds[0] = (double)x - 0.5; + bounds[1] = (double)x + 0.5; + bounds[2] = (double)y - 0.5; + bounds[3] = (double)y + 0.5; + bounds[4] = (double)z - 0.5; + bounds[5] = (double)z + 0.5; + + int entryPlane; + int exitPlane; + int hit = vtkBox::IntersectWithLine(bounds, + startPoint, + endPoint, + t0, + t1, + entrancePoint, + exitPoint, + entryPlane, + exitPlane); + if (hit) + { + if (entryPlane>=0 && exitPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (exitPoint[i] - entrancePoint[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + else if (entryPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (ef[i] - entrancePoint[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + else if (exitPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (exitPoint[i]-sf[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + } + } + return out; +} + //------------------------- SH-function ------------------------------------ double mitk::sh::factorial(int number) { if(number <= 1) return 1; double result = 1.0; for(int i=1; i<=number; i++) result *= i; return result; } void mitk::sh::Cart2Sph(double x, double y, double z, double *spherical) { double phi, th, rad; rad = sqrt(x*x+y*y+z*z); if( rad < mitk::eps ) { th = itk::Math::pi/2; phi = itk::Math::pi/2; } else { th = acos(z/rad); phi = atan2(y, x); } spherical[0] = phi; spherical[1] = th; spherical[2] = rad; } double mitk::sh::legendre0(int l) { if( l%2 != 0 ) { return 0; } else { double prod1 = 1.0; for(int i=1;i(l,abs(m),-cos(theta)); double mag = sqrt((double)(2*l+1)/(4.0*itk::Math::pi)*::boost::math::factorial(l-abs(m))/::boost::math::factorial(l+abs(m)))*plm; if (m>0) return mag*cos(m*phi); else if (m==0) return mag; else return mag*sin(-m*phi); } return 0; } vnl_matrix mitk::sh::CalcShBasisForDirections(int sh_order, vnl_matrix U, bool mrtrix) { vnl_matrix sh_basis = vnl_matrix(U.cols(), (sh_order*sh_order + sh_order + 2)/2 + sh_order ); for(unsigned int i=0; i mitk::gradients::GetAllUniqueDirections(const BValueMap & refBValueMap, GradientDirectionContainerType *refGradientsContainer ) { IndiciesVector directioncontainer; auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); auto containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot_product(refGradientsContainer->ElementAt(*containerIt), refGradientsContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } } return directioncontainer; } bool mitk::gradients::CheckForDifferingShellDirections(const BValueMap & refBValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer) { auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ auto mapIterator_2 = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator_2++; //skip bzero Values for( ; mapIterator_2 != refBValueMap.end(); mapIterator_2++){ if(mapIterator_2 == mapIterator) continue; IndiciesVector currentShell = mapIterator->second; IndiciesVector testShell = mapIterator_2->second; for (unsigned int i = 0; i< currentShell.size(); i++) if (fabs(dot_product(refGradientsContainer->ElementAt(currentShell[i]), refGradientsContainer->ElementAt(testShell[i]))) <= 0.9998) { return true; } } } return false; } vnl_matrix mitk::gradients::ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer) { vnl_matrix Q(3, refShell.size()); Q.fill(0.0); for(unsigned int i = 0; i < refShell.size(); i++) { GradientDirectionType dir = refGradientsContainer->ElementAt(refShell[i]); double x = dir.normalize().get(0); double y = dir.normalize().get(1); double z = dir.normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); Q(0,i) = cart[0]; Q(1,i) = cart[1]; Q(2,i) = cart[2]; } return Q; } vnl_matrix mitk::gradients::ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder) { vnl_matrix SHBasisOutput(QBallReference.cols(), (LOrder+1)*(LOrder+2)*0.5); SHBasisOutput.fill(0.0); for(int i=0; i< (int)SHBasisOutput.rows(); i++) for(int k = 0; k <= (int)LOrder; k += 2) for(int m =- k; m <= k; m++) { int j = ( k * k + k + 2 ) / 2.0 + m - 1; double phi = QBallReference(0,i); double th = QBallReference(1,i); double val = mitk::sh::Yj(m,k,th,phi); SHBasisOutput(i,j) = val; } return SHBasisOutput; } mitk::gradients::GradientDirectionContainerType::Pointer mitk::gradients::CreateNormalizedUniqueGradientDirectionContainer(const mitk::gradients::BValueMap & bValueMap, - const GradientDirectionContainerType *origninalGradentcontainer) + const GradientDirectionContainerType *origninalGradentcontainer) { mitk::gradients::GradientDirectionContainerType::Pointer directioncontainer = mitk::gradients::GradientDirectionContainerType::New(); auto mapIterator = bValueMap.begin(); if(bValueMap.find(0) != bValueMap.end() && bValueMap.size() > 1){ mapIterator++; //skip bzero Values vnl_vector_fixed vec; vec.fill(0.0); directioncontainer->push_back(vec); } for( ; mapIterator != bValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); mitk::gradients::GradientDirectionContainerType::Iterator containerIt = directioncontainer->Begin(); bool directionExist = false; while(containerIt != directioncontainer->End()) { if (fabs(dot_product(containerIt.Value(), origninalGradentcontainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { GradientDirectionType dir(origninalGradentcontainer->ElementAt(wntIndex)); directioncontainer->push_back(dir.normalize()); } } } return directioncontainer; } diff --git a/Modules/DiffusionImaging/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/itkFitFibersToImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp index 2d9645a07a..3c7f599a2d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp @@ -1,971 +1,997 @@ #include "itkFitFibersToImageFilter.h" #include +#include namespace itk{ FitFibersToImageFilter::FitFibersToImageFilter() : m_PeakImage(nullptr) , m_DiffImage(nullptr) , m_ScalarImage(nullptr) , m_MaskImage(nullptr) , m_FitIndividualFibers(true) , m_GradientTolerance(1e-5) , m_Lambda(0.1) , m_MaxIterations(20) - , m_FiberSampling(10) , m_Coverage(0) , m_Overshoot(0) , m_RMSE(0.0) , m_FilterOutliers(false) , m_MeanWeight(1.0) , m_MedianWeight(1.0) , m_MinWeight(1.0) , m_MaxWeight(1.0) , m_Verbose(true) - , m_DeepCopy(true) - , m_ResampleFibers(true) , m_NumUnknowns(0) , m_NumResiduals(0) , m_NumCoveredDirections(0) , m_SignalModel(nullptr) , sz_x(0) , sz_y(0) , sz_z(0) , m_MeanTractDensity(0) , m_MeanSignal(0) , fiber_count(0) , m_Regularization(VnlCostFunction::REGU::VOXEL_VARIANCE) { this->SetNumberOfRequiredOutputs(3); } FitFibersToImageFilter::~FitFibersToImageFilter() { } +itk::Point FitFibersToImageFilter::GetItkPoint(double point[3]) +{ + itk::Point itkPoint; + itkPoint[0] = point[0]; + itkPoint[1] = point[1]; + itkPoint[2] = point[2]; + return itkPoint; +} + void FitFibersToImageFilter::CreateDiffSystem() { sz_x = m_DiffImage->GetLargestPossibleRegion().GetSize(0); sz_y = m_DiffImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_DiffImage->GetLargestPossibleRegion().GetSize(2); dim_four_size = m_DiffImage->GetVectorLength(); int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_DiffImage->GetSpacing()[0]GetSpacing()[1] && m_DiffImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_DiffImage->GetSpacing()[0]; - else if (m_DiffImage->GetSpacing()[1] < m_DiffImage->GetSpacing()[2]) - minSpacing = m_DiffImage->GetSpacing()[1]; - else - minSpacing = m_DiffImage->GetSpacing()[2]; - - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } + auto spacing = m_DiffImage->GetSpacing(); m_NumResiduals = num_voxels * dim_four_size; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; m_NumCoveredDirections = 0; fiber_count = 0; vnl_vector voxel_indicator; voxel_indicator.set_size(sz_x*sz_y*sz_z); voxel_indicator.fill(0); + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); m_GroupSizes.clear(); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; for (int j=0; jGetPoint(j); - PointType3 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - - itk::Index<3> idx3; - m_DiffImage->TransformPhysicalPointToIndex(p, idx3); - if (!m_DiffImage->GetLargestPossibleRegion().IsInside(idx3) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_DiffImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_DiffImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_DiffImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_DiffImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); - double* p2 = points->GetPoint(j+1); mitk::DiffusionSignalModel<>::GradientType fiber_dir; - fiber_dir[0] = p[0]-p2[0]; - fiber_dir[1] = p[1]-p2[1]; - fiber_dir[2] = p[2]-p2[2]; + fiber_dir[0] = endVertex[0]-startVertex[0]; + fiber_dir[1] = endVertex[1]-startVertex[1]; + fiber_dir[2] = endVertex[2]-startVertex[2]; fiber_dir.Normalize(); - int x = idx3[0]; - int y = idx3[1]; - int z = idx3[2]; - - mitk::DiffusionSignalModel<>::PixelType simulated_pixel = m_SignalModel->SimulateMeasurement(fiber_dir); - VectorImgType::PixelType measured_pixel = m_DiffImage->GetPixel(idx3); - - double simulated_mean = 0; - double measured_mean = 0; - int num_nonzero_g = 0; - for (int g=0; g, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) { - if( m_SignalModel->GetGradientDirection(g).GetNorm()GetLargestPossibleRegion().IsInside(seg.first) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(seg.first)==0)) continue; - simulated_mean += simulated_pixel[g]; - measured_mean += (double)measured_pixel[g]; - ++num_nonzero_g; - } - simulated_mean /= num_nonzero_g; - measured_mean /= num_nonzero_g; - simulated_pixel -= simulated_mean; - if (voxel_indicator[x + sz_x*y + sz_x*sz_y*z]==0) - m_MeanSignal += measured_mean; - m_MeanTractDensity += simulated_mean; - voxel_indicator[x + sz_x*y + sz_x*sz_y*z] = 1; + int x = seg.first[0]; + int y = seg.first[1]; + int z = seg.first[2]; - for (int g=0; g::PixelType simulated_pixel = m_SignalModel->SimulateMeasurement(fiber_dir)*seg.second; + VectorImgType::PixelType measured_pixel = m_DiffImage->GetPixel(seg.first); - if (m_FitIndividualFibers) + double simulated_mean = 0; + double measured_mean = 0; + int num_nonzero_g = 0; + for (int g=0; gGetGradientDirection(g).GetNorm()GetLargestPossibleRegion().GetSize(0); sz_y = m_PeakImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_PeakImage->GetLargestPossibleRegion().GetSize(2); dim_four_size = m_PeakImage->GetLargestPossibleRegion().GetSize(3)/3 + 1; // +1 for zero - peak int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_PeakImage->GetSpacing()[0]GetSpacing()[1] && m_PeakImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_PeakImage->GetSpacing()[0]; - else if (m_PeakImage->GetSpacing()[1] < m_PeakImage->GetSpacing()[2]) - minSpacing = m_PeakImage->GetSpacing()[1]; - else - minSpacing = m_PeakImage->GetSpacing()[2]; + itk::Vector< double, 3 > spacing; + spacing[0] = m_PeakImage->GetSpacing()[0]; + spacing[1] = m_PeakImage->GetSpacing()[1]; + spacing[2] = m_PeakImage->GetSpacing()[2]; - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } + PointType3 origin; + origin[0] = m_PeakImage->GetOrigin()[0]; + origin[1] = m_PeakImage->GetOrigin()[1]; + origin[2] = m_PeakImage->GetOrigin()[2]; + + UcharImgType::RegionType::SizeType size; + size[0] = m_PeakImage->GetLargestPossibleRegion().GetSize()[0]; + size[1] = m_PeakImage->GetLargestPossibleRegion().GetSize()[1]; + size[2] = m_PeakImage->GetLargestPossibleRegion().GetSize()[2]; + UcharImgType::RegionType imageRegion; imageRegion.SetSize(size); + + itk::Matrix direction; + for (int r=0; r<3; r++) + for (int c=0; c<3; c++) + direction[r][c] = m_PeakImage->GetDirection()[r][c]; + + if (m_MaskImage.IsNull()) + { + m_MaskImage = UcharImgType::New(); + m_MaskImage->SetSpacing( spacing ); + m_MaskImage->SetOrigin( origin ); + m_MaskImage->SetDirection( direction ); + m_MaskImage->SetRegions( imageRegion ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } m_NumResiduals = num_voxels * dim_four_size; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; m_NumCoveredDirections = 0; fiber_count = 0; m_GroupSizes.clear(); + + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; for (int j=0; jGetPoint(j); - PointType4 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - p[3]=0; - - itk::Index<4> idx4; - m_PeakImage->TransformPhysicalPointToIndex(p, idx4); - itk::Index<3> idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; - if (!m_PeakImage->GetLargestPossibleRegion().IsInside(idx4) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); - double* p2 = points->GetPoint(j+1); vnl_vector_fixed fiber_dir; - fiber_dir[0] = p[0]-p2[0]; - fiber_dir[1] = p[1]-p2[1]; - fiber_dir[2] = p[2]-p2[2]; + fiber_dir[0] = endVertex[0]-startVertex[0]; + fiber_dir[1] = endVertex[1]-startVertex[1]; + fiber_dir[2] = endVertex[2]-startVertex[2]; fiber_dir.normalize(); - double w = 1; - int peak_id = dim_four_size-1; + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) + { + if (!m_MaskImage->GetLargestPossibleRegion().IsInside(seg.first) || m_MaskImage->GetPixel(seg.first)==0) + continue; + + itk::Index<4> idx4; + idx4[0]=seg.first[0]; + idx4[1]=seg.first[1]; + idx4[2]=seg.first[2]; + idx4[3]=0; - double peak_mag = 0; - GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w, peak_mag); + double w = 1; + int peak_id = dim_four_size-1; - int x = idx4[0]; - int y = idx4[1]; - int z = idx4[2]; + double peak_mag = 0; + GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w, peak_mag); + w *= seg.second; - unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z + sz_x*sz_y*sz_z*peak_id; + int x = idx4[0]; + int y = idx4[1]; + int z = idx4[2]; - if (b[linear_index] == 0 && peak_idGetLargestPossibleRegion().GetSize(0); sz_y = m_ScalarImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_ScalarImage->GetLargestPossibleRegion().GetSize(2); int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_ScalarImage->GetSpacing()[0]GetSpacing()[1] && m_ScalarImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_ScalarImage->GetSpacing()[0]; - else if (m_ScalarImage->GetSpacing()[1] < m_ScalarImage->GetSpacing()[2]) - minSpacing = m_ScalarImage->GetSpacing()[1]; - else - minSpacing = m_ScalarImage->GetSpacing()[2]; - - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } - + auto spacing = m_ScalarImage->GetSpacing(); m_NumResiduals = num_voxels; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; int numCoveredVoxels = 0; fiber_count = 0; + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); m_GroupSizes.clear(); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); - for (int j=0; jGetPoint(j); - PointType3 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - - itk::Index<3> idx3; - m_ScalarImage->TransformPhysicalPointToIndex(p, idx3); - if (!m_ScalarImage->GetLargestPossibleRegion().IsInside(idx3) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_ScalarImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_ScalarImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_ScalarImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_ScalarImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) + { + if (!m_ScalarImage->GetLargestPossibleRegion().IsInside(seg.first) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(seg.first)==0)) + continue; - float image_value = m_ScalarImage->GetPixel(idx3); - int x = idx3[0]; - int y = idx3[1]; - int z = idx3[2]; + float image_value = m_ScalarImage->GetPixel(seg.first); + int x = seg.first[0]; + int y = seg.first[1]; + int z = seg.first[2]; - unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; + unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; - if (b[linear_index] == 0) - { - numCoveredVoxels++; - m_MeanSignal += image_value; - } - m_MeanTractDensity += 1; + if (b[linear_index] == 0) + { + numCoveredVoxels++; + m_MeanSignal += image_value; + } + m_MeanTractDensity += seg.second; - if (m_FitIndividualFibers) - { - b[linear_index] = image_value; - A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + 1); - } - else - { - b[linear_index] = image_value; - A.put(linear_index, bundle, A.get(linear_index, bundle) + 1); + if (m_FitIndividualFibers) + { + b[linear_index] = image_value; + A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + seg.second); + } + else + { + b[linear_index] = image_value; + A.put(linear_index, bundle, A.get(linear_index, bundle) + seg.second); + } } } ++fiber_count; } } m_MeanTractDensity /= (numCoveredVoxels*fiber_count); m_MeanSignal /= numCoveredVoxels; A /= m_MeanTractDensity; b *= 100.0/m_MeanSignal; // times 100 because we want to avoid too small values for computational reasons // NEW FIT // m_MeanTractDensity /= numCoveredVoxels; // m_MeanSignal /= numCoveredVoxels; // b /= m_MeanSignal; // b *= m_MeanTractDensity; } void FitFibersToImageFilter::GenerateData() { m_NumUnknowns = m_Tractograms.size(); if (m_FitIndividualFibers) { m_NumUnknowns = 0; for (unsigned int bundle=0; bundleGetNumFibers(); } else m_FilterOutliers = false; if (m_NumUnknowns<1) { MITK_INFO << "No fibers in tractogram."; return; } fiber_count = 0; sz_x = 0; sz_y = 0; sz_z = 0; m_MeanTractDensity = 0; m_MeanSignal = 0; if (m_PeakImage.IsNotNull()) CreatePeakSystem(); else if (m_DiffImage.IsNotNull()) CreateDiffSystem(); else if (m_ScalarImage.IsNotNull()) CreateScalarSystem(); else mitkThrow() << "No input image set!"; + MITK_INFO << "Initializing optimizer"; double init_lambda = fiber_count; // initialization for lambda estimation itk::TimeProbe clock; clock.Start(); cost = VnlCostFunction(m_NumUnknowns); cost.SetProblem(A, b, init_lambda, m_Regularization); cost.SetGroupSizes(m_GroupSizes); m_Weights.set_size(m_NumUnknowns); m_Weights.fill( 1.0/m_NumUnknowns ); vnl_lbfgsb minimizer(cost); vnl_vector l; l.set_size(m_NumUnknowns); l.fill(0); vnl_vector bound_selection; bound_selection.set_size(m_NumUnknowns); bound_selection.fill(1); minimizer.set_bound_selection(bound_selection); minimizer.set_lower_bound(l); minimizer.set_projected_gradient_tolerance(m_GradientTolerance); if (m_Regularization==VnlCostFunction::REGU::MSM) MITK_INFO << "Regularization type: MSM"; else if (m_Regularization==VnlCostFunction::REGU::VARIANCE) MITK_INFO << "Regularization type: VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::LASSO) MITK_INFO << "Regularization type: LASSO"; else if (m_Regularization==VnlCostFunction::REGU::VOXEL_VARIANCE) MITK_INFO << "Regularization type: VOXEL_VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::GROUP_LASSO) MITK_INFO << "Regularization type: GROUP_LASSO"; else if (m_Regularization==VnlCostFunction::REGU::GROUP_VARIANCE) MITK_INFO << "Regularization type: GROUP_VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::NONE) MITK_INFO << "Regularization type: NONE"; if (m_Regularization!=VnlCostFunction::REGU::NONE) // REMOVE FOR NEW FIT AND SET cost.m_Lambda = m_Lambda { MITK_INFO << "Estimating regularization"; minimizer.set_trace(false); minimizer.set_max_function_evals(2); minimizer.minimize(m_Weights); vnl_vector dx; dx.set_size(m_NumUnknowns); dx.fill(0.0); cost.calc_regularization_gradient(m_Weights, dx); if (m_Weights.magnitude()==0) { MITK_INFO << "Regularization estimation failed. Using default value."; cost.m_Lambda = fiber_count*m_Lambda; } else { double r = dx.magnitude()/m_Weights.magnitude(); // wtf??? cost.m_Lambda *= m_Lambda*55.0/r; MITK_INFO << r << " - " << m_Lambda*55.0/r; if (cost.m_Lambda>10e7) { MITK_INFO << "Regularization estimation failed. Using default value."; cost.m_Lambda = fiber_count*m_Lambda; } } } else cost.m_Lambda = 0; MITK_INFO << "Using regularization factor of " << cost.m_Lambda << " (λ: " << m_Lambda << ")"; MITK_INFO << "Fitting fibers"; minimizer.set_trace(m_Verbose); minimizer.set_max_function_evals(m_MaxIterations); minimizer.minimize(m_Weights); std::vector< double > weights; if (m_FilterOutliers) { for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); MITK_INFO << "Setting upper weight bound to " << weights.at(m_NumUnknowns*0.99); vnl_vector u; u.set_size(m_NumUnknowns); u.fill(weights.at(m_NumUnknowns*0.99)); minimizer.set_upper_bound(u); bound_selection.fill(2); minimizer.set_bound_selection(bound_selection); minimizer.minimize(m_Weights); weights.clear(); } for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); m_MeanWeight = m_Weights.mean(); m_MedianWeight = weights.at(m_NumUnknowns*0.5); m_MinWeight = weights.at(0); m_MaxWeight = weights.at(m_NumUnknowns-1); MITK_INFO << "*************************"; MITK_INFO << "Weight statistics"; MITK_INFO << "Sum: " << m_Weights.sum(); MITK_INFO << "Mean: " << m_MeanWeight; MITK_INFO << "1% quantile: " << weights.at(m_NumUnknowns*0.01); MITK_INFO << "5% quantile: " << weights.at(m_NumUnknowns*0.05); MITK_INFO << "25% quantile: " << weights.at(m_NumUnknowns*0.25); MITK_INFO << "Median: " << m_MedianWeight; MITK_INFO << "75% quantile: " << weights.at(m_NumUnknowns*0.75); MITK_INFO << "95% quantile: " << weights.at(m_NumUnknowns*0.95); MITK_INFO << "99% quantile: " << weights.at(m_NumUnknowns*0.99); MITK_INFO << "Min: " << m_MinWeight; MITK_INFO << "Max: " << m_MaxWeight; MITK_INFO << "*************************"; MITK_INFO << "NumEvals: " << minimizer.get_num_evaluations(); MITK_INFO << "NumIterations: " << minimizer.get_num_iterations(); MITK_INFO << "Residual cost: " << minimizer.get_end_error(); m_RMSE = cost.S->get_rms_error(m_Weights); MITK_INFO << "Final RMSE: " << m_RMSE; clock.Stop(); int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "Optimization took " << h << "h, " << m << "m and " << s << "s"; MITK_INFO << "Weighting fibers"; m_RmsDiffPerBundle.set_size(m_Tractograms.size()); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); if (m_FitIndividualFibers) { unsigned int fiber_count = 0; for (unsigned int bundle=0; bundle temp_weights; temp_weights.set_size(m_Weights.size()); temp_weights.copy_in(m_Weights.data_block()); for (int i=0; iGetNumFibers(); i++) { m_Tractograms.at(bundle)->SetFiberWeight(i, m_Weights[fiber_count]); temp_weights[fiber_count] = 0; ++fiber_count; } double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE; m_RmsDiffPerBundle[bundle] = d_rms; m_Tractograms.at(bundle)->Compress(0.1); m_Tractograms.at(bundle)->ColorFibersByFiberWeights(false, true); } } else { for (unsigned int i=0; i temp_weights; temp_weights.set_size(m_Weights.size()); temp_weights.copy_in(m_Weights.data_block()); temp_weights[i] = 0; double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE; m_RmsDiffPerBundle[i] = d_rms; m_Tractograms.at(i)->SetFiberWeights(m_Weights[i]); m_Tractograms.at(i)->Compress(0.1); m_Tractograms.at(i)->ColorFibersByFiberWeights(false, true); } } std::cout.rdbuf (old); // transform back A *= m_MeanSignal/100.0; b *= m_MeanSignal/100.0; MITK_INFO << "Generating output images ..."; if (m_PeakImage.IsNotNull()) GenerateOutputPeakImages(); else if (m_DiffImage.IsNotNull()) GenerateOutputDiffImages(); else if (m_ScalarImage.IsNotNull()) GenerateOutputScalarImages(); m_Coverage = m_Coverage/m_MeanSignal; m_Overshoot = m_Overshoot/m_MeanSignal; MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*m_Coverage << "%"; MITK_INFO << std::fixed << "Overshoot: " << setprecision(2) << 100.0*m_Overshoot << "%"; } void FitFibersToImageFilter::GenerateOutputDiffImages() { VectorImgType::PixelType pix; pix.SetSize(m_DiffImage->GetVectorLength()); pix.Fill(0); itk::ImageDuplicator< VectorImgType >::Pointer duplicator = itk::ImageDuplicator< VectorImgType >::New(); duplicator->SetInputImage(m_DiffImage); duplicator->Update(); m_UnderexplainedImageDiff = duplicator->GetOutput(); m_UnderexplainedImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_UnderexplainedImageDiff); duplicator->Update(); m_OverexplainedImageDiff = duplicator->GetOutput(); m_OverexplainedImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_OverexplainedImageDiff); duplicator->Update(); m_ResidualImageDiff = duplicator->GetOutput(); m_ResidualImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_ResidualImageDiff); duplicator->Update(); m_FittedImageDiff = duplicator->GetOutput(); m_FittedImageDiff->FillBuffer(pix); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); itk::ImageRegionIterator it1 = itk::ImageRegionIterator(m_DiffImage, m_DiffImage->GetLargestPossibleRegion()); itk::ImageRegionIterator it2 = itk::ImageRegionIterator(m_FittedImageDiff, m_FittedImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it3 = itk::ImageRegionIterator(m_ResidualImageDiff, m_ResidualImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it4 = itk::ImageRegionIterator(m_UnderexplainedImageDiff, m_UnderexplainedImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it5 = itk::ImageRegionIterator(m_OverexplainedImageDiff, m_OverexplainedImageDiff->GetLargestPossibleRegion()); m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; while( !it2.IsAtEnd() ) { itk::Index<3> idx3 = it2.GetIndex(); VectorImgType::PixelType original_pix =it1.Get(); VectorImgType::PixelType fitted_pix =it2.Get(); VectorImgType::PixelType residual_pix =it3.Get(); VectorImgType::PixelType underexplained_pix =it4.Get(); VectorImgType::PixelType overexplained_pix =it5.Get(); int num_nonzero_g = 0; double original_mean = 0; for (int g=0; gGetGradientDirection(g).GetNorm()>=mitk::eps ) { original_mean += original_pix[g]; ++num_nonzero_g; } } original_mean /= num_nonzero_g; for (int g=0; g=0) { underexplained_pix[g] = residual_pix[g]; m_Coverage += fitted_b[linear_index] + original_mean; } m_MeanSignal += b[linear_index] + original_mean; } it2.Set(fitted_pix); it3.Set(residual_pix); it4.Set(underexplained_pix); it5.Set(overexplained_pix); ++it1; ++it2; ++it3; ++it4; ++it5; } } void FitFibersToImageFilter::GenerateOutputScalarImages() { itk::ImageDuplicator< DoubleImgType >::Pointer duplicator = itk::ImageDuplicator< DoubleImgType >::New(); duplicator->SetInputImage(m_ScalarImage); duplicator->Update(); m_UnderexplainedImageScalar = duplicator->GetOutput(); m_UnderexplainedImageScalar->FillBuffer(0); duplicator->SetInputImage(m_UnderexplainedImageScalar); duplicator->Update(); m_OverexplainedImageScalar = duplicator->GetOutput(); m_OverexplainedImageScalar->FillBuffer(0); duplicator->SetInputImage(m_OverexplainedImageScalar); duplicator->Update(); m_ResidualImageScalar = duplicator->GetOutput(); m_ResidualImageScalar->FillBuffer(0); duplicator->SetInputImage(m_ResidualImageScalar); duplicator->Update(); m_FittedImageScalar = duplicator->GetOutput(); m_FittedImageScalar->FillBuffer(0); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); itk::ImageRegionIterator it1 = itk::ImageRegionIterator(m_ScalarImage, m_ScalarImage->GetLargestPossibleRegion()); itk::ImageRegionIterator it2 = itk::ImageRegionIterator(m_FittedImageScalar, m_FittedImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it3 = itk::ImageRegionIterator(m_ResidualImageScalar, m_ResidualImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it4 = itk::ImageRegionIterator(m_UnderexplainedImageScalar, m_UnderexplainedImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it5 = itk::ImageRegionIterator(m_OverexplainedImageScalar, m_OverexplainedImageScalar->GetLargestPossibleRegion()); m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; while( !it2.IsAtEnd() ) { itk::Index<3> idx3 = it2.GetIndex(); DoubleImgType::PixelType original_pix =it1.Get(); DoubleImgType::PixelType fitted_pix =it2.Get(); DoubleImgType::PixelType residual_pix =it3.Get(); DoubleImgType::PixelType underexplained_pix =it4.Get(); DoubleImgType::PixelType overexplained_pix =it5.Get(); unsigned int linear_index = idx3[0] + sz_x*idx3[1] + sz_x*sz_y*idx3[2]; fitted_pix = fitted_b[linear_index]; residual_pix = original_pix - fitted_pix; if (residual_pix<0) { overexplained_pix = residual_pix; m_Coverage += b[linear_index]; m_Overshoot -= residual_pix; } else if (residual_pix>=0) { underexplained_pix = residual_pix; m_Coverage += fitted_b[linear_index]; } m_MeanSignal += b[linear_index]; it2.Set(fitted_pix); it3.Set(residual_pix); it4.Set(underexplained_pix); it5.Set(overexplained_pix); ++it1; ++it2; ++it3; ++it4; ++it5; } } VnlCostFunction::REGU FitFibersToImageFilter::GetRegularization() const { return m_Regularization; } void FitFibersToImageFilter::SetRegularization(const VnlCostFunction::REGU &Regularization) { m_Regularization = Regularization; } void FitFibersToImageFilter::GenerateOutputPeakImages() { itk::ImageDuplicator< PeakImgType >::Pointer duplicator = itk::ImageDuplicator< PeakImgType >::New(); duplicator->SetInputImage(m_PeakImage); duplicator->Update(); m_UnderexplainedImage = duplicator->GetOutput(); m_UnderexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_UnderexplainedImage); duplicator->Update(); m_OverexplainedImage = duplicator->GetOutput(); m_OverexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_OverexplainedImage); duplicator->Update(); m_ResidualImage = duplicator->GetOutput(); m_ResidualImage->FillBuffer(0.0); duplicator->SetInputImage(m_ResidualImage); duplicator->Update(); m_FittedImage = duplicator->GetOutput(); m_FittedImage->FillBuffer(0.0); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); for (unsigned int r=0; r idx4; unsigned int linear_index = r; idx4[0] = linear_index % sz_x; linear_index /= sz_x; idx4[1] = linear_index % sz_y; linear_index /= sz_y; idx4[2] = linear_index % sz_z; linear_index /= sz_z; int peak_id = linear_index % dim_four_size; if (peak_id peak_dir; idx4[3] = peak_id*3; peak_dir[0] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[1] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[2] = m_PeakImage->GetPixel(idx4); peak_dir.normalize(); peak_dir *= fitted_b[r]; idx4[3] = peak_id*3; m_FittedImage->SetPixel(idx4, peak_dir[0]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[1]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[2]); } } m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; itk::Index<4> idx4; for (idx4[0]=0; idx4[0] idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; if (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0) continue; vnl_vector_fixed peak_dir; vnl_vector_fixed fitted_dir; vnl_vector_fixed overshoot_dir; for (idx4[3]=0; idx4[3]<(itk::IndexValueType)m_PeakImage->GetLargestPossibleRegion().GetSize(3); ++idx4[3]) { peak_dir[idx4[3]%3] = m_PeakImage->GetPixel(idx4); fitted_dir[idx4[3]%3] = m_FittedImage->GetPixel(idx4); m_ResidualImage->SetPixel(idx4, m_PeakImage->GetPixel(idx4) - m_FittedImage->GetPixel(idx4)); if (idx4[3]%3==2) { m_MeanSignal += peak_dir.magnitude(); itk::Index<4> tidx= idx4; if (peak_dir.magnitude()>fitted_dir.magnitude()) { m_Coverage += fitted_dir.magnitude(); m_UnderexplainedImage->SetPixel(tidx, peak_dir[2]-fitted_dir[2]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[1]-fitted_dir[1]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[0]-fitted_dir[0]); } else { overshoot_dir[0] = fitted_dir[0]-peak_dir[0]; overshoot_dir[1] = fitted_dir[1]-peak_dir[1]; overshoot_dir[2] = fitted_dir[2]-peak_dir[2]; m_Coverage += peak_dir.magnitude(); m_Overshoot += overshoot_dir.magnitude(); m_OverexplainedImage->SetPixel(tidx, overshoot_dir[2]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[1]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[0]); } } } } } void FitFibersToImageFilter::GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer peak_image , vnl_vector_fixed fiber_dir, int& id, double& w, double& peak_mag ) { int m_NumDirs = peak_image->GetLargestPossibleRegion().GetSize()[3]/3; vnl_vector_fixed out_dir; out_dir.fill(0); float angle = 0.9; for (int i=0; i dir; idx[3] = i*3; dir[0] = peak_image->GetPixel(idx); idx[3] += 1; dir[1] = peak_image->GetPixel(idx); idx[3] += 1; dir[2] = peak_image->GetPixel(idx); float mag = dir.magnitude(); if (magangle) { angle = a; w = angle; peak_mag = mag; id = i; } } } std::vector FitFibersToImageFilter::GetTractograms() const { return m_Tractograms; } void FitFibersToImageFilter::SetTractograms(const std::vector &tractograms) { m_Tractograms = tractograms; } void FitFibersToImageFilter::SetSignalModel(mitk::DiffusionSignalModel<> *SignalModel) { m_SignalModel = SignalModel; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h index e5d56fe256..e5f1259749 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h @@ -1,483 +1,475 @@ #ifndef __itkFitFibersToImageFilter_h__ #define __itkFitFibersToImageFilter_h__ // MITK #include #include #include #include #include #include #include #include #include #include #include class VnlCostFunction : public vnl_cost_function { public: enum REGU { MSM, VARIANCE, LASSO, VOXEL_VARIANCE, GROUP_LASSO, GROUP_VARIANCE, NONE }; vnl_sparse_matrix_linear_system< double >* S; vnl_sparse_matrix< double > m_A; vnl_sparse_matrix< double > m_A_Ones; // matrix indicating active weights with 1 vnl_vector< double > m_b; double m_Lambda; // regularization factor vnl_vector row_sums; // number of active weights per row vnl_vector local_weight_means; // mean weight of each row REGU regularization; std::vector group_sizes; void SetProblem(vnl_sparse_matrix< double >& A, vnl_vector& b, double lambda, REGU regu) { S = new vnl_sparse_matrix_linear_system(A, b); m_A = A; m_b = b; m_Lambda = lambda; m_A_Ones.set_size(m_A.rows(), m_A.cols()); m_A.reset(); while (m_A.next()) m_A_Ones.put(m_A.getrow(), m_A.getcolumn(), 1); unsigned int N = m_b.size(); vnl_vector ones; ones.set_size(dim); ones.fill(1.0); row_sums.set_size(N); m_A_Ones.mult(ones, row_sums); local_weight_means.set_size(N); regularization = regu; } void SetGroupSizes(std::vector sizes) { unsigned int sum = 0; for (auto s : sizes) sum += s; if (sum!=m_A.cols()) { MITK_INFO << "Group sizes do not match number of unknowns (" << sum << " vs. " << m_A.cols() << ")"; return; } group_sizes = sizes; } VnlCostFunction(const int NumVars=0) : vnl_cost_function(NumVars) { } // Regularization: mean squared magnitude of weight vectors (small weights) void regu_MSM(vnl_vector const &x, double& cost) { cost += 10000.0*m_Lambda*x.squared_magnitude()/dim; } // Regularization: mean squared deaviation of weights from mean weight (enforce uniform weights) void regu_Variance(vnl_vector const &x, double& cost) { double mean = x.mean(); vnl_vector tx = x-mean; cost += 10000.0*m_Lambda*tx.squared_magnitude()/dim; } // Regularization: mean absolute magnitude of weight vectors (small weights) L1 void regu_Lasso(vnl_vector const &x, double& cost) { cost += m_Lambda*x.one_norm()/dim; } // Regularization: mean squared deaviation of weights from bundle mean weight (enforce uniform weights PER BUNDLE) void regu_GroupVariance(vnl_vector const &x, double& cost) { vnl_vector tx(x); unsigned int offset = 0; for (auto g : group_sizes) { double group_mean = 0; for (unsigned int i=0; i const &x, double& cost) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); m_A_Ones.reset(); double regu = 0; while (m_A_Ones.next()) { double d = 0; if (x[m_A_Ones.getcolumn()]>local_weight_means[m_A_Ones.getrow()]) d = std::exp(x[m_A_Ones.getcolumn()]) - std::exp(local_weight_means[m_A_Ones.getrow()]); else d = x[m_A_Ones.getcolumn()] - local_weight_means[m_A_Ones.getrow()]; regu += d*d; } cost += m_Lambda*regu/dim; } // Regularization: group Lasso: sum_g(lambda_g * ||x_g||_2) void regu_GroupLasso(vnl_vector const &x, double& cost) { unsigned int offset = 0; for (auto g : group_sizes) { double group_cost = 0; for (unsigned int i=0; i const &x, vnl_vector &dx) { dx += 10000.0*m_Lambda*2.0*x/dim; } void grad_regu_Variance(vnl_vector const &x, vnl_vector &dx) { double mean = x.mean(); vnl_vector tx = x-mean; // difference to mean dx += 10000.0*tx*(2.0-2.0/dim)/dim; } void grad_regu_Lasso(vnl_vector const &x, vnl_vector &dx) { for (int i=0; i0) dx[i] += m_Lambda/dim; } void grad_regu_GroupVariance(vnl_vector const &x, vnl_vector &dx) { vnl_vector tx(x); unsigned int offset = 0; for (auto g : group_sizes) { double group_mean = 0; for (unsigned int i=0; i const &x, vnl_vector &dx) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); vnl_vector exp_x = x.apply(std::exp); vnl_vector exp_means = local_weight_means.apply(std::exp); vnl_vector tdx(dim, 0); m_A_Ones.reset(); while (m_A_Ones.next()) { int c = m_A_Ones.getcolumn(); int r = m_A_Ones.getrow(); if (x[c]>local_weight_means[r]) tdx[c] += exp_x[c] * ( exp_x[c] - exp_means[r] ); else tdx[c] += x[c] - local_weight_means[r]; } dx += tdx*2.0*m_Lambda/dim; } void grad_regu_GroupLasso(vnl_vector const &x, vnl_vector &dx) { unsigned int offset = 0; for (auto g : group_sizes) { double group_lambda = m_Lambda*std::sqrt(g)/dim; double group_l2 = 0; for (unsigned int i=0; i0.0) { for (unsigned int i=0; i const &x, double& cost) { if (regularization==VOXEL_VARIANCE) regu_VoxelVariance(x, cost); else if (regularization==VARIANCE) regu_Variance(x, cost); else if (regularization==MSM) regu_MSM(x, cost); else if (regularization==LASSO) regu_Lasso(x, cost); else if (regularization==GROUP_LASSO) regu_GroupLasso(x, cost); else if (regularization==GROUP_VARIANCE) regu_GroupVariance(x, cost); } void calc_regularization_gradient(vnl_vector const &x, vnl_vector &dx) { if (regularization==VOXEL_VARIANCE) grad_regu_VoxelVariance(x,dx); else if (regularization==VARIANCE) grad_regu_Variance(x,dx); else if (regularization==MSM) grad_regu_MSM(x,dx); else if (regularization==LASSO) grad_regu_Lasso(x,dx); else if (regularization==GROUP_LASSO) grad_regu_GroupLasso(x, dx); else if (regularization==GROUP_VARIANCE) grad_regu_GroupVariance(x, dx); } // cost function double f(vnl_vector const &x) { // RMS error unsigned int N = m_b.size(); vnl_vector d; d.set_size(N); S->multiply(x,d); double cost = (d - m_b).squared_magnitude()/N; // regularize calc_regularization(x, cost); return cost; } // gradient of cost function void gradf(vnl_vector const &x, vnl_vector &dx) { dx.fill(0.0); unsigned int N = m_b.size(); // calculate output difference d vnl_vector d; d.set_size(N); S->multiply(x,d); d -= m_b; // (f(u(x)))' = f'(u(x)) * u'(x) // d/dx_j = 1/N * Sum_i A_i,j * 2*(A_i,j * x_j - b_i) S->transpose_multiply(d, dx); dx *= 2.0/N; calc_regularization_gradient(x,dx); } }; namespace itk{ /** * \brief Fits the tractogram to the input image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ class FitFibersToImageFilter : public ImageSource< mitk::PeakImage::ItkPeakImageType > { public: typedef FitFibersToImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Point PointType3; typedef itk::Point PointType4; typedef mitk::DiffusionPropertyHelper::ImageType VectorImgType; typedef mitk::PeakImage::ItkPeakImageType PeakImgType; typedef itk::Image UcharImgType; typedef itk::Image DoubleImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FitFibersToImageFilter, ImageSource ) itkSetMacro( ScalarImage, DoubleImgType::Pointer) itkGetMacro( ScalarImage, DoubleImgType::Pointer) itkSetMacro( PeakImage, PeakImgType::Pointer) itkGetMacro( PeakImage, PeakImgType::Pointer) itkSetMacro( DiffImage, VectorImgType::Pointer) itkGetMacro( DiffImage, VectorImgType::Pointer) itkSetMacro( MaskImage, UcharImgType::Pointer) itkGetMacro( MaskImage, UcharImgType::Pointer) itkSetMacro( FitIndividualFibers, bool) itkGetMacro( FitIndividualFibers, bool) itkSetMacro( GradientTolerance, double) itkGetMacro( GradientTolerance, double) itkSetMacro( Lambda, double) itkGetMacro( Lambda, double) itkSetMacro( MaxIterations, int) itkGetMacro( MaxIterations, int) - itkSetMacro( FiberSampling, float) - itkGetMacro( FiberSampling, float) itkSetMacro( FilterOutliers, bool) itkGetMacro( FilterOutliers, bool) itkSetMacro( Verbose, bool) itkGetMacro( Verbose, bool) - itkSetMacro( DeepCopy, bool) - itkGetMacro( DeepCopy, bool) - itkSetMacro( ResampleFibers, bool) - itkGetMacro( ResampleFibers, bool) itkGetMacro( Weights, vnl_vector) itkGetMacro( RmsDiffPerBundle, vnl_vector) itkGetMacro( FittedImage, PeakImgType::Pointer) itkGetMacro( ResidualImage, PeakImgType::Pointer) itkGetMacro( OverexplainedImage, PeakImgType::Pointer) itkGetMacro( UnderexplainedImage, PeakImgType::Pointer) itkGetMacro( FittedImageDiff, VectorImgType::Pointer) itkGetMacro( ResidualImageDiff, VectorImgType::Pointer) itkGetMacro( OverexplainedImageDiff, VectorImgType::Pointer) itkGetMacro( UnderexplainedImageDiff, VectorImgType::Pointer) itkGetMacro( FittedImageScalar, DoubleImgType::Pointer) itkGetMacro( ResidualImageScalar, DoubleImgType::Pointer) itkGetMacro( OverexplainedImageScalar, DoubleImgType::Pointer) itkGetMacro( UnderexplainedImageScalar, DoubleImgType::Pointer) itkGetMacro( Coverage, double) itkGetMacro( Overshoot, double) itkGetMacro( RMSE, double) itkGetMacro( MeanWeight, double) itkGetMacro( MedianWeight, double) itkGetMacro( MinWeight, double) itkGetMacro( MaxWeight, double) itkGetMacro( NumUnknowns, unsigned int) itkGetMacro( NumResiduals, unsigned int) itkGetMacro( NumCoveredDirections, unsigned int) void SetTractograms(const std::vector &tractograms); void GenerateData() override; std::vector GetTractograms() const; void SetSignalModel(mitk::DiffusionSignalModel<> *SignalModel); VnlCostFunction::REGU GetRegularization() const; void SetRegularization(const VnlCostFunction::REGU &GetRegularization); protected: FitFibersToImageFilter(); virtual ~FitFibersToImageFilter(); + itk::Point GetItkPoint(double point[3]); void GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer m_PeakImage , vnl_vector_fixed fiber_dir, int& id, double& w, double& peak_mag ); void CreatePeakSystem(); void CreateDiffSystem(); void CreateScalarSystem(); void GenerateOutputPeakImages(); void GenerateOutputDiffImages(); void GenerateOutputScalarImages(); std::vector< mitk::FiberBundle::Pointer > m_Tractograms; PeakImgType::Pointer m_PeakImage; VectorImgType::Pointer m_DiffImage; DoubleImgType::Pointer m_ScalarImage; UcharImgType::Pointer m_MaskImage; bool m_FitIndividualFibers; double m_GradientTolerance; double m_Lambda; int m_MaxIterations; - float m_FiberSampling; double m_Coverage; double m_Overshoot; double m_RMSE; bool m_FilterOutliers; double m_MeanWeight; double m_MedianWeight; double m_MinWeight; double m_MaxWeight; bool m_Verbose; - bool m_DeepCopy; - bool m_ResampleFibers; unsigned int m_NumUnknowns; unsigned int m_NumResiduals; unsigned int m_NumCoveredDirections; // output vnl_vector m_RmsDiffPerBundle; vnl_vector m_Weights; PeakImgType::Pointer m_UnderexplainedImage; PeakImgType::Pointer m_OverexplainedImage; PeakImgType::Pointer m_ResidualImage; PeakImgType::Pointer m_FittedImage; VectorImgType::Pointer m_UnderexplainedImageDiff; VectorImgType::Pointer m_OverexplainedImageDiff; VectorImgType::Pointer m_ResidualImageDiff; VectorImgType::Pointer m_FittedImageDiff; DoubleImgType::Pointer m_UnderexplainedImageScalar; DoubleImgType::Pointer m_OverexplainedImageScalar; DoubleImgType::Pointer m_ResidualImageScalar; DoubleImgType::Pointer m_FittedImageScalar; mitk::DiffusionSignalModel<>* m_SignalModel; vnl_sparse_matrix A; vnl_vector b; VnlCostFunction cost; int sz_x; int sz_y; int sz_z; int dim_four_size; double m_MeanTractDensity; double m_MeanSignal; unsigned int fiber_count; VnlCostFunction::REGU m_Regularization; std::vector m_GroupSizes; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFitFibersToImageFilter.cpp" #endif #endif // __itkFitFibersToImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/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/Algorithms/itkTractDensityImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp index 3938627d56..254c0a41f9 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp @@ -1,273 +1,187 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Coindex[1]right (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractDensityImageFilter.h" // VTK #include #include #include #include // misc #include #include +#include +#include namespace itk{ template< class OutputImageType > TractDensityImageFilter< OutputImageType >::TractDensityImageFilter() : m_UpsamplingFactor(1) , m_InvertImage(false) , m_BinaryOutput(false) , m_UseImageGeometry(false) , m_OutputAbsoluteValues(false) - , m_UseTrilinearInterpolation(false) - , m_DoFiberResampling(true) - , m_WorkOnFiberCopy(true) , m_MaxDensity(0) , m_NumCoveredVoxels(0) { } template< class OutputImageType > TractDensityImageFilter< OutputImageType >::~TractDensityImageFilter() { } template< class OutputImageType > itk::Point TractDensityImageFilter< OutputImageType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class OutputImageType > void TractDensityImageFilter< OutputImageType >::GenerateData() { // generate upsampled image mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); typename OutputImageType::Pointer outImage = this->GetOutput(); // calculate new image parameters itk::Vector newSpacing; mitk::Point3D newOrigin; itk::Matrix newDirection; ImageRegion<3> upsampledRegion; if (m_UseImageGeometry && !m_InputImage.IsNull()) { MITK_INFO << "TractDensityImageFilter: using image geometry"; newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; upsampledRegion = m_InputImage->GetLargestPossibleRegion(); newOrigin = m_InputImage->GetOrigin(); typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); size[0] *= m_UpsamplingFactor; size[1] *= m_UpsamplingFactor; size[2] *= m_UpsamplingFactor; upsampledRegion.SetSize(size); newDirection = m_InputImage->GetDirection(); } else { MITK_INFO << "TractDensityImageFilter: using fiber bundle geometry"; newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); // we retrieve the origin from a vtk-polydata (corner-based) and hance have to translate it to an image geometry // i.e. center-based newOrigin[0] += bounds.GetElement(0) + 0.5 * newSpacing[0]; newOrigin[1] += bounds.GetElement(2) + 0.5 * newSpacing[1]; newOrigin[2] += bounds.GetElement(4) + 0.5 * newSpacing[2]; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; upsampledRegion.SetSize(0, ceil( geometry->GetExtent(0)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(1, ceil( geometry->GetExtent(1)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(2, ceil( geometry->GetExtent(2)*m_UpsamplingFactor ) ); } typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // apply new image parameters outImage->SetSpacing( newSpacing ); outImage->SetOrigin( newOrigin ); outImage->SetDirection( newDirection ); outImage->SetLargestPossibleRegion( upsampledRegion ); outImage->SetBufferedRegion( upsampledRegion ); outImage->SetRequestedRegion( upsampledRegion ); outImage->Allocate(); outImage->FillBuffer(0.0); int w = upsampledSize[0]; int h = upsampledSize[1]; int d = upsampledSize[2]; // set/initialize output OutPixelType* outImageBufferPointer = (OutPixelType*)outImage->GetBufferPointer(); - // resample fiber bundle - float minSpacing = 1; - if(newSpacing[0]GetDeepCopy(); - m_FiberBundle->ResampleLinear(minSpacing/10); - } - MITK_INFO << "TractDensityImageFilter: starting image generation"; - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float weight = m_FiberBundle->GetFiberWeight(i); // fill output image - for( int j=0; j vertex = GetItkPoint(points->GetPoint(j)); - itk::Index<3> index; - itk::ContinuousIndex contIndex; - outImage->TransformPhysicalPointToIndex(vertex, index); - outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); - - if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index)) + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + outImage->TransformPhysicalPointToIndex(startVertex, startIndex); + outImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + outImage->TransformPhysicalPointToIndex(endVertex, endIndex); + outImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(newSpacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - if (outImage->GetPixel(index)==0) + if (outImage->GetPixel(segment.first)==0) m_NumCoveredVoxels++; if (m_BinaryOutput) - outImage->SetPixel(index, 1); + outImage->SetPixel(segment.first, 1); else - outImage->SetPixel(index, outImage->GetPixel(index)+weight); - continue; - } - - float frac_x = contIndex[0] - index[0]; - float frac_y = contIndex[1] - index[1]; - float frac_z = contIndex[2] - index[2]; - - if (frac_x<0) - { - index[0] -= 1; - frac_x += 1; - } - if (frac_y<0) - { - index[1] -= 1; - frac_y += 1; - } - if (frac_z<0) - { - index[2] -= 1; - frac_z += 1; - } - - frac_x = 1-frac_x; - frac_y = 1-frac_y; - frac_z = 1-frac_z; - - // int coordinates inside image? - if (index[0] < 0 || index[0] >= w-1) - continue; - if (index[1] < 0 || index[1] >= h-1) - continue; - if (index[2] < 0 || index[2] >= d-1) - continue; - - - if (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))]==0) - m_NumCoveredVoxels++; - - if (m_BinaryOutput) - { - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] = 1; - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] = 1; - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] = 1; - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] = 1; - } - else - { - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] += ( frac_x)*( frac_y)*( frac_z); - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] += ( frac_x)*(1-frac_y)*( frac_z); - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] += ( frac_x)*( frac_y)*(1-frac_z); - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] += ( frac_x)*(1-frac_y)*(1-frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] += (1-frac_x)*( frac_y)*( frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] += (1-frac_x)*( frac_y)*(1-frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] += (1-frac_x)*(1-frac_y)*( frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] += (1-frac_x)*(1-frac_y)*(1-frac_z); + outImage->SetPixel(segment.first, outImage->GetPixel(segment.first)+segment.second * weight); } } } m_MaxDensity = 0; for (int i=0; i0) for (int i=0; i #include #include #include #include namespace itk{ /** * \brief Generates tract density images from input fiberbundles (Calamante 2010). */ template< class OutputImageType > class TractDensityImageFilter : public ImageSource< OutputImageType > { public: typedef TractDensityImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename OutputImageType::PixelType OutPixelType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractDensityImageFilter, ImageSource ) itkSetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkGetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkSetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkGetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkSetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkGetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkSetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkGetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkSetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkGetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle itkSetMacro( InputImage, typename OutputImageType::Pointer) ///< use input image geometry to initialize output image - itkSetMacro( UseTrilinearInterpolation, bool ) - itkSetMacro( DoFiberResampling, bool ) - itkSetMacro( WorkOnFiberCopy, bool ) itkGetMacro( MaxDensity, OutPixelType) itkGetMacro( NumCoveredVoxels, unsigned int) void GenerateData() override; protected: itk::Point GetItkPoint(double point[3]); TractDensityImageFilter(); ~TractDensityImageFilter() override; typename OutputImageType::Pointer m_InputImage; ///< use input image geometry to initialize output image mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle float m_UpsamplingFactor; ///< use higher resolution for ouput image bool m_InvertImage; ///< voxelvalue = 1-voxelvalue bool m_BinaryOutput; ///< generate binary fiber envelope bool m_UseImageGeometry; ///< use input image geometry to initialize output image bool m_OutputAbsoluteValues; ///< do not normalize image values to 0-1 bool m_UseTrilinearInterpolation; bool m_DoFiberResampling; bool m_WorkOnFiberCopy; OutPixelType m_MaxDensity; unsigned int m_NumCoveredVoxels; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractDensityImageFilter.cpp" #endif #endif // __itkTractDensityImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp index 1d68533729..044a6a265c 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp @@ -1,284 +1,197 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToRgbaImageFilter.h" // VTK #include #include #include // misc #include #include +#include namespace itk{ - template< class OutputImageType > - TractsToRgbaImageFilter< OutputImageType >::TractsToRgbaImageFilter() - : m_UpsamplingFactor(1) - , m_UseImageGeometry(false) - , m_InputImage(nullptr) - { +template< class OutputImageType > +TractsToRgbaImageFilter< OutputImageType >::TractsToRgbaImageFilter() + : m_UpsamplingFactor(1) + , m_UseImageGeometry(false) + , m_InputImage(nullptr) +{ - } +} + +template< class OutputImageType > +TractsToRgbaImageFilter< OutputImageType >::~TractsToRgbaImageFilter() +{ +} + +template< class OutputImageType > +itk::Point TractsToRgbaImageFilter< OutputImageType >::GetItkPoint(double point[3]) +{ + itk::Point itkPoint; + itkPoint[0] = point[0]; + itkPoint[1] = point[1]; + itkPoint[2] = point[2]; + return itkPoint; +} - template< class OutputImageType > - TractsToRgbaImageFilter< OutputImageType >::~TractsToRgbaImageFilter() +template< class OutputImageType > +void TractsToRgbaImageFilter< OutputImageType >::GenerateData() +{ + if(&typeid(OutPixelType) != &typeid(itk::RGBAPixel)) + return; + + // generate upsampled image + mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); + typename OutputImageType::Pointer outImage = this->GetOutput(); + + // calculate new image parameters + itk::Vector newSpacing; + mitk::Point3D newOrigin; + itk::Matrix newDirection; + ImageRegion<3> upsampledRegion; + if (m_UseImageGeometry && !m_InputImage.IsNull()) { + newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; + upsampledRegion = m_InputImage->GetLargestPossibleRegion(); + newOrigin = m_InputImage->GetOrigin(); + typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); + size[0] *= m_UpsamplingFactor; + size[1] *= m_UpsamplingFactor; + size[2] *= m_UpsamplingFactor; + upsampledRegion.SetSize(size); + newDirection = m_InputImage->GetDirection(); } - - template< class OutputImageType > - itk::Point TractsToRgbaImageFilter< OutputImageType >::GetItkPoint(double point[3]) + else { - itk::Point itkPoint; - itkPoint[0] = point[0]; - itkPoint[1] = point[1]; - itkPoint[2] = point[2]; - return itkPoint; + newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; + newOrigin = geometry->GetOrigin(); + mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); + newOrigin[0] += bounds.GetElement(0); + newOrigin[1] += bounds.GetElement(2); + newOrigin[2] += bounds.GetElement(4); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; + upsampledRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); + upsampledRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); + upsampledRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); } - - template< class OutputImageType > - void TractsToRgbaImageFilter< OutputImageType >::GenerateData() + typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); + + // apply new image parameters + outImage->SetSpacing( newSpacing ); + outImage->SetOrigin( newOrigin ); + outImage->SetDirection( newDirection ); + outImage->SetRegions( upsampledRegion ); + outImage->Allocate(); + outImage->FillBuffer(0.0); + + itk::Image< itk::RGBAPixel, 3 >::Pointer double_out = itk::Image< itk::RGBAPixel, 3 >::New(); + double_out->SetSpacing( newSpacing ); + double_out->SetOrigin( newOrigin ); + double_out->SetDirection( newDirection ); + double_out->SetRegions( upsampledRegion ); + double_out->Allocate(); + double_out->FillBuffer(0.0); + + vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + int numFibers = m_FiberBundle->GetNumFibers(); + + float scale = 100 * pow((float)m_UpsamplingFactor,3); + boost::progress_display disp(numFibers); + for( int i=0; i)) - return; - - // generate upsampled image - mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); - typename OutputImageType::Pointer outImage = this->GetOutput(); - - // calculate new image parameters - itk::Vector newSpacing; - mitk::Point3D newOrigin; - itk::Matrix newDirection; - ImageRegion<3> upsampledRegion; - if (m_UseImageGeometry && !m_InputImage.IsNull()) - { - newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; - upsampledRegion = m_InputImage->GetLargestPossibleRegion(); - newOrigin = m_InputImage->GetOrigin(); - typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); - size[0] *= m_UpsamplingFactor; - size[1] *= m_UpsamplingFactor; - size[2] *= m_UpsamplingFactor; - upsampledRegion.SetSize(size); - newDirection = m_InputImage->GetDirection(); - } - else - { - newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; - newOrigin = geometry->GetOrigin(); - mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); - newOrigin[0] += bounds.GetElement(0); - newOrigin[1] += bounds.GetElement(2); - newOrigin[2] += bounds.GetElement(4); - - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; - upsampledRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); - upsampledRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); - upsampledRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); - } - typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); - - // apply new image parameters - outImage->SetSpacing( newSpacing ); - outImage->SetOrigin( newOrigin ); - outImage->SetDirection( newDirection ); - outImage->SetRegions( upsampledRegion ); - outImage->Allocate(); - - int w = upsampledSize[0]; - int h = upsampledSize[1]; - int d = upsampledSize[2]; - - // set/initialize output - unsigned char* outImageBufferPointer = (unsigned char*)outImage->GetBufferPointer(); - float* buffer = new float[w*h*d*4]; - for (int i=0; iGetDeepCopy(); - m_FiberBundle->ResampleLinear(minSpacing); - - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + ++disp; + vtkCell* cell = fiberPolyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); - int numFibers = m_FiberBundle->GetNumFibers(); - boost::progress_display disp(numFibers); - for( int i=0; iGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - // calc directions (which are used as weights) - std::list< itk::Point > rgbweights; - std::list intensities; - - for( int j=0; j startVertex = GetItkPoint(points->GetPoint(j)); + Index<3> startIndex; + ContinuousIndex startIndexCont; + double_out->TransformPhysicalPointToIndex(startVertex, startIndex); + double_out->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + Index<3> endIndex; + ContinuousIndex endIndexCont; + double_out->TransformPhysicalPointToIndex(endVertex, endIndex); + double_out->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + Vector dir; + dir[0] = fabs(endVertex[0]-startVertex[0]); + dir[1] = fabs(endVertex[1]-startVertex[1]); + dir[2] = fabs(endVertex[2]-startVertex[2]); + dir.Normalize(); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(newSpacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - - itk::Point vertex = GetItkPoint(points->GetPoint(j)); - itk::Point vertexPost = GetItkPoint(points->GetPoint(j+1)); - - itk::Point dir; - dir[0] = fabs((vertexPost[0] - vertex[0]) * outImage->GetSpacing()[0]); - dir[1] = fabs((vertexPost[1] - vertex[1]) * outImage->GetSpacing()[1]); - dir[2] = fabs((vertexPost[2] - vertex[2]) * outImage->GetSpacing()[2]); - - rgbweights.push_back(dir); - - float intensity = sqrt(dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]); - intensities.push_back(intensity); - - // last point gets same as previous one - if(j==numPoints-2) - { - rgbweights.push_back(dir); - intensities.push_back(intensity); - } - } - - // fill output image - for( int j=0; j vertex = GetItkPoint(points->GetPoint(j)); - itk::Index<3> index; - itk::ContinuousIndex contIndex; - outImage->TransformPhysicalPointToIndex(vertex, index); - outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); - - float frac_x = contIndex[0] - index[0]; - float frac_y = contIndex[1] - index[1]; - float frac_z = contIndex[2] - index[2]; - - int px = index[0]; - if (frac_x<0) - { - px -= 1; - frac_x += 1; - } - - int py = index[1]; - if (frac_y<0) - { - py -= 1; - frac_y += 1; - } - - int pz = index[2]; - if (frac_z<0) - { - pz -= 1; - frac_z += 1; - } - - // int coordinates inside image? - if (px < 0 || px >= w-1) - continue; - if (py < 0 || py >= h-1) - continue; - if (pz < 0 || pz >= d-1) + if (!double_out->GetLargestPossibleRegion().IsInside(segment.first)) continue; - float scale = 100 * pow((float)m_UpsamplingFactor,3); - itk::Point rgbweight = rgbweights.front(); - rgbweights.pop_front(); - float intweight = intensities.front(); - intensities.pop_front(); - - // add to r-channel in output image - buffer[0+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[0] * scale; - - // add to g-channel in output image - buffer[1+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[1] * scale; - - // add to b-channel in output image - buffer[2+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[2] * scale; + itk::RGBAPixel pix = double_out->GetPixel(segment.first); + pix[0] += dir[0] * scale; + pix[1] += dir[1] * scale; + pix[2] += dir[2] * scale; + pix[3] += segment.second * scale; - // add to a-channel in output image - buffer[3+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * intweight * scale; + double_out->SetPixel(segment.first, pix); } } + float maxRgb = 0.000000001; float maxInt = 0.000000001; - int numPix; + int w = upsampledSize[0]; + int h = upsampledSize[1]; + int d = upsampledSize[2]; + int numPix = w*h*d*4; - numPix = w*h*d*4; + double* buffer = (double*)double_out->GetBufferPointer(); // calc maxima for(int i=0; i maxRgb) maxRgb = buffer[i]; } else { if(buffer[i] > maxInt) maxInt = buffer[i]; } } // write output, normalized uchar 0..255 + unsigned char* outImageBufferPointer = (unsigned char*)outImage->GetBufferPointer(); for(int i=0; i #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include - +#include namespace itk{ static inline bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType > TractsToVectorImageFilter< PixelType >::TractsToVectorImageFilter(): m_NormalizationMethod(GLOBAL_MAX), m_AngularThreshold(0.7), m_Epsilon(0.999), - m_UseWorkingCopy(true), m_MaxNumDirections(3), m_SizeThreshold(0.3) { this->SetNumberOfRequiredOutputs(1); } template< class PixelType > TractsToVectorImageFilter< PixelType >::~TractsToVectorImageFilter() { } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > itk::Point TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > void TractsToVectorImageFilter< PixelType >::GenerateData() { mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); // calculate new image parameters itk::Vector spacing3; itk::Point origin3; itk::Matrix direction3; ImageRegion<3> imageRegion3; if (!m_MaskImage.IsNull()) { spacing3 = m_MaskImage->GetSpacing(); imageRegion3 = m_MaskImage->GetLargestPossibleRegion(); origin3 = m_MaskImage->GetOrigin(); direction3 = m_MaskImage->GetDirection(); } else { spacing3 = geometry->GetSpacing(); origin3 = geometry->GetOrigin(); mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); origin3[0] += bounds.GetElement(0); origin3[1] += bounds.GetElement(2); origin3[2] += bounds.GetElement(4); for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction3[j][i] = geometry->GetMatrixColumn(i)[j]; imageRegion3.SetSize(0, geometry->GetExtent(0)+1); imageRegion3.SetSize(1, geometry->GetExtent(1)+1); imageRegion3.SetSize(2, geometry->GetExtent(2)+1); m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing3 ); m_MaskImage->SetOrigin( origin3 ); m_MaskImage->SetDirection( direction3 ); m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize(); m_OutImageSpacing = m_MaskImage->GetSpacing(); m_ClusteredDirectionsContainer = ContainerType::New(); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing3 ); m_NumDirectionsImage->SetOrigin( origin3 ); m_NumDirectionsImage->SetDirection( direction3 ); m_NumDirectionsImage->SetRegions( imageRegion3 ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, m_MaxNumDirections*3); m_DirectionImage = ItkDirectionImageType::New(); m_DirectionImage->SetSpacing( spacing4 ); m_DirectionImage->SetOrigin( origin4 ); m_DirectionImage->SetDirection( direction4 ); m_DirectionImage->SetRegions( imageRegion4 ); m_DirectionImage->Allocate(); m_DirectionImage->FillBuffer(0.0); - // resample fiber bundle - double minSpacing = 1; - if(m_OutImageSpacing[0]GetDeepCopy(); - - // resample fiber bundle for sufficient voxel coverage - m_FiberBundle->ResampleLinear(minSpacing/10); - // iterate over all fibers vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); m_DirectionsContainer = ContainerType::New(); VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New(); MITK_INFO << "Generating directions from tractogram"; boost::progress_display disp(numFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; vnl_vector_fixed dir; - itk::Point worldPos; vnl_vector v; - float fiberWeight = m_FiberBundle->GetFiberWeight(i); for( int j=0; jGetPoint(j); - worldPos = GetItkPoint(temp); - itk::Index<3> index; - m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); - if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) - continue; - - // get fiber tangent direction at this position - v = GetVnlVector(temp); - dir = GetVnlVector(points->GetPoint(j+1))-v; + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + dir[0] = endVertex[0]-startVertex[0]; + dir[1] = endVertex[1]-startVertex[1]; + dir[2] = endVertex[2]-startVertex[2]; if (dir.is_zero()) continue; dir.normalize(); - // add direction to container - unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); - DirectionContainerType::Pointer dirCont; - if (m_DirectionsContainer->IndexExists(idx)) + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing3, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - peakLengths->ElementAt(idx).push_back(fiberWeight); + if (!m_MaskImage->GetLargestPossibleRegion().IsInside(segment.first) || m_MaskImage->GetPixel(segment.first)==0) + continue; - dirCont = m_DirectionsContainer->GetElement(idx); - if (dirCont.IsNull()) + // add direction to container + unsigned int idx = segment.first[0] + outImageSize[0]*(segment.first[1] + outImageSize[1]*segment.first[2]); + DirectionContainerType::Pointer dirCont; + if (m_DirectionsContainer->IndexExists(idx)) + { + peakLengths->ElementAt(idx).push_back(fiberWeight*segment.second); + + dirCont = m_DirectionsContainer->GetElement(idx); + if (dirCont.IsNull()) + { + dirCont = DirectionContainerType::New(); + dirCont->push_back(dir); + m_DirectionsContainer->InsertElement(idx, dirCont); + } + else + dirCont->push_back(dir); + } + else { dirCont = DirectionContainerType::New(); dirCont->push_back(dir); m_DirectionsContainer->InsertElement(idx, dirCont); + + std::vector< double > lengths; lengths.push_back(fiberWeight*segment.second); + peakLengths->InsertElement(idx, lengths); } - else - dirCont->push_back(dir); } - else - { - dirCont = DirectionContainerType::New(); - dirCont->push_back(dir); - m_DirectionsContainer->InsertElement(idx, dirCont); - std::vector< double > lengths; lengths.push_back(fiberWeight); - peakLengths->InsertElement(idx, lengths); - } } } itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); MITK_INFO << "Clustering directions"; float max_dir_mag = 0; boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); while(!dirIt.IsAtEnd()) { ++disp2; OutputImageType::IndexType idx3 = dirIt.GetIndex(); int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0]; itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; if (!m_DirectionsContainer->IndexExists(idx_lin)) { ++dirIt; continue; } DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin); if (dirCont.IsNull() || dirCont->empty()) { ++dirIt; continue; } DirectionContainerType::Pointer directions; if (m_MaxNumDirections>0) { directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin)); std::sort( directions->begin(), directions->end(), CompareVectorLengths ); } else directions = dirCont; unsigned int numDir = directions->size(); if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections) numDir = m_MaxNumDirections; float voxel_max_mag = 0; for (unsigned int i=0; iat(i); float mag = dir.magnitude(); if (mag>voxel_max_mag) voxel_max_mag = mag; if (mag>max_dir_mag) max_dir_mag = mag; } int count = 0; for (unsigned int i=0; iat(i); count++; float mag = dir.magnitude(); if (m_NormalizationMethod==MAX_VEC_NORM && voxel_max_mag>mitk::eps) dir /= voxel_max_mag; else if (m_NormalizationMethod==SINGLE_VEC_NORM && mag>mitk::eps) dir.normalize(); for (unsigned int j = 0; j<3; j++) { idx4[3] = i*3 + j; m_DirectionImage->SetPixel(idx4, dir[j]); } } dirIt.Set(count); ++dirIt; } if (m_NormalizationMethod==GLOBAL_MAX && max_dir_mag>0) { itk::ImageRegionIterator dirImgIt(m_DirectionImage, m_DirectionImage->GetLargestPossibleRegion()); while(!dirImgIt.IsAtEnd()) { dirImgIt.Set(dirImgIt.Get()/max_dir_mag); ++dirImgIt; } } } template< class PixelType > TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths) { DirectionContainerType::Pointer outDirs = DirectionContainerType::New(); if (inDirs->size()<2) { if (inDirs->size()==1) inDirs->SetElement(0, inDirs->at(0)*lengths.at(0)); return inDirs; } DirectionType oldMean, currentMean; std::vector< int > touched; // initialize touched.resize(inDirs->size(), 0); bool free = true; currentMean = inDirs->at(0); // initialize first seed currentMean.normalize(); double length = lengths.at(0); touched[0] = 1; std::vector< double > newLengths; bool meanChanged = false; double max = 0; while (free) { oldMean.fill(0.0); // start mean-shift clustering double angle = 0; while (fabs(dot_product(currentMean, oldMean))<0.99) { oldMean = currentMean; currentMean.fill(0.0); for (unsigned int i=0; isize(); i++) { angle = dot_product(oldMean, inDirs->at(i)); if (angle>=m_AngularThreshold) { currentMean += inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } } if(!meanChanged) currentMean = oldMean; else currentMean.normalize(); } // found stable mean outDirs->push_back(currentMean); newLengths.push_back(length); if (length>max) max = length; // find next unused seed free = false; for (unsigned int i=0; iat(i); free = true; meanChanged = false; length = lengths.at(i); touched[i] = 1; break; } } if (inDirs->size()==outDirs->size()) { if (max>0) { for (unsigned int i=0; isize(); i++) outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)); } return outDirs; } else return FastClustering(outDirs, newLengths); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h index 7e2ee9198c..e8c9f4a0b7 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h @@ -1,106 +1,103 @@ #ifndef __itkTractsToVectorImageFilter_h__ #define __itkTractsToVectorImageFilter_h__ // MITK #include // ITK #include #include // VTK #include #include #include #include #include namespace itk{ /** * \brief Extracts the voxel-wise main directions of the input fiber bundle. */ template< class PixelType > class TractsToVectorImageFilter : public ImageSource< Image< PixelType, 4 > > { public: enum NormalizationMethods { GLOBAL_MAX, ///< global maximum normalization SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak in the voxel (0-1) }; typedef TractsToVectorImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Vector OutputVectorType; typedef itk::Image OutputImageType; typedef std::vector< OutputImageType::Pointer > OutputImageContainerType; typedef vnl_vector_fixed< double, 3 > DirectionType; typedef VectorContainer< unsigned int, DirectionType > DirectionContainerType; typedef VectorContainer< unsigned int, DirectionContainerType::Pointer > ContainerType; typedef Image< PixelType, 4 > ItkDirectionImageType; typedef itk::Image ItkUcharImgType; typedef itk::Image ItkDoubleImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractsToVectorImageFilter, ImageSource ) itkSetMacro( SizeThreshold, float) itkGetMacro( SizeThreshold, float) itkSetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkGetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of peaks - itkSetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. - itkGetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. itkSetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. itkGetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only process voxels inside mask itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle itkGetMacro( ClusteredDirectionsContainer, ContainerType::Pointer) ///< output directions itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of directions per voxel itkGetMacro( DirectionImage, typename ItkDirectionImageType::Pointer) ///< output directions void GenerateData() override; protected: DirectionContainerType::Pointer FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths); ///< cluster fiber directions vnl_vector_fixed GetVnlVector(double point[3]); itk::Point GetItkPoint(double point[3]); TractsToVectorImageFilter(); ~TractsToVectorImageFilter() override; NormalizationMethods m_NormalizationMethod; ///< normalization method of peaks mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle float m_AngularThreshold; ///< cluster directions that are closer together than the specified threshold float m_Epsilon; ///< epsilon for vector equality check ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed itk::Vector m_OutImageSpacing; ///< spacing of output image ContainerType::Pointer m_DirectionsContainer; ///< container for fiber directions - bool m_UseWorkingCopy; ///< do not modify input fiber bundle but work on copy unsigned long m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept float m_SizeThreshold; // output datastructures typename ItkDirectionImageType::Pointer m_DirectionImage; ContainerType::Pointer m_ClusteredDirectionsContainer; ///< contains direction vectors for each voxel ItkUcharImgType::Pointer m_NumDirectionsImage; ///< shows number of fibers per voxel }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToVectorImageFilter.cpp" #endif #endif // __itkTractsToVectorImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp index 28da14ba91..32b66414a7 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp @@ -1,1742 +1,1732 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() - : m_FiberBundle(nullptr) - , m_StatusText("") + : m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_RandGen->SetSeed(); m_DoubleInterpolator = itk::LinearInterpolateImageFunction< ItkDoubleImgType, float >::New(); m_NullDir.Fill(0); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >:: SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& compartment_images ) { unsigned int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; DoubleDwiType::PixelType nullPix; nullPix.SetSize(compartment_images.at(0)->GetVectorLength()); nullPix.Fill(0.0); auto magnitudeDwiImage = DoubleDwiType::New(); magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); magnitudeDwiImage->Allocate(); magnitudeDwiImage->FillBuffer(nullPix); m_PhaseImage = DoubleDwiType::New(); m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); m_PhaseImage->Allocate(); m_PhaseImage->FillBuffer(nullPix); m_KspaceImage = DoubleDwiType::New(); m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(nullPix); std::vector< unsigned int > spikeVolume; for (unsigned int i=0; iGetIntegerVariate()%(compartment_images.at(0)->GetVectorLength())); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); // calculate coil positions double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m m_CoilPointset = mitk::PointSet::New(); std::vector< itk::Vector > coilPositions; itk::Vector pos; pos.Fill(0.0); pos[1] = -diagonal/2; itk::Vector center; center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; for (int c=0; cInsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; pos.SetVnlVector(rotZ*pos.GetVnlVector()); } PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); unsigned long lastTick = 0; boost::progress_display disp(compartment_images.at(0)->GetVectorLength()*compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); #pragma omp parallel for for (int g=0; g<(int)compartment_images.at(0)->GetVectorLength(); g++) { if (this->GetAbortGenerateData()) continue; std::vector< unsigned int > spikeSlice; #pragma omp critical while (!spikeVolume.empty() && (int)spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< Float2DImageType::Pointer > compartment_slices; std::vector< float > t2Vector; std::vector< float > t1Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { Float2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, compartment_images.at(i)->GetPixel(index3D)[g]); } compartment_slices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils; if (this->GetAbortGenerateData()) continue; for (int c=0; c::New(); idft->SetCompartmentImages(compartment_slices); idft->SetT2(t2Vector); idft->SetT1(t1Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetParameters(&m_Parameters); idft->SetZ((float)z-(float)( compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2) -compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0); idft->SetZidx(z); idft->SetCoilPosition(coilPositions.at(c)); - idft->SetFiberBundle(m_FiberBundleWorkingCopy); + idft->SetFiberBundle(m_FiberBundle); idft->SetTranslation(m_Translations.at(g)); idft->SetRotation(m_Rotations.at(g)); idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); if (c==spikeCoil) idft->SetSpikesPerSlice(numSpikes); idft->Update(); #pragma omp critical if (c==spikeCoil && numSpikes>0) { m_SpikeLog += "Volume " + boost::lexical_cast(g) + " Coil " + boost::lexical_cast(c) + "\n"; m_SpikeLog += idft->GetSpikeLog(); } Complex2DImageType::Pointer fSlice; fSlice = idft->GetOutput(); // fourier transform slice Complex2DImageType::Pointer newSlice; auto dft = itk::DftImageFilter< Float2DImageType::PixelType >::New(); dft->SetInput(fSlice); dft->SetParameters(m_Parameters); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; Complex2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; Complex2DImageType::PixelType cPix = newSlice->GetPixel(index2D); double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); double phase = 0; if (cPix.real()!=0) phase = atan( cPix.imag()/cPix.real() ); DoubleDwiType::PixelType real_pix = m_OutputImagesReal.at(c)->GetPixel(index3D); real_pix[g] = cPix.real(); m_OutputImagesReal.at(c)->SetPixel(index3D, real_pix); DoubleDwiType::PixelType imag_pix = m_OutputImagesImag.at(c)->GetPixel(index3D); imag_pix[g] = cPix.imag(); m_OutputImagesImag.at(c)->SetPixel(index3D, imag_pix); DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { dwiPix[g] += magn*magn; phasePix[g] += phase*phase; } else { dwiPix[g] = magn; phasePix[g] = phase; } //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, dwiPix); m_PhaseImage->SetPixel(index3D, phasePix); // k-space image if (g==0) { DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); m_KspaceImage->SetPixel(index3D, kspacePix); } } } } if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { for (int y=0; y(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(1)); y++) for (int x=0; x(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(0)); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, magPix); m_PhaseImage->SetPixel(index3D, phasePix); } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; } } PrintToLog("\n", false); return magnitudeDwiImage; } template< class PixelType > TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >:: NormalizeInsideMask(ItkDoubleImgType::Pointer image) { double max = itk::NumericTraits< double >::min(); double min = itk::NumericTraits< double >::max(); itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) { it.Set(0.0); ++it; continue; } if (it.Get()>max) max = it.Get(); if (it.Get()::New(); scaler->SetInput(image); scaler->SetShift(-min); scaler->SetScale(1.0/(max-min)); scaler->Update(); return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { m_UseRelativeNonFiberVolumeFractions = false; // check for fiber volume fraction maps unsigned int fibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1)); fibVolImages++; } } // check for non-fiber volume fraction maps unsigned int nonfibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1)); nonfibVolImages++; } } // not all fiber compartments are using volume fraction maps // --> non-fiber volume fractions are assumed to be relative to the // non-fiber volume and not absolute voxel-volume fractions. // this means if two non-fiber compartments are used but only one of them // has an associated volume fraction map, the repesctive other volume fraction map // can be determined as inverse (1-val) of the present volume fraction map- if ( fibVolImages::New(); inverter->SetMaximum(1.0); if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); } else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); } else { itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!" " Did you use two non fiber compartments but only one volume fraction image?" " Then it should work and this error is really strange."); } m_UseRelativeNonFiberVolumeFractions = true; nonfibVolImages++; } // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); if (fibVolImages0) { PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values."); m_UseRelativeNonFiberVolumeFractions = true; // itk::ImageFileWriter::Pointer wr = itk::ImageFileWriter::New(); // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); // wr->SetFileName("/local/volumefraction.nrrd"); // wr->Update(); } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (std::size_t i=0; iSetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { m_Rotations.clear(); m_Translations.clear(); m_MotionLog = ""; m_SpikeLog = ""; // initialize output dwi image m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1) *m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1) -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); // images containing real and imaginary part of the dMRI signal for each coil m_OutputImagesReal.clear(); m_OutputImagesImag.clear(); for (int i=0; iSetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageReal->SetOrigin( shiftedOrigin ); outputImageReal->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageReal->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageReal->Allocate(); outputImageReal->FillBuffer(temp); m_OutputImagesReal.push_back(outputImageReal); typename DoubleDwiType::Pointer outputImageImag = DoubleDwiType::New(); outputImageImag->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageImag->SetOrigin( shiftedOrigin ); outputImageImag->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageImag->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageImag->Allocate(); outputImageImag->FillBuffer(temp); m_OutputImagesImag.push_back(outputImageImag); } // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull()) { m_CompartmentImages.clear(); m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; PrintToLog("Simulating acquisition for input diffusion-weighted image.", false); auto caster = itk::CastImageFilter< OutputImageType, DoubleDwiType >::New(); caster->SetInput(m_InputImage); caster->Update(); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false); auto resampler = itk::ResampleDwiImageFilter< double >::New(); resampler->SetInput(caster->GetOutput()); itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = upsampling; samplingFactor[1] = upsampling; samplingFactor[2] = 1; resampler->SetSamplingFactor(samplingFactor); resampler->SetInterpolation(itk::ResampleDwiImageFilter< double >::Interpolate_WindowedSinc); resampler->Update(); m_CompartmentImages.push_back(resampler->GetOutput()); } else m_CompartmentImages.push_back(caster->GetOutput()); for (unsigned int g=0; g::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) { auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default PrintToLog("No tissue mask set", false); m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) { itkExceptionMacro("Mask image and specified DWI geometry are not matching!"); } PrintToLog("Using tissue mask", false); } if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { PrintToLog("Random motion artifacts:", false); PrintToLog("Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } else { PrintToLog("Linear motion artifacts:", false); PrintToLog("Maximum rotation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } } if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() ) { // no motion in first volume m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); // motion in all other volumes while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true); } } // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; DoubleVectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); auto upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { - // resample fiber bundle for sufficient voxel coverage - PrintToLog("Resampling fibers ..."); - m_SegmentVolume = 0.0001; - float minSpacing = 1; - if( m_WorkingSpacing[0]GetDeepCopy(); - double volumeAccuracy = 10; - m_FiberBundleWorkingCopy->ResampleLinear(minSpacing/volumeAccuracy); m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; auto caster = itk::CastImageFilter< itk::Image, itk::Image >::New(); caster->SetInput(m_TransformedMaskImage); caster->Update(); - vtkSmartPointer weights = m_FiberBundleWorkingCopy->GetFiberWeights(); + vtkSmartPointer weights = m_FiberBundle->GetFiberWeights(); float mean_weight = 0; for (int i=0; iGetSize(); i++) mean_weight += weights->GetValue(i); mean_weight /= weights->GetSize(); if (mean_weight>0.000001) for (int i=0; iGetSize(); i++) - m_FiberBundleWorkingCopy->SetFiberWeight(i, weights->GetValue(i)/mean_weight); + m_FiberBundle->SetFiberWeight(i, weights->GetValue(i)/mean_weight); else PrintToLog("\nWarning: streamlines have VERY low weights. Average weight: " + boost::lexical_cast(mean_weight) + ". Possible source of calculation errors.", false, true, true); auto density_calculator = itk::TractDensityImageFilter< itk::Image >::New(); - density_calculator->SetFiberBundle(m_FiberBundleWorkingCopy); + density_calculator->SetFiberBundle(m_FiberBundle); density_calculator->SetInputImage(caster->GetOutput()); density_calculator->SetBinaryOutput(false); density_calculator->SetUseImageGeometry(true); - density_calculator->SetDoFiberResampling(false); density_calculator->SetOutputAbsoluteValues(true); - density_calculator->SetWorkOnFiberCopy(false); density_calculator->Update(); float max_density = density_calculator->GetMaxDensity(); + float voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; if (m_mmRadius>0) { - m_SegmentVolume = itk::Math::pi*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; std::stringstream stream; - stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; + stream << std::fixed << setprecision(2) << itk::Math::pi*m_mmRadius*m_mmRadius*max_density; std::string s = stream.str(); PrintToLog("\nMax. fiber volume: " + s + "mm².", false, true, true); + + { + float full_radius = 1000*std::sqrt(voxel_volume/(max_density*itk::Math::pi)); + std::stringstream stream; + stream << std::fixed << setprecision(2) << full_radius; + std::string s = stream.str(); + PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); + } } else { + m_mmRadius = std::sqrt(voxel_volume/(max_density*itk::Math::pi)); std::stringstream stream; - stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; + stream << std::fixed << setprecision(2) << m_mmRadius*1000; std::string s = stream.str(); - PrintToLog("\nMax. fiber volume: " + s + "mm² (before rescaling to voxel volume).", false, true, true); + PrintToLog("\nSetting fiber radius to " + s + "µm to obtain full voxel.", false, true, true); } - float voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; - float new_seg_vol = voxel_volume/max_density; - float new_fib_radius = 1000*std::sqrt(new_seg_vol*volumeAccuracy/(minSpacing*itk::Math::pi)); - std::stringstream stream; - stream << std::fixed << setprecision(2) << new_fib_radius; - std::string s = stream.str(); - PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy - m_FiberBundleTransformed = m_FiberBundleWorkingCopy; + m_FiberBundleTransformed = m_FiberBundle; } template< class PixelType > bool TractsToDWIImageFilter< PixelType >::PrepareLogFile() { assert( ! m_Logfile.is_open() ); std::string filePath; std::string fileName; // Get directory name: if (m_Parameters.m_Misc.m_OutputPath.size() > 0) { filePath = m_Parameters.m_Misc.m_OutputPath; if( *(--(filePath.cend())) != '/') { filePath.push_back('/'); } } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // check if directory exists, else use /tmp/: if( itksys::SystemTools::FileIsDirectory( filePath ) ) { while( *(--(filePath.cend())) == '/') { filePath.pop_back(); } filePath = filePath + '/'; } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // Get file name: if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() ) { fileName = m_Parameters.m_Misc.m_ResultNode->GetName(); } else { fileName = ""; } if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() ) { fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName; } else { fileName = "fiberfox"; } // check if file already exists and DO NOT overwrite existing files: std::string NameTest = fileName; int c = 0; while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" ) && c <= std::numeric_limits::max() ) { fileName = NameTest + "_" + boost::lexical_cast(c); ++c; } try { m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() ); } catch (const std::ios_base::failure &fail) { MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what() << " while trying to open file" << filePath << '/' << fileName << ".log"; return false; } if ( m_Logfile.is_open() ) { PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false ); return true; } else { m_StatusText += "Logfile could not be opened!\n"; MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!"; return false; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { // prepare logfile if ( ! PrepareLogFile() ) { this->SetAbortGenerateData( true ); return; } m_TimeProbe.Start(); // check input data if (m_FiberBundle.IsNull() && m_InputImage.IsNull()) itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is nullptr!"); if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one non-fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // no partial volume? remove all but first fiber compartment while (m_Parameters.m_FiberModelList.size()>1) m_Parameters.m_FiberModelList.pop_back(); // int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex(); // if (baselineIndex<0) { itkExceptionMacro("No baseline index found!"); } if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); InitializeData(); if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation { CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); PrintToLog("\n", false, false); PrintToLog("Generating " + boost::lexical_cast(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal."); std::vector< int > bVals = m_Parameters.m_SignalGen.GetBvalues(); PrintToLog("b-values: ", false, false, true); for (auto v : bVals) PrintToLog(boost::lexical_cast(v) + " ", false, false, true); PrintToLog("\n", false, false, true); PrintToLog("\n", false, false, true); - int numFibers = m_FiberBundleWorkingCopy->GetNumFibers(); + int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes()); if (m_FiberBundle->GetMeanFiberLength()<5.0) omp_set_num_threads(2); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); for (unsigned int g=0; gSetSeed(signalModelSeed); for (std::size_t i=0; iSetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ auto intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; if (this->GetAbortGenerateData()) continue; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) { #pragma omp parallel for for( int i=0; iGetAbortGenerateData()) continue; float fiberWeight = m_FiberBundleTransformed->GetFiberWeight(i); int numPoints = -1; std::vector< itk::Vector > points_copy; #pragma omp critical { vtkCell* cell = fiberPolyData->GetCell(i); numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j))); } if (numPoints<2) continue; - for( int j=0; jGetAbortGenerateData()) { j=numPoints; continue; } - itk::Point vertex = points_copy.at(j); itk::Vector v = points_copy.at(j); - itk::Vector dir(3); - if (j dir = points_copy.at(j+1)-v; if ( dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2] ) continue; + dir.Normalize(); - itk::Index<3> idx; - itk::ContinuousIndex contIndex; - m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx); - m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); + itk::Point startVertex = points_copy.at(j); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_TransformedMaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); - if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0) - continue; - dir.Normalize(); + itk::Point endVertex = points_copy.at(j+1); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_TransformedMaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(m_WorkingSpacing, startIndex, endIndex, startIndexCont, endIndexCont); - // generate signal for each fiber compartment - for (int k=0; k, double > seg : segments) { - DoubleDwiType::PixelType pix = m_CompartmentImages.at(k)->GetPixel(idx); - pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir); - m_CompartmentImages.at(k)->SetPixel(idx, pix); - } + if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(seg.first) || m_TransformedMaskImage->GetPixel(seg.first)<=0) + continue; - // update fiber volume image - double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight; - intraAxonalVolumeImage->SetPixel(idx, vol); + // generate signal for each fiber compartment + for (int k=0; kGetPixel(seg.first); + + float seg_volume = seg.second*fiberWeight*itk::Math::pi*m_mmRadius*m_mmRadius; + + pix[g] += seg_volume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir); + m_CompartmentImages.at(k)->SetPixel(seg.first, pix); - // we assume that the first volume is always unweighted! - if (vol>maxVolume) { maxVolume = vol; } + if (k==0) + { + // update fiber volume image + double vol = intraAxonalVolumeImage->GetPixel(seg.first) + seg_volume; + intraAxonalVolumeImage->SetPixel(seg.first, vol); + if (vol>maxVolume) { maxVolume = vol; } + } + } + + } } #pragma omp critical { // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); ++tick) PrintToLog("*", false, false, false); lastTick = newTick; } } } // axon radius not manually defined --> set fullest voxel (maxVolume) to full fiber voxel double density_correctiony_global = 1.0; if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001) density_correctiony_global = m_VoxelVolume/maxVolume; // generate non-fiber signal ImageRegionIterator it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // get non-transformed point (remove headmotion tranformation) // this point lives in the volume fraction image space itk::Point volume_fraction_point; if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] ) volume_fraction_point = GetMovedPoint(index, false); else m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, volume_fraction_point); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { if (iAxVolume>0.0001) // scale fiber compartment to voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); } else { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] = 0; m_CompartmentImages.at(0)->SetPixel(index, pix); SimulateExtraAxonalSignal(index, volume_fraction_point, 0, g); } } else { // manually defined axon radius and voxel overflow --> rescale to voxel volume if ( m_Parameters.m_SignalGen.m_AxonRadius>=0.0001 && iAxVolume>m_VoxelVolume ) { for (int i=0; iGetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } iAxVolume = m_VoxelVolume; } // if volume fraction image is set use it, otherwise use global scaling factor double density_correction_voxel = density_correctiony_global; if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001 ) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()); double volume_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (volume_fraction<0) mitkThrow() << "Volume fraction image (index 1) contains negative values (intra-axonal compartment)!"; density_correction_voxel = m_VoxelVolume*volume_fraction/iAxVolume; // remove iAxVolume sclaing and scale to volume_fraction } else if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr) density_correction_voxel = 0.0; // adjust intra-axonal compartment volume by density correction factor DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= density_correction_voxel; m_CompartmentImages.at(0)->SetPixel(index, pix); // normalize remaining fiber volume fractions (they are rescaled in SimulateExtraAxonalSignal) if (iAxVolume>0.0001) { for (int i=1; iGetPixel(index); pix[g] /= iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { for (int i=1; iGetPixel(index); pix[g] = 0; m_CompartmentImages.at(i)->SetPixel(index, pix); } } iAxVolume = density_correction_voxel*iAxVolume; // new intra-axonal volume = old intra-axonal volume * correction factor // simulate other compartments SimulateExtraAxonalSignal(index, volume_fraction_point, iAxVolume, g); } } ++it3; } } PrintToLog("\n", false); } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } DoubleDwiType::Pointer doubleOutImage; double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { PrintToLog("\n", false, false); PrintToLog("Simulating k-space acquisition using " +boost::lexical_cast(m_Parameters.m_SignalGen.m_NumberOfCoils) +" coil(s)"); switch (m_Parameters.m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: { PrintToLog("Acquisition type: single shot EPI", false); break; } case SignalGenerationParameters::SpinEcho: { PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false); break; } default: { PrintToLog("Acquisition type: single shot EPI", false); break; } } if (m_Parameters.m_SignalGen.m_NoiseVariance>0 && m_Parameters.m_Misc.m_CheckAddNoiseBox) PrintToLog("Simulating complex Gaussian noise", false); if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) PrintToLog("Simulating signal relaxation", false); if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) PrintToLog("Simulating distortions", false); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) PrintToLog("Simulating ringing artifacts", false); if (m_Parameters.m_SignalGen.m_EddyStrength>0) PrintToLog("Simulating eddy currents", false); if (m_Parameters.m_SignalGen.m_Spikes>0) PrintToLog("Simulating spikes", false); if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0) PrintToLog("Simulating aliasing artifacts", false); if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0) PrintToLog("Simulating ghosts", false); doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); signalScale = 1; // already scaled in SimulateKspaceAcquisition() } else // don't do k-space stuff, just sum compartments { PrintToLog("Summing compartments"); doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } PrintToLog("Finalizing image"); if (signalScale>1) PrintToLog(" Scaling signal", false); if (m_Parameters.m_NoiseModel) PrintToLog(" Adding noise", false); unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); int lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*signalScale; if (m_Parameters.m_NoiseModel) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]SetNthOutput(0, m_OutputImage); PrintToLog("\n", false); PrintToLog("Finished simulation"); m_TimeProbe.Stop(); if (m_Parameters.m_SignalGen.m_DoAddMotion) { PrintToLog("\nHead motion log:", false); PrintToLog(m_MotionLog, false, false); } if (m_Parameters.m_SignalGen.m_Spikes>0) { PrintToLog("\nSpike log:", false); PrintToLog(m_SpikeLog, false, false); } if (m_Logfile.is_open()) m_Logfile.close(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::PrintToLog(std::string m, bool addTime, bool linebreak, bool stdOut) { // timestamp if (addTime) { m_Logfile << this->GetTime() << " > "; m_StatusText += this->GetTime() + " > "; if (stdOut) std::cout << this->GetTime() << " > "; } // message if (m_Logfile.is_open()) m_Logfile << m; m_StatusText += m; if (stdOut) std::cout << m; // new line if (linebreak) { if (m_Logfile.is_open()) m_Logfile << "\n"; m_StatusText += "\n"; if (stdOut) std::cout << "\n"; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { // is motion artifact enabled? // is the current volume g affected by motion? if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] && g(m_Parameters.m_SignalGen.GetNumVolumes()) ) { if ( m_Parameters.m_SignalGen.m_DoRandomizeMotion ) { // either undo last transform or work on fresh copy of untransformed fibers - m_FiberBundleTransformed = m_FiberBundleWorkingCopy->GetDeepCopy(); + m_FiberBundleTransformed = m_FiberBundle->GetDeepCopy(); m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2) -m_Parameters.m_SignalGen.m_Rotation[0]; m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2) -m_Parameters.m_SignalGen.m_Rotation[1]; m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2) -m_Parameters.m_SignalGen.m_Rotation[2]; m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2) -m_Parameters.m_SignalGen.m_Translation[0]; m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2) -m_Parameters.m_SignalGen.m_Translation[1]; m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2) -m_Parameters.m_SignalGen.m_Translation[2]; } else { m_Rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; m_Translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes; m_MotionCounter++; } // move mask image if (m_MaskImageSet) { ImageRegionIterator maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); m_TransformedMaskImage->TransformPhysicalPointToIndex(GetMovedPoint(index, true), index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) m_TransformedMaskImage->SetPixel(index,100); ++maskIt; } } if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } else { m_Rotations.push_back(m_Rotation*m_MotionCounter); m_Translations.push_back(m_Translation*m_MotionCounter); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[2]*m_MotionCounter) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[2]*m_MotionCounter) + "\n"; } m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); } else { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetMovedPoint(itk::Index<3>& index, bool forward) { itk::Point transformed_point; if (forward) { m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0],m_Rotation[1],m_Rotation[2], m_Translation[0],m_Translation[1],m_Translation[2]); } else { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0]*m_MotionCounter,m_Rotation[1]*m_MotionCounter,m_Rotation[2]*m_MotionCounter, m_Translation[0]*m_MotionCounter,m_Translation[1]*m_MotionCounter,m_Translation[2]*m_MotionCounter); } } else { m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0], -m_Rotation[1], -m_Rotation[2], -m_Translation[0], -m_Translation[1], -m_Translation[2] ); } else { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0]*m_MotionCounter, -m_Rotation[1]*m_MotionCounter, -m_Rotation[2]*m_MotionCounter, -m_Translation[0]*m_MotionCounter, -m_Translation[1]*m_MotionCounter, -m_Translation[2]*m_MotionCounter ); } } return transformed_point; } template< class PixelType > void TractsToDWIImageFilter< PixelType >:: SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point& volume_fraction_point, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { // simulate signal for largest non-fiber compartment int max_compartment_index = 0; double max_fraction = 0; if (numNonFiberCompartments>1) { for (int i=0; iSetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); double compartment_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (compartment_fraction<0) mitkThrow() << "Volume fraction image (index " << i << ") contains values less than zero!"; if (compartment_fraction>max_fraction) { max_fraction = compartment_fraction; max_compartment_index = i; } } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(max_compartment_index+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[max_compartment_index]->SimulateMeasurement(g, m_NullDir)*m_VoxelVolume; doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(max_compartment_index+numFiberCompartments)->SetPixel(index, 1); } else { std::vector< double > fractions; if (g==0) m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { if (extraAxonalVolume<-0.001) MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume! " << m_VoxelVolume << "<" << intraAxonalVolume; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double nonFiberVolume = extraAxonalVolume - interAxonalVolume; // rest of compartment if (nonFiberVolume<0) { if (nonFiberVolume<-0.001) MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; nonFiberVolume = 0; interAxonalVolume = extraAxonalVolume; } double compartmentSum = intraAxonalVolume; fractions.push_back(intraAxonalVolume/m_VoxelVolume); // rescale extra-axonal fiber signal for (int i=1; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()); interAxonalVolume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (interAxonalVolume<0) mitkThrow() << "Volume fraction image (index " << i+1 << ") contains negative values!"; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] *= interAxonalVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); compartmentSum += interAxonalVolume; fractions.push_back(interAxonalVolume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, interAxonalVolume/m_VoxelVolume); } for (int i=0; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); volume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (volume<0) mitkThrow() << "Volume fraction image (index " << numFiberCompartments+i+1 << ") contains negative values (non-fiber compartment)!"; if (m_UseRelativeNonFiberVolumeFractions) volume *= nonFiberVolume/m_VoxelVolume; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i+numFiberCompartments)->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g, m_NullDir)*volume; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); compartmentSum += volume; fractions.push_back(volume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, volume/m_VoxelVolume); } if (compartmentSum/m_VoxelVolume>1.05) { MITK_ERROR << "Compartments do not sum to 1 in voxel " << index << " (" << compartmentSum/m_VoxelVolume << ")"; for (auto val : fractions) MITK_ERROR << val; } } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h index ce6fc47372..3d4af97ac3 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h @@ -1,178 +1,177 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ #include #include #include #include #include #include #include #include #include #include namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class PixelType > class TractsToDWIImageFilter : public ImageSource< itk::VectorImage< PixelType, 3 > > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< itk::VectorImage< PixelType, 3 > > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename Superclass::OutputImageType OutputImageType; typedef itk::Image ItkDoubleImgType4D; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundle::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef itk::Matrix MatrixType; typedef itk::Image< float, 2 > Float2DImageType; typedef itk::Image< vcl_complex< float >, 2 > Complex2DImageType; typedef itk::Vector< double,3> DoubleVectorType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageSource ) /** Input */ itkSetMacro( FiberBundle, FiberBundleType ) ///< Input fiber bundle itkSetMacro( InputImage, typename OutputImageType::Pointer ) ///< Input diffusion-weighted image. If no fiber bundle is set, then the acquisition is simulated for this image without a new diffusion simulation. itkSetMacro( UseConstantRandSeed, bool ) ///< Seed for random generator. void SetParameters( FiberfoxParameters param ) ///< Simulation parameters. { m_Parameters = param; } /** Output */ FiberfoxParameters GetParameters(){ return m_Parameters; } std::vector< ItkDoubleImgType::Pointer > GetVolumeFractions() ///< one double image for each compartment containing the corresponding volume fraction per voxel { return m_VolumeFractions; } mitk::LevelWindow GetLevelWindow() ///< Level window is determined from the output image { return m_LevelWindow; } itkGetMacro( StatusText, std::string ) itkGetMacro( PhaseImage, DoubleDwiType::Pointer ) itkGetMacro( KspaceImage, DoubleDwiType::Pointer ) itkGetMacro( CoilPointset, mitk::PointSet::Pointer ) void GenerateData() override; std::vector GetOutputImagesReal() const { return m_OutputImagesReal; } std::vector GetOutputImagesImag() const { return m_OutputImagesImag; } protected: TractsToDWIImageFilter(); ~TractsToDWIImageFilter() override; itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); double RoundToNearest(double num); std::string GetTime(); bool PrepareLogFile(); /** Prepares the log file and returns true if successful or false if failed. */ void PrintToLog(std::string m, bool addTime=true, bool linebreak=true, bool stdOut=true); /** Transform generated image compartment by compartment, channel by channel and slice by slice using DFT and add k-space artifacts/effects. */ DoubleDwiType::Pointer SimulateKspaceAcquisition(std::vector< DoubleDwiType::Pointer >& images); /** Generate signal of non-fiber compartments. */ void SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point& volume_fraction_point, double intraAxonalVolume, int g); /** Move fibers to simulate headmotion */ void SimulateMotion(int g=-1); void CheckVolumeFractionImages(); ItkDoubleImgType::Pointer NormalizeInsideMask(ItkDoubleImgType::Pointer image); void InitializeData(); void InitializeFiberData(); itk::Point GetMovedPoint(itk::Index<3>& index, bool forward); // input mitk::FiberfoxParameters m_Parameters; FiberBundleType m_FiberBundle; typename OutputImageType::Pointer m_InputImage; // output typename OutputImageType::Pointer m_OutputImage; typename DoubleDwiType::Pointer m_PhaseImage; typename DoubleDwiType::Pointer m_KspaceImage; std::vector < typename DoubleDwiType::Pointer > m_OutputImagesReal; std::vector < typename DoubleDwiType::Pointer > m_OutputImagesImag; mitk::LevelWindow m_LevelWindow; std::vector< ItkDoubleImgType::Pointer > m_VolumeFractions; std::string m_StatusText; // MISC itk::TimeProbe m_TimeProbe; bool m_UseConstantRandSeed; bool m_MaskImageSet; ofstream m_Logfile; std::string m_MotionLog; std::string m_SpikeLog; // signal generation - FiberBundleType m_FiberBundleWorkingCopy; ///< we work on an upsampled version of the input bundle FiberBundleType m_FiberBundleTransformed; ///< transformed bundle simulating headmotion itk::Vector m_WorkingSpacing; itk::Point m_WorkingOrigin; ImageRegion<3> m_WorkingImageRegion; double m_VoxelVolume; std::vector< DoubleDwiType::Pointer > m_CompartmentImages; ItkUcharImgType::Pointer m_TransformedMaskImage; ///< copy of mask image (changes for each motion step) ItkUcharImgType::Pointer m_UpsampledMaskImage; ///< helper image for motion simulation DoubleVectorType m_Rotation; DoubleVectorType m_Translation; std::vector< DoubleVectorType > m_Rotations; /// m_Translations; ///::Pointer m_DoubleInterpolator; itk::Vector m_NullDir; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToDWIImageFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp index 39a34e8d82..bc3ff77cdb 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp @@ -1,2643 +1,2653 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkFiberBundle.h" #include #include #include #include "mitkImagePixelReadAccessor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs"; mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData ) : m_NumFibers(0) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != nullptr) m_FiberPolyData = fiberPolyData; else { this->m_FiberPolyData->SetPoints(vtkSmartPointer::New()); this->m_FiberPolyData->SetLines(vtkSmartPointer::New()); } this->UpdateFiberGeometry(); this->GenerateFiberIds(); this->ColorFibersByOrientation(); } mitk::FiberBundle::~FiberBundle() { } mitk::FiberBundle::Pointer mitk::FiberBundle::GetDeepCopy() { mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(m_FiberPolyData); newFib->SetFiberColors(this->m_FiberColors); newFib->SetFiberWeights(this->m_FiberWeights); return newFib; } vtkSmartPointer mitk::FiberBundle::GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights) { vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); weights->SetNumberOfValues(fiberIds.size()); int counter = 0; auto finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); } weights->InsertValue(counter, this->GetFiberWeight(*finIt)); newLineSet->InsertNextCell(newFiber); ++finIt; ++counter; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); int num_weights = this->GetNumFibers(); for (auto fib : fibs) num_weights += fib->GetNumFibers(); weights->SetNumberOfValues(num_weights); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } for (auto fib : fibs) { // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(this->GetNumFibers()+fib->GetNumFibers()); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // Only retain fibers with a weight larger than the specified threshold mitk::FiberBundle::Pointer mitk::FiberBundle::FilterByWeights(float weight_thr, bool invert) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector weights; for (int i=0; iGetNumFibers(); i++) { if ( (invert && this->GetFiberWeight(i)>weight_thr) || (!invert && this->GetFiberWeight(i)<=weight_thr)) continue; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); weights.push_back(this->GetFiberWeight(i)); } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); for (unsigned int i=0; iSetFiberWeight(i, weights.at(i)); return newFib; } // Only retain a subsample of the fibers mitk::FiberBundle::Pointer mitk::FiberBundle::SubsampleFibers(float factor) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); int new_num_fibs = this->GetNumFibers()*factor; MITK_INFO << "Subsampling fibers with factor " << factor << "(" << new_num_fibs << "/" << this->GetNumFibers() << ")"; // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(new_num_fibs); std::vector< int > ids; for (int i=0; iGetNumFibers(); i++) ids.push_back(i); std::random_shuffle(ids.begin(), ids.end()); unsigned int counter = 0; for (int i=0; iGetCell(ids.at(i)); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(ids.at(i))); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // subtract two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::SubtractBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector< std::vector< itk::Point > > points1; for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points1.push_back( {start, end} ); } std::vector< std::vector< itk::Point > > points2; for( int i=0; iGetNumFibers(); i++ ) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points2.push_back( {start, end} ); } // int progress = 0; std::vector< int > ids; #pragma omp parallel for for (int i=0; i<(int)points1.size(); i++) { //#pragma omp critical // { // progress++; // std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; // cout.flush(); // } bool match = false; for (unsigned int j=0; jGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(points->GetPoint(j)); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if(vNewLines->GetNumberOfCells()==0) return mitk::FiberBundle::New(); // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle return mitk::FiberBundle::New(vNewPolyData); } itk::Point mitk::FiberBundle::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set PolyData (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundle::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == nullptr) this->m_FiberPolyData = vtkSmartPointer::New(); else m_FiberPolyData->DeepCopy(fiberPD); m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); GenerateFiberIds(); ColorFibersByOrientation(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundle::GetFiberPolyData() const { return m_FiberPolyData; } void mitk::FiberBundle::ColorFibersByLength(bool opacity, bool normalize) { if (m_MaxFiberLength<=0) return; int numOfPoints = this->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); float l = m_FiberLengths.at(i)/m_MaxFiberLength; if (!normalize) { l = m_FiberLengths.at(i)/255.0; if (l > 1.0) l = 1.0; } for (int j=0; jGetColor(1.0 - l, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * l); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByOrientation() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also PolyData needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= vtkPoints* extrPoints = nullptr; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=nullptr) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } m_FiberColors->InsertTypedTuple(idList[i], rgba); } } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByCurvature(bool, bool normalize) { double window = 5; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); std::vector< double > values; double min = 1; double max = 0; MITK_INFO << "Coloring fibers by curvature"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures for (int j=0; j > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0); while(dist1) { double p1[3]; points->GetPoint(c-1, p1); double p2[3]; points->GetPoint(c, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); meanV += v; c--; } c = j; dist = 0; while(distGetPoint(c, p1); double p2[3]; points->GetPoint(c+1, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); meanV += v; c++; } meanV.normalize(); double dev = 0; for (unsigned int c=0; c1.0) angle = 1.0; if (angle<-1.0) angle = -1.0; dev += acos(angle)*180/itk::Math::pi; } if (vectors.size()>0) dev /= vectors.size(); dev = 1.0-dev/180.0; values.push_back(dev); if (devmax) max = dev; } } unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); for (int j=0; j1) dev = 1; lookupTable->GetColor(dev, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberOpacity(vtkDoubleArray* FAValArray) { for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; m_FiberColors->SetComponent(i,3, (unsigned char) faValue ); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ResetFiberOpacity() { for(long i=0; iGetNumberOfTuples(); i++) m_FiberColors->SetComponent(i,3, 255.0 ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByScalarMap(mitk::Image::Pointer FAimage, bool opacity, bool normalize) { mitkPixelTypeMultiplex3( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity, normalize ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } template void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); unsigned char rgba[4] = {0,0,0,0}; vtkPoints* pointSet = m_FiberPolyData->GetPoints(); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); double min = 9999999; double max = -9999999; for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (pixelValue>max) max = pixelValue; if (pixelValueGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (normalize) pixelValue = (pixelValue-min)/(max-min); else if (pixelValue>1) pixelValue = 1; double color[3]; lookupTable->GetColor(1-pixelValue, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * pixelValue); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByFiberWeights(bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); unsigned char rgba[4] = {0,0,0,0}; unsigned int counter = 0; float max = -999999; float min = 999999; for (int i=0; iGetFiberWeight(i); if (weight>max) max = weight; if (weightGetCell(i); int numPoints = cell->GetNumberOfPoints(); double weight = this->GetFiberWeight(i); for (int j=0; j1) v = 1; double color[3]; lookupTable->GetColor(1-v, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * v); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(counter, rgba); counter++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberColors(float r, float g, float b, float alpha) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); unsigned char rgba[4] = {0,0,0,0}; for(long i=0; iGetNumberOfPoints(); ++i) { rgba[0] = (unsigned char) r; rgba[1] = (unsigned char) g; rgba[2] = (unsigned char) b; rgba[3] = (unsigned char) alpha; m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::GenerateFiberIds() { if (m_FiberPolyData == nullptr) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInputData(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); } -float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask, bool do_resampling) +float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask) { vtkSmartPointer PolyData = m_FiberPolyData; - mitk::FiberBundle::Pointer fibCopy = this; - if (do_resampling) - { - float minSpacing = 1; - if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) - minSpacing = mask->GetSpacing()[0]; - else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) - minSpacing = mask->GetSpacing()[1]; - else - minSpacing = mask->GetSpacing()[2]; - - fibCopy = this->GetDeepCopy(); - fibCopy->ResampleLinear(minSpacing/5); - PolyData = fibCopy->GetFiberPolyData(); - } MITK_INFO << "Calculating overlap"; - int inside = 0; - int outside = 0; + auto spacing = mask->GetSpacing(); boost::progress_display disp(m_NumFibers); + double length_sum = 0; + double in_mask_length = 0; for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); - for (int j=0; jGetPoint(j); - itk::Point itkP; - itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; - itk::Index<3> idx; - mask->TransformPhysicalPointToIndex(itkP, idx); - - if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 ) - inside++; - else - outside++; + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + mask->TransformPhysicalPointToIndex(startVertex, startIndex); + mask->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + mask->TransformPhysicalPointToIndex(endVertex, endIndex); + mask->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (endVertex[i]-startVertex[i])*spacing[i]; + length_sum += std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) + { + if ( mask->GetLargestPossibleRegion().IsInside(segment.first) && mask->GetPixel(segment.first) != 0 ) + in_mask_length += segment.second; + } } } - if (inside+outside==0) - outside = 1; - return (float)inside/(inside+outside); + if (length_sum==0) + { + MITK_INFO << "Fiber length sum is zero!"; + return length_sum; + } + return in_mask_length/length_sum; } mitk::FiberBundle::Pointer mitk::FiberBundle::RemoveFibersOutside(ItkUcharImgType* mask, bool invert) { - float minSpacing = 1; - if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) - minSpacing = mask->GetSpacing()[0]; - else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) - minSpacing = mask->GetSpacing()[1]; - else - minSpacing = mask->GetSpacing()[2]; - - mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy(); - fibCopy->ResampleLinear(minSpacing/10); - vtkSmartPointer PolyData =fibCopy->GetFiberPolyData(); - vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); - vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); - newFiberWeights->SetName("FIBER_WEIGHTS"); - newFiberWeights->SetNumberOfValues(m_NumFibers); + std::vector< float > fib_weights; MITK_INFO << "Cutting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); + vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); + int newNumPoints = 0; if (numPoints>1) { - int newNumPoints = 0; for (int j=0; jGetPoint(j); - - itk::Point itkP; - itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; + itk::Point itkP = GetItkPoint(points->GetPoint(j)); itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); - if ( mask->GetPixel(idx) != 0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert ) + bool inside = false; + if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx)!=0 ) + inside = true; + + if (inside && !invert) { - vtkIdType id = vtkNewPoints->InsertNextPoint(p); + vtkIdType id = vtkNewPoints->InsertNextPoint(itkP.GetDataPointer()); container->GetPointIds()->InsertNextId(id); newNumPoints++; } - else if ( (!mask->GetLargestPossibleRegion().IsInside(idx) || mask->GetPixel(idx) == 0) && invert ) + else if ( !inside && invert ) { - vtkIdType id = vtkNewPoints->InsertNextPoint(p); + vtkIdType id = vtkNewPoints->InsertNextPoint(itkP.GetDataPointer()); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if (newNumPoints>1) { + fib_weights.push_back(this->GetFiberWeight(i)); vtkNewCells->InsertNextCell(container); - if (newFiberWeights->GetSize()<=vtkNewCells->GetNumberOfCells()) - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()*2); - newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), fibCopy->GetFiberWeight(i)); - + newNumPoints = 0; + container = vtkSmartPointer::New(); + } + else + { newNumPoints = 0; container = vtkSmartPointer::New(); } } if (newNumPoints>1) { + fib_weights.push_back(this->GetFiberWeight(i)); vtkNewCells->InsertNextCell(container); - if (newFiberWeights->GetSize()<=vtkNewCells->GetNumberOfCells()) - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()*2); - - newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), fibCopy->GetFiberWeight(i)); } } } + vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); + newFiberWeights->SetName("FIBER_WEIGHTS"); + newFiberWeights->SetNumberOfValues(fib_weights.size()); + if (vtkNewCells->GetNumberOfCells()<=0) return nullptr; - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()); + + for (int i=0; iGetNumberOfValues(); i++) + newFiberWeights->SetValue(i, fib_weights.at(i)); + +// vtkSmartPointer newFiberColors = vtkSmartPointer::New(); +// newFiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); +// newFiberColors->SetNumberOfComponents(4); +// newFiberColors->SetName("FIBER_COLORS"); + +// unsigned char rgba[4] = {0,0,0,0}; +// for(long i=0; iGetNumberOfPoints(); ++i) +// { +// rgba[0] = (unsigned char) r; +// rgba[1] = (unsigned char) g; +// rgba[2] = (unsigned char) b; +// rgba[3] = (unsigned char) alpha; +// m_FiberColors->InsertTypedTuple(i, rgba); +// } vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(newPolyData); newFib->SetFiberWeights(newFiberWeights); - newFib->Compress(0.1); +// newFib->Compress(0.1); return newFib; } mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(DataNode* roi, DataStorage* storage) { if (roi==nullptr || !(dynamic_cast(roi->GetData()) || dynamic_cast(roi->GetData())) ) return nullptr; std::vector tmp = ExtractFiberIdSubset(roi, storage); if (tmp.size()<=0) return mitk::FiberBundle::New(); vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); fib->SetFiberWeights(weights); return fib; } std::vector mitk::FiberBundle::ExtractFiberIdSubset(DataNode *roi, DataStorage* storage) { std::vector result; if (roi==nullptr || roi->GetData()==nullptr) return result; mitk::PlanarFigureComposite::Pointer pfc = dynamic_cast(roi->GetData()); if (!pfc.IsNull()) // handle composite { DataStorage::SetOfObjects::ConstPointer children = storage->GetDerivations(roi); if (children->size()==0) return result; switch (pfc->getOperationType()) { case 0: // AND { MITK_INFO << "AND"; result = this->ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { std::vector inRoi = this->ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(std::min(result.size(),inRoi.size())); it = std::set_intersection(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } case 1: // OR { MITK_INFO << "OR"; result = ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { it = result.end(); std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); result.insert(it, inRoi.begin(), inRoi.end()); } // remove duplicates sort(result.begin(), result.end()); it = unique(result.begin(), result.end()); result.resize( it - result.begin() ); break; } case 2: // NOT { MITK_INFO << "NOT"; for(long i=0; iGetNumFibers(); i++) result.push_back(i); std::vector::iterator it; for (unsigned int i=0; iSize(); ++i) { std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(result.size()-inRoi.size()); it = std::set_difference(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } } } else if ( dynamic_cast(roi->GetData()) ) // actual extraction { if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarPoly = dynamic_cast(roi->GetData()); //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); for (unsigned int i=0; iGetNumberOfControlPoints(); ++i) { itk::Point p = planarPoly->GetWorldControlPoint(i); vtkIdType id = polygonVtk->GetPoints()->InsertNextPoint(p[0], p[1], p[2] ); polygonVtk->GetPointIds()->InsertNextId(id); } MITK_INFO << "Extracting with polygon"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); double tolerance = 0.001; // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection double pcoords[3] = {0,0,0}; int subId = 0; int iD = polygonVtk->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subId); if (iD!=0) { result.push_back(i); break; } } } } else if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(roi->GetData()); Vector3D planeNormal = planarFigure->GetPlaneGeometry()->GetNormal(); planeNormal.Normalize(); //calculate circle radius mitk::Point3D V1w = planarFigure->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = planarFigure->GetWorldControlPoint(1); //radiusPoint double radius = V1w.EuclideanDistanceTo(V2w); radius *= radius; MITK_INFO << "Extracting with circle"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection int iD = vtkPlane::IntersectWithLine(p1,p2,planeNormal.GetDataPointer(),V1w.GetDataPointer(),t,x); if (iD!=0) { double dist = (x[0]-V1w[0])*(x[0]-V1w[0])+(x[1]-V1w[1])*(x[1]-V1w[1])+(x[2]-V1w[2])*(x[2]-V1w[2]); if( dist <= radius) { result.push_back(i); break; } } } } } return result; } return result; } void mitk::FiberBundle::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfCells(); if (m_FiberColors==nullptr || m_FiberColors->GetNumberOfTuples()!=m_FiberPolyData->GetNumberOfPoints()) this->ColorFibersByOrientation(); if (m_FiberWeights->GetNumberOfValues()!=m_NumFibers) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberWeights->SetNumberOfValues(m_NumFibers); this->SetFiberWeights(1); } if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(false); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } double b[6]; m_FiberPolyData->GetBounds(b); // calculate statistics for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } float mitk::FiberBundle::GetFiberWeight(unsigned int fiber) const { return m_FiberWeights->GetValue(fiber); } void mitk::FiberBundle::SetFiberWeights(float newWeight) { for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, newWeight); } void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer weights) { if (m_NumFibers!=weights->GetNumberOfValues()) { MITK_INFO << "Weights array not equal to number of fibers! " << weights->GetNumberOfValues() << " vs " << m_NumFibers; return; } for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, weights->GetValue(i)); m_FiberWeights->SetName("FIBER_WEIGHTS"); } void mitk::FiberBundle::SetFiberWeight(unsigned int fiber, float weight) { m_FiberWeights->SetValue(fiber, weight); } void mitk::FiberBundle::SetFiberColors(vtkSmartPointer fiberColors) { for(long i=0; iGetNumberOfPoints(); ++i) { unsigned char source[4] = {0,0,0,0}; fiberColors->GetTypedTuple(i, source); unsigned char target[4] = {0,0,0,0}; target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; m_FiberColors->InsertTypedTuple(i, target); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } itk::Matrix< double, 3, 3 > mitk::FiberBundle::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; m = rot*m; return m; } itk::Point mitk::FiberBundle::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); point[0] -= center[0]; point[1] -= center[1]; point[2] -= center[2]; point = rot*point; point[0] += center[0]+tx; point[1] += center[1]+ty; point[2] += center[2]+tz; itk::Point out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2]; return out; } void mitk::FiberBundle::TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; j p = GetItkPoint(points->GetPoint(j)); p = transform->TransformPoint(p); vtkIdType id = vtkNewPoints->InsertNextPoint(p.GetDataPointer()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rot*dir; dir[0] += center[0]+tx; dir[1] += center[1]+ty; dir[2] += center[2]+tz; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RotateAroundAxis(double x, double y, double z) { x = x*itk::Math::pi/180; y = y*itk::Math::pi/180; z = z*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ScaleFibers(double x, double y, double z, bool subtractCenter) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::BaseGeometry* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); if (subtractCenter) { p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; } p[0] *= x; p[1] *= y; p[2] *= z; if (subtractCenter) { p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; } vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TranslateFibers(double x, double y, double z) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RemoveDir(vnl_vector_fixed dir, double threshold) { dir.normalize(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); bool discard = false; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); vnl_vector_fixed< double, 3 > v1; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; if (v1.magnitude()>0.001) { v1.normalize(); if (fabs(dot_product(v1,dir))>threshold) { discard = true; break; } } } if (!discard) { for (int j=0; jGetPoint(j, p1); vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); // UpdateColorCoding(); // UpdateFiberGeometry(); } bool mitk::FiberBundle::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); double p3[3]; points->GetPoint(j+2, p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveShortFibers(float lengthInMM) { MITK_INFO << "Removing short fibers"; if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers { MITK_WARN << "Process aborted. No fibers would be left!"; return false; } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); float min = m_MaxFiberLength; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } void mitk::FiberBundle::ResampleSpline(float pointDistance, double tension, double continuity, double bias ) { if (pointDistance<=0) return; vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines MITK_INFO << "Smoothing fibers"; vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_NumFibers); boost::progress_display disp(m_NumFibers); #pragma omp parallel for for (int i=0; i newPoints = vtkSmartPointer::New(); float length = 0; #pragma omp critical { length = m_FiberLengths.at(i); ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jInsertNextPoint(points->GetPoint(j)); } int sampling = std::ceil(length/pointDistance); vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(newPoints); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); #pragma omp critical { for (int j=0; jGetNumberOfPoints(); j++) { vtkIdType id = vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); smoothLine->GetPointIds()->InsertNextId(id); } resampled_streamlines[i] = smoothLine; } } for (auto container : resampled_streamlines) { vtkSmoothCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ResampleSpline(float pointDistance) { ResampleSpline(pointDistance, 0, 0, 0 ); } unsigned long mitk::FiberBundle::GetNumberOfPoints() const { unsigned long points = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); points += cell->GetNumberOfPoints(); } return points; } void mitk::FiberBundle::Compress(float error) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Compressing fibers"; unsigned long numRemovedPoints = 0; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; #pragma omp critical { ++disp; weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } // calculate curvatures int numPoints = vertices.size(); std::vector< int > removedPoints; removedPoints.resize(numPoints, 0); removedPoints[0]=-1; removedPoints[numPoints-1]=-1; vtkSmartPointer container = vtkSmartPointer::New(); int remCounter = 0; bool pointFound = true; while (pointFound) { pointFound = false; double minError = error; int removeIndex = -1; for (unsigned int j=0; j candV = vertices.at(j); int validP = -1; vnl_vector_fixed< double, 3 > pred; for (int k=j-1; k>=0; k--) if (removedPoints[k]<=0) { pred = vertices.at(k); validP = k; break; } int validS = -1; vnl_vector_fixed< double, 3 > succ; for (int k=j+1; k=0 && validS>=0) { double a = (candV-pred).magnitude(); double b = (candV-succ).magnitude(); double c = (pred-succ).magnitude(); double s=0.5*(a+b+c); double hc=(2.0/c)*sqrt(fabs(s*(s-a)*(s-b)*(s-c))); if (hcInsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); numRemovedPoints += remCounter; vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()>0) { MITK_INFO << "Removed points: " << numRemovedPoints; SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } void mitk::FiberBundle::ResampleToNumPoints(unsigned int targetPoints) { if (targetPoints<2) mitkThrow() << "Minimum two points required for resampling!"; MITK_INFO << "Resampling fibers (number of points " << targetPoints << ")"; bool unequal_fibs = true; while (unequal_fibs) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); unequal_fibs = false; //#pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; double seg_len = 0; //#pragma omp critical { weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); if ((unsigned int)numPoints!=targetPoints) seg_len = this->GetFiberLength(i)/(targetPoints-1);; vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= seg_len && seg_len>0) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-seg_len <= mitk::eps ) { vec.normalize(); newV += vec * seg_len; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - seg_len*seg_len; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if ( (j==vertices.size()-1 && new_dist>0.0001) || seg_len==0) { //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } //#pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); vtkNewCells->InsertNextCell(container); if (container->GetNumberOfPoints()!=targetPoints) unequal_fibs = true; } } if (vtkNewCells->GetNumberOfCells()>0) { SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } } void mitk::FiberBundle::ResampleLinear(double pointDistance) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Resampling fibers (linear)"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_FiberPolyData->GetNumberOfCells()); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; #pragma omp critical { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= pointDistance) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-pointDistance <= mitk::eps ) { vec.normalize(); newV += vec * pointDistance; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - pointDistance*pointDistance; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if (j==vertices.size()-1 && new_dist>0.0001) { #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { resampled_streamlines[i] = container; } } for (auto container : resampled_streamlines) { vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()>0) { m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } // reapply selected colorcoding in case PolyData structure has changed bool mitk::FiberBundle::Equals(mitk::FiberBundle* fib, double eps) { if (fib==nullptr) { MITK_INFO << "Reference bundle is nullptr!"; return false; } if (m_NumFibers!=fib->GetNumFibers()) { MITK_INFO << "Unequal number of fibers!"; MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers(); return false; } for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (numPoints2!=numPoints) { MITK_INFO << "Unequal number of points in fiber " << i << "!"; MITK_INFO << numPoints2 << " vs. " << numPoints; return false; } for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps) { MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!"; MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2]; MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2]; return false; } } } return true; } void mitk::FiberBundle::PrintSelf(std::ostream &os, itk::Indent indent) const { os << this->GetNameOfClass() << ":\n"; os << indent << "Number of fibers: " << this->GetNumFibers() << std::endl; os << indent << "Min. fiber length: " << this->GetMinFiberLength() << std::endl; os << indent << "Max. fiber length: " << this->GetMaxFiberLength() << std::endl; os << indent << "Mean fiber length: " << this->GetMeanFiberLength() << std::endl; os << indent << "Median fiber length: " << this->GetMedianFiberLength() << std::endl; os << indent << "STDEV fiber length: " << this->GetLengthStDev() << std::endl; os << indent << "Number of points: " << this->GetNumberOfPoints() << std::endl; os << indent << "Extent x: " << this->GetGeometry()->GetExtentInMM(0) << "mm" << std::endl; os << indent << "Extent y: " << this->GetGeometry()->GetExtentInMM(1) << "mm" << std::endl; os << indent << "Extent z: " << this->GetGeometry()->GetExtentInMM(2) << "mm" << std::endl; os << indent << "Diagonal: " << this->GetGeometry()->GetDiagonalLength() << "mm" << std::endl; if (m_FiberWeights!=nullptr) { std::vector< float > weights; for (int i=0; iGetSize(); i++) weights.push_back(m_FiberWeights->GetValue(i)); std::sort(weights.begin(), weights.end()); os << indent << "\nFiber weight statistics" << std::endl; os << indent << "Min: " << weights.front() << std::endl; os << indent << "1% quantile: " << weights.at(weights.size()*0.01) << std::endl; os << indent << "5% quantile: " << weights.at(weights.size()*0.05) << std::endl; os << indent << "25% quantile: " << weights.at(weights.size()*0.25) << std::endl; os << indent << "Median: " << weights.at(weights.size()*0.5) << std::endl; os << indent << "75% quantile: " << weights.at(weights.size()*0.75) << std::endl; os << indent << "95% quantile: " << weights.at(weights.size()*0.95) << std::endl; os << indent << "99% quantile: " << weights.at(weights.size()*0.99) << std::endl; os << indent << "Max: " << weights.back() << std::endl; } else os << indent << "\n\nNo fiber weight array found." << std::endl; Superclass::PrintSelf(os, indent); } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundle::UpdateOutputInformation() { } void mitk::FiberBundle::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundle::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundle::VerifyRequestedRegion() { return true; } void mitk::FiberBundle::SetRequestedRegion(const itk::DataObject* ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h index 94caf97c92..01d7525c3c 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h @@ -1,183 +1,183 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_FiberBundle_H #define _MITK_FiberBundle_H //includes for MITK datastructure #include #include #include #include #include #include #include //includes storing fiberdata #include #include #include #include #include #include #include namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class MITKFIBERTRACKING_EXPORT FiberBundle : public BaseData { public: typedef itk::Image ItkUcharImgType; // fiber colorcodings static const char* FIBER_ID_ARRAY; void UpdateOutputInformation() override; void SetRequestedRegionToLargestPossibleRegion() override; bool RequestedRegionIsOutsideOfTheBufferedRegion() override; bool VerifyRequestedRegion() override; void SetRequestedRegion(const itk::DataObject*) override; mitkClassMacro( FiberBundle, BaseData ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, vtkSmartPointer) // custom constructor // colorcoding related methods void ColorFibersByFiberWeights(bool opacity, bool normalize); void ColorFibersByCurvature(bool opacity, bool normalize); void ColorFibersByLength(bool opacity, bool normalize); void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity, bool normalize); template void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity, bool normalize); void ColorFibersByOrientation(); void SetFiberOpacity(vtkDoubleArray *FAValArray); void ResetFiberOpacity(); void SetFiberColors(vtkSmartPointer fiberColors); void SetFiberColors(float r, float g, float b, float alpha=255); vtkSmartPointer GetFiberColors() const { return m_FiberColors; } // fiber compression void Compress(float error = 0.0); // fiber resampling void ResampleSpline(float pointDistance=1); void ResampleSpline(float pointDistance, double tension, double continuity, double bias ); void ResampleLinear(double pointDistance=1); void ResampleToNumPoints(unsigned int targetPoints); mitk::FiberBundle::Pointer FilterByWeights(float weight_thr, bool invert=false); bool RemoveShortFibers(float lengthInMM); bool RemoveLongFibers(float lengthInMM); bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers); void MirrorFibers(unsigned int axis); void RotateAroundAxis(double x, double y, double z); void TranslateFibers(double x, double y, double z); void ScaleFibers(double x, double y, double z, bool subtractCenter=true); void TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz); void TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform); void RemoveDir(vnl_vector_fixed dir, double threshold); itk::Point TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz); itk::Matrix< double, 3, 3 > TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz); // add/subtract fibers FiberBundle::Pointer AddBundle(FiberBundle* fib); mitk::FiberBundle::Pointer AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs); FiberBundle::Pointer SubtractBundle(FiberBundle* fib); // fiber subset extraction FiberBundle::Pointer ExtractFiberSubset(DataNode *roi, DataStorage* storage); std::vector ExtractFiberIdSubset(DataNode* roi, DataStorage* storage); FiberBundle::Pointer RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false); - float GetOverlap(ItkUcharImgType* mask, bool do_resampling); + float GetOverlap(ItkUcharImgType* mask); mitk::FiberBundle::Pointer SubsampleFibers(float factor); // get/set data float GetFiberLength(int index) const { return m_FiberLengths.at(index); } vtkSmartPointer GetFiberWeights() const { return m_FiberWeights; } float GetFiberWeight(unsigned int fiber) const; void SetFiberWeights(float newWeight); void SetFiberWeight(unsigned int fiber, float weight); void SetFiberWeights(vtkSmartPointer weights); void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData() const; itkGetConstMacro( NumFibers, int) //itkGetMacro( FiberSampling, int) itkGetConstMacro( MinFiberLength, float ) itkGetConstMacro( MaxFiberLength, float ) itkGetConstMacro( MeanFiberLength, float ) itkGetConstMacro( MedianFiberLength, float ) itkGetConstMacro( LengthStDev, float ) itkGetConstMacro( UpdateTime2D, itk::TimeStamp ) itkGetConstMacro( UpdateTime3D, itk::TimeStamp ) void RequestUpdate2D(){ m_UpdateTime2D.Modified(); } void RequestUpdate3D(){ m_UpdateTime3D.Modified(); } void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); } unsigned long GetNumberOfPoints() const; // copy fiber bundle mitk::FiberBundle::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundle* fib, double eps=0.01); itkSetMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) itkGetConstMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) vtkSmartPointer GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights); protected: FiberBundle( vtkPolyData* fiberPolyData = nullptr ); ~FiberBundle() override; void GenerateFiberIds(); itk::Point GetItkPoint(double point[3]); void UpdateFiberGeometry(); void PrintSelf(std::ostream &os, itk::Indent indent) const override; private: // actual fiber container vtkSmartPointer m_FiberPolyData; // contains fiber ids vtkSmartPointer m_FiberIdDataSet; int m_NumFibers; vtkSmartPointer m_FiberColors; vtkSmartPointer m_FiberWeights; std::vector< float > m_FiberLengths; float m_MinFiberLength; float m_MaxFiberLength; float m_MeanFiberLength; float m_MedianFiberLength; float m_LengthStDev; itk::TimeStamp m_UpdateTime2D; itk::TimeStamp m_UpdateTime3D; mitk::BaseGeometry::Pointer m_ReferenceGeometry; }; } // namespace mitk #endif /* _MITK_FiberBundle_H */ diff --git a/Modules/DiffusionImaging/FiberTracking/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..eab698d2d4 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,156 +1,155 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #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..69ec445777 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp @@ -1,175 +1,174 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include "mitkCommandLineParser.h" #include #include #include -#include +#include #include #include #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/FitFibersToImage.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp index d8577f4050..819e709f32 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp @@ -1,350 +1,350 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; std::vector< std::string > get_file_list(const std::string& path) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); if (ext==".fib" || ext==".trk") file_list.push_back(path + '/' + filename); } } return file_list; } /*! \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fit Fibers To Image"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Assigns a weight to each fiber in order to optimally explain the input peak image"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i1", mitkCommandLineParser::StringList, "Input tractograms:", "input tractograms (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input image:", "input image", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20); parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false); parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. g:", "lower termination threshold for gradient magnitude", 1e-5); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Save Residuals:", "save residual images", false); parser.addArgument("save_weights", "", mitkCommandLineParser::Bool, "Save Weights:", "save fiber weights in a separate text file", false); parser.addArgument("filter_outliers", "", mitkCommandLineParser::Bool, "Filter outliers:", "perform second optimization run with an upper weight bound based on the first weight estimation (99% quantile)", false); parser.addArgument("join_tracts", "", mitkCommandLineParser::Bool, "Join output tracts:", "outout tracts are merged into a single tractogram", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, Variance, VoxelVariance (default), Lasso, GroupLasso, GroupVariance, NONE"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType fib_files = us::any_cast(parsedArgs["i1"]); std::string input_image_name = us::any_cast(parsedArgs["i2"]); std::string outRoot = us::any_cast(parsedArgs["o"]); bool single_fib = true; if (parsedArgs.count("bundle_based")) single_fib = !us::any_cast(parsedArgs["bundle_based"]); bool save_residuals = false; if (parsedArgs.count("save_res")) save_residuals = us::any_cast(parsedArgs["save_res"]); bool save_weights = false; if (parsedArgs.count("save_weights")) save_weights = us::any_cast(parsedArgs["save_weights"]); std::string regu = "VoxelVariance"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); bool join_tracts = false; if (parsedArgs.count("join_tracts")) join_tracts = us::any_cast(parsedArgs["join_tracts"]); int max_iter = 20; if (parsedArgs.count("max_iter")) max_iter = us::any_cast(parsedArgs["max_iter"]); float g_tol = 1e-5; if (parsedArgs.count("min_g")) g_tol = us::any_cast(parsedArgs["min_g"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = false; if (parsedArgs.count("filter_outliers")) filter_outliers = us::any_cast(parsedArgs["filter_outliers"]); try { MITK_INFO << "Loading data"; - std::streambuf *old = cout.rdbuf(); // <-- save - std::stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect +// std::streambuf *old = cout.rdbuf(); // <-- save +// std::stringstream ss; +// std::cout.rdbuf (ss.rdbuf()); // <-- redirect std::vector< mitk::FiberBundle::Pointer > input_tracts; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); std::vector< std::string > fib_names; for (auto item : fib_files) { if ( ist::FileIsDirectory(item) ) { for ( auto fibFile : get_file_list(item) ) { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(fibFile); } } else { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(item); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(item); } } - std::cout.rdbuf (old); // <-- restore +// std::cout.rdbuf (old); // <-- restore itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); mitk::BaseData::Pointer inputData = mitk::IOUtil::Load(input_image_name, &functor)[0].GetPointer(); mitk::Image::Pointer mitk_image = dynamic_cast(inputData.GetPointer()); mitk::PeakImage::Pointer mitk_peak_image = dynamic_cast(inputData.GetPointer()); if (mitk_peak_image.IsNotNull()) { typedef mitk::ImageToItk< mitk::PeakImage::ItkPeakImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitk_peak_image); caster->Update(); mitk::PeakImage::ItkPeakImageType::Pointer peak_image = caster->GetOutput(); fitter->SetPeakImage(peak_image); } else if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) { fitter->SetDiffImage(mitk::DiffusionPropertyHelper::GetItkVectorImage(mitk_image)); mitk::TensorModel<>* model = new mitk::TensorModel<>(); model->SetBvalue(1000); model->SetDiffusivity1(0.0010); model->SetDiffusivity2(0.00015); model->SetDiffusivity3(0.00015); model->SetGradientList(mitk::DiffusionPropertyHelper::GetGradientContainer(mitk_image)); fitter->SetSignalModel(model); } else if (mitk_image->GetDimension()==3) { itk::FitFibersToImageFilter::DoubleImgType::Pointer scalar_image = itk::FitFibersToImageFilter::DoubleImgType::New(); mitk::CastToItkImage(mitk_image, scalar_image); fitter->SetScalarImage(scalar_image); } else { MITK_INFO << "Input image invalid. Valid options are peak image, 3D scalar image or raw diffusion-weighted image."; return EXIT_FAILURE; } fitter->SetTractograms(input_tracts); fitter->SetFitIndividualFibers(single_fib); fitter->SetMaxIterations(max_iter); fitter->SetGradientTolerance(g_tol); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="Variance") fitter->SetRegularization(VnlCostFunction::REGU::VARIANCE); else if (regu=="Lasso") fitter->SetRegularization(VnlCostFunction::REGU::LASSO); else if (regu=="VoxelVariance") fitter->SetRegularization(VnlCostFunction::REGU::VOXEL_VARIANCE); else if (regu=="GroupLasso") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_LASSO); else if (regu=="GroupVariance") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_VARIANCE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); if (save_residuals && mitk_peak_image.IsNotNull()) { itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New(); writer->SetInput(fitter->GetFittedImage()); writer->SetFileName(outRoot + "_fitted.nii.gz"); writer->Update(); writer->SetInput(fitter->GetResidualImage()); writer->SetFileName(outRoot + "_residual.nii.gz"); writer->Update(); writer->SetInput(fitter->GetOverexplainedImage()); writer->SetFileName(outRoot + "_overexplained.nii.gz"); writer->Update(); writer->SetInput(fitter->GetUnderexplainedImage()); writer->SetFileName(outRoot + "_underexplained.nii.gz"); writer->Update(); } else if (save_residuals && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) { { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetFittedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_fitted_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetResidualImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_residual_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetOverexplainedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_overexplained_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetUnderexplainedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_underexplained_image.nii.gz"); } } else if (save_residuals) { itk::ImageFileWriter< itk::FitFibersToImageFilter::DoubleImgType >::Pointer writer = itk::ImageFileWriter< itk::FitFibersToImageFilter::DoubleImgType >::New(); writer->SetInput(fitter->GetFittedImageScalar()); writer->SetFileName(outRoot + "_fitted_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetResidualImageScalar()); writer->SetFileName(outRoot + "_residual_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetOverexplainedImageScalar()); writer->SetFileName(outRoot + "_overexplained_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetUnderexplainedImageScalar()); writer->SetFileName(outRoot + "_underexplained_image.nii.gz"); writer->Update(); } std::vector< mitk::FiberBundle::Pointer > output_tracts = fitter->GetTractograms(); if (!join_tracts) { for (unsigned int bundle=0; bundleGetNumFibers(); ++f) logfile << output_tracts.at(bundle)->GetFiberWeight(f) << "\n"; logfile.close(); } } } else { mitk::FiberBundle::Pointer out = mitk::FiberBundle::New(); out = out->AddBundles(output_tracts); out->ColorFibersByFiberWeights(false, true); mitk::IOUtil::Save(out, outRoot + "_fitted.fib"); if (save_weights) { ofstream logfile; logfile.open (outRoot + "_weights.txt"); for (int f=0; fGetNumFibers(); ++f) logfile << out->GetFiberWeight(f) << "\n"; logfile.close(); } } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp index 33bbaaafb4..5a46d38d55 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp @@ -1,173 +1,171 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkCommandLineParser.h" #include #include -#include +#include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Get Overlapping Tracts"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Find tracts that overlap with the reference masks or tracts"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::StringList, "Input:", "input tractograms (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference:", "reference tractograms or mask images", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "move input tracts that do/don't overlap here", us::Any(), false); parser.addArgument("overlap_fraction", "", mitkCommandLineParser::Float, "Overlap fraction:", "", 0.9); parser.addArgument("use_any_overlap", "", mitkCommandLineParser::Bool, "Use any overlap:", "Don't find maximum overlap but use first overlap larger threshold"); parser.addArgument("dont_save_tracts", "", mitkCommandLineParser::Bool, "Don't save tracts:", "if true, only text files documenting the overlaps are saved and no tract files are copied"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType input = us::any_cast(parsedArgs["input"]); mitkCommandLineParser::StringContainerType reference = us::any_cast(parsedArgs["reference"]); std::string out_folder = us::any_cast(parsedArgs["out"]); bool use_any_overlap = false; if (parsedArgs.count("use_any_overlap")) use_any_overlap = us::any_cast(parsedArgs["use_any_overlap"]); bool dont_save_tracts = false; if (parsedArgs.count("dont_save_tracts")) dont_save_tracts = us::any_cast(parsedArgs["dont_save_tracts"]); float overlap_threshold = 0.9; if (parsedArgs.count("overlap_fraction")) overlap_threshold = us::any_cast(parsedArgs["overlap_fraction"]); try { itk::TractDensityImageFilter< ItkFloatImgType >::Pointer filter = itk::TractDensityImageFilter< ItkFloatImgType >::New(); - filter->SetDoFiberResampling(true); filter->SetUpsamplingFactor(0.25); filter->SetBinaryOutput(true); MITK_INFO << "Loading references"; std::vector< ItkFloatImgType::Pointer > masks; for (auto f : reference) { MITK_INFO << f; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNotNull()) { filter->SetFiberBundle(fib); filter->Update(); masks.push_back(filter->GetOutput()); } else { mitk::Image::Pointer m = mitk::IOUtil::Load(f); ItkFloatImgType::Pointer itkImage = ItkFloatImgType::New(); CastToItkImage(m, itkImage); masks.push_back(itkImage); } std::cout.rdbuf (old); // <-- restore } MITK_INFO << "Finding overlaps"; ofstream logfile; logfile.open (out_folder + "Overlaps.txt"); ofstream logfile2; logfile2.open (out_folder + "AllOverlaps.txt"); boost::progress_display disp(input.size()); for (auto f : input) { ++disp; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect bool is_overlapping = false; mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); - fib->ResampleLinear(2); float overlap = 0; float max_overlap = 0; std::string max_ref = "-"; int i = 0; std::string overlap_string = ist::GetFilenameWithoutExtension(f); for (auto m : masks) { - overlap = fib->GetOverlap(m, false); + overlap = fib->GetOverlap(m); if (overlap>max_overlap) { max_overlap = overlap; max_ref = ist::GetFilenameWithoutExtension(reference.at(i)); } if (use_any_overlap && overlap>=overlap_threshold) break; overlap_string += " " + ist::GetFilenameWithoutExtension(reference.at(i)) + " " + boost::lexical_cast(overlap); ++i; } if (overlap>=overlap_threshold) is_overlapping = true; logfile << ist::GetFilenameWithoutExtension(f) << " - " << max_ref << ": " << boost::lexical_cast(max_overlap) << "\n"; logfile2 << overlap_string << "\n"; if (!dont_save_tracts && is_overlapping) ist::CopyAFile(f, out_folder + ist::GetFilenameName(f)); std::cout.rdbuf (old); // <-- restore } logfile.close(); logfile2.close(); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/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..e9c1b20d15 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp @@ -1,215 +1,213 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" -#include +#include #include #include #include #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..5fe1a73974 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp @@ -1,111 +1,110 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include "mitkCommandLineParser.h" #include #include -#include +#include #include #include #include #include #include #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..b6c9959895 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp @@ -1,831 +1,837 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" #include -#include +#include #include #include #include #include #include #include #include #include #include #include using namespace mitk; double CalcErrorSignal(const std::vector& histo_mod, itk::VectorImage< short, 3 >* reference, itk::VectorImage< short, 3 >* simulation, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa) { typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiImageType; if (fa.IsNotNull()) { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it3(fa, fa->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it3.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += std::pow(mod, 4) * fabs(diff); count++; } } } } ++it1; ++it2; ++it3; } return error/count; } else { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += fabs(diff); count++; } } } ++it1; ++it2; } return error/count; } return -1; } double CalcErrorFA(const std::vector& histo_mod, mitk::Image::Pointer dwi1, itk::VectorImage< short, 3 >* dwi2, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa1, itk::Image< double,3 >::Pointer md1, bool b0_contrast) { typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiType; DwiType::Pointer dwi1_itk = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi1); typedef itk::DiffusionTensor3DReconstructionImageFilter TensorReconstructionImageFilterType; DoubleImageType::Pointer fa2; { mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainerCopy = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); for(auto it = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->Begin(); it != mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->End(); it++) gradientContainerCopy->push_back(it.Value()); TensorReconstructionImageFilterType::Pointer tensorReconstructionFilter = TensorReconstructionImageFilterType::New(); tensorReconstructionFilter->SetBValue( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); tensorReconstructionFilter->SetGradientImage(gradientContainerCopy, dwi2 ); tensorReconstructionFilter->Update(); MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput( tensorReconstructionFilter->GetOutput() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); fa2 = measurementsCalculator->GetOutput(); } DoubleImageType::Pointer md2; if (md1.IsNotNull()) { typedef itk::AdcImageFilter< short, double > AdcFilterType; AdcFilterType::Pointer filter = AdcFilterType::New(); filter->SetInput( dwi2 ); filter->SetGradientDirections( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1) ); filter->SetB_value( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); filter->SetFitSignal(false); filter->Update(); md2 = filter->GetOutput(); } itk::ImageRegionConstIterator< DoubleImageType > it1(fa1, fa1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it2(fa2, fa2->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff1(dwi1_itk, dwi1_itk->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff2(dwi2, dwi2->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; if (md1.IsNotNull() && md2.IsNotNull()) { itk::ImageRegionConstIterator< DoubleImageType > it3(md1, md1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it4(md2, md2->GetLargestPossibleRegion()); while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0 && it3.Get()>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = std::fabs(it2.Get()/fa - 1.0); double md_diff = std::fabs(it4.Get()/it3.Get() - 1.0); - error += std::pow(mod, 4) * (fa_diff + md_diff); + error += mod * (fa_diff + md_diff); count += 2; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; - error += std::pow(mod, 4) * std::fabs(b0_diff); + error += std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it3; ++it4; ++it_diff1; ++it_diff2; } } else { unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = fabs(it2.Get()/fa - 1.0); - error += std::pow(mod, 4) * fa_diff; + error += mod * fa_diff; ++count; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; - error += std::pow(mod, 4) * std::fabs(b0_diff); + error += std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it_diff1; ++it_diff2; } } return error/count; } FiberfoxParameters MakeProposalScale(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, new_params.m_SignalGen.m_SignalScale*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); new_params.m_SignalGen.m_SignalScale += add; MITK_INFO << "Proposal Signal Scale: " << new_params.m_SignalGen.m_SignalScale << " (" << add << ")"; return new_params; } FiberfoxParameters MakeProposalRelaxation(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, 3); int prop = uint1(randgen); switch(prop) { case 0: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t2 = new_params.m_NonFiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_NonFiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_NonFiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Non-Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 1: { int model_index = rand()%new_params.m_FiberModelList.size(); double t2 = new_params.m_FiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_FiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_FiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 2: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t1 = new_params.m_NonFiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_NonFiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_NonFiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Non-Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } case 3: { int model_index = rand()%new_params.m_FiberModelList.size(); double t1 = new_params.m_FiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_FiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_FiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } } return new_params; } double UpdateDiffusivity(double d, double temperature) { std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, d*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if (d+add > 0.0025) d -= add; else if ( d+add < 0.0 ) d -= add; else d += add; return d; } void ProposeDiffusivities(mitk::DiffusionSignalModel<>* signalModel, double temperature) { if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* m = dynamic_cast*>(signalModel); double new_d1 = UpdateDiffusivity(m->GetDiffusivity1(), temperature); double new_d2 = UpdateDiffusivity(m->GetDiffusivity2(), temperature); while (new_d1GetDiffusivity2(), temperature); MITK_INFO << "d1: " << new_d1 << " (" << new_d1-m->GetDiffusivity1() << ")"; MITK_INFO << "d2: " << new_d2 << " (" << new_d2-m->GetDiffusivity2() << ")"; m->SetDiffusivity1(new_d1); m->SetDiffusivity2(new_d2); m->SetDiffusivity3(new_d2); } else if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } } FiberfoxParameters MakeProposalDiff(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, new_params.m_NonFiberModelList.size() + new_params.m_FiberModelList.size() - 1); unsigned int prop = uint1(randgen); if (prop::Pointer > frac, double temperature) { FiberfoxParameters new_params(old_params); MITK_INFO << "Proposal Volume"; std::random_device r; std::default_random_engine randgen(r()); { std::normal_distribution normal_dist(0, old_tdi_thr*0.1*temperature); new_tdi_thr = old_tdi_thr + normal_dist(randgen); while (new_tdi_thr<=0.01) + { new_tdi_thr = old_tdi_thr + normal_dist(randgen); + } } { std::normal_distribution normal_dist(0, old_sqrt*0.1*temperature); new_sqrt = old_sqrt + normal_dist(randgen); while (new_sqrt<=0.01) + { new_sqrt = old_sqrt + normal_dist(randgen); + } } itk::TdiToVolumeFractionFilter< double >::Pointer fraction_generator = itk::TdiToVolumeFractionFilter< double >::New(); fraction_generator->SetTdiThreshold(new_tdi_thr); fraction_generator->SetSqrt(new_sqrt); fraction_generator->SetInput(0, frac.at(0)); fraction_generator->SetInput(1, frac.at(1)); fraction_generator->SetInput(2, frac.at(2)); fraction_generator->SetInput(3, frac.at(3)); fraction_generator->SetInput(4, frac.at(4)); fraction_generator->Update(); new_params.m_FiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(0)); new_params.m_FiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(1)); new_params.m_NonFiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(2)); new_params.m_NonFiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(3)); MITK_INFO << "TDI Threshold: " << new_tdi_thr << " (" << new_tdi_thr-old_tdi_thr << ")"; MITK_INFO << "SQRT: " << new_sqrt << " (" << new_sqrt-old_sqrt << ")"; return new_params; } /*! * \brief Command line interface to optimize Fiberfox parameters. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("FiberfoxOptimization"); parser.setCategory("Optimize Fiberfox Parameters"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.beginGroup("1. Mandatory Input:"); parser.addArgument("parameters", "p", mitkCommandLineParser::InputFile, "Parameter File:", "fiberfox parameter file (.ffp)", us::Any(), false); parser.addArgument("tracts", "t", mitkCommandLineParser::String, "Input Tractogram:", "Input tractogram.", us::Any(), false); parser.addArgument("out_folder", "o", mitkCommandLineParser::String, "Output Folder:", "", us::Any(), false); parser.addArgument("dmri", "d", mitkCommandLineParser::String, "Target image:", "Target dMRI to approximate.", us::Any(), false); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "Error is only calculated inside the mask image", false); parser.endGroup(); parser.beginGroup("2. Parameters to optimize:"); parser.addArgument("no_diff", "", mitkCommandLineParser::Bool, "Don't optimize diffusivities:", "Don't optimize diffusivities"); parser.addArgument("no_relax", "", mitkCommandLineParser::Bool, "Don't optimize relaxation times:", "Don't optimize relaxation times"); parser.addArgument("no_scale", "", mitkCommandLineParser::Bool, "Don't optimize signal scale:", "Don't optimize global signal scale"); parser.endGroup(); parser.beginGroup("3. Error measure:"); parser.addArgument("fa_error", "", mitkCommandLineParser::Bool, "Optimize FA", "Optimize FA instead of raw signal. Requires FA image."); parser.addArgument("fa_image", "", mitkCommandLineParser::InputFile, "FA image:", "Weight error by FA histogram. Always necessary with option fa_error!"); parser.addArgument("md_image", "", mitkCommandLineParser::InputFile, "MD image:", "Optimize MD in conjunction with FA (recommended when optimizing FA)."); parser.endGroup(); parser.beginGroup("4. Optimization of volume fraction maps:"); parser.addArgument("tdi", "", mitkCommandLineParser::InputFile, "TDI:", "tract density image"); parser.addArgument("wm", "", mitkCommandLineParser::InputFile, "WM:", "white matter volume fraction image"); parser.addArgument("gm", "", mitkCommandLineParser::InputFile, "GM:", "gray matter volume fraction image"); parser.addArgument("dgm", "", mitkCommandLineParser::InputFile, "DGM:", "subcortical gray matter volume fraction image"); parser.addArgument("csf", "", mitkCommandLineParser::InputFile, "CSF:", "CSF volume fraction image"); parser.addArgument("tdi_threshold", "", mitkCommandLineParser::Float, "", "", 0.75); parser.addArgument("sqrt", "", mitkCommandLineParser::Float, "", "", 1.0); parser.endGroup(); parser.beginGroup("5. General parameters:"); parser.addArgument("iterations", "", mitkCommandLineParser::Int, "Iterations:", "Number of optimizations steps", 1000); parser.addArgument("start_temp", "", mitkCommandLineParser::Float, "Start temperature:", "Higher temperature means larger parameter change proposals", 1.0); parser.addArgument("end_temp", "", mitkCommandLineParser::Float, "End temperature:", "Higher temperature means larger parameter change proposals", 0.1); parser.endGroup(); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string paramName = us::any_cast(parsedArgs["parameters"]); std::string out_folder = us::any_cast(parsedArgs["out_folder"]); std::string tract_file = us::any_cast(parsedArgs["tracts"]); MITK_INFO << "Loading target dMRI and parameters"; FiberfoxParameters parameters; parameters.LoadParameters(paramName); typedef itk::VectorImage< short, 3 > ItkDwiType; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images", "Fiberbundles"}, {}); auto dwi = mitk::IOUtil::Load(us::any_cast(parsedArgs["dmri"]), &functor); ItkDwiType::Pointer reference = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi); parameters.m_SignalGen.m_ImageRegion = reference->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = reference->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = reference->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = reference->GetDirection(); parameters.SetBvalue(static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue()); parameters.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); auto tracts = mitk::IOUtil::Load(tract_file, &functor); int iterations=1000; if (parsedArgs.count("iterations")) iterations = us::any_cast(parsedArgs["iterations"]); float start_temp=1.0; if (parsedArgs.count("start_temp")) start_temp = us::any_cast(parsedArgs["start_temp"]); float end_temp=0.1; if (parsedArgs.count("end_temp")) end_temp = us::any_cast(parsedArgs["end_temp"]); float tdi_threshold=0.75; if (parsedArgs.count("tdi_threshold")) tdi_threshold = us::any_cast(parsedArgs["tdi_threshold"]); float sqrt=1.0; if (parsedArgs.count("sqrt")) sqrt = us::any_cast(parsedArgs["sqrt"]); bool fa_error=false; if (parsedArgs.count("fa_error")) fa_error = true; std::string fa_file = ""; if (parsedArgs.count("fa_image")) fa_file = us::any_cast(parsedArgs["fa_image"]); std::string md_file = ""; if (parsedArgs.count("md_image")) md_file = us::any_cast(parsedArgs["md_image"]); std::vector< int > possible_proposals; if (!parsedArgs.count("no_diff")) { MITK_INFO << "Optimizing diffusivities"; possible_proposals.push_back(0); } if (!parsedArgs.count("no_relax")) { MITK_INFO << "Optimizing relaxation constants"; possible_proposals.push_back(1); } if (!parsedArgs.count("no_scale")) { MITK_INFO << "Optimizing global signal scale"; possible_proposals.push_back(2); } - if (possible_proposals.empty()) - { - MITK_INFO << "Incompatible options. Nothing to optimize."; - return EXIT_FAILURE; - } itk::ImageFileReader< itk::Image< unsigned char, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< unsigned char, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["mask"]) ); reader->Update(); itk::Image< unsigned char,3 >::Pointer mask = reader->GetOutput(); std::vector< itk::Image< double, 3 >::Pointer > fracs; if ( parsedArgs.count("tdi")>0 && parsedArgs.count("wm")>0 && parsedArgs.count("gm")>0 && parsedArgs.count("dgm")>0 && parsedArgs.count("csf")>0 ) { MITK_INFO << "Optimizing volume fractions"; { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["tdi"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["wm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["gm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["dgm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["csf"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } MITK_INFO << "Initial sqrt: " << sqrt; MITK_INFO << "Initial TDI threshold: " << tdi_threshold; possible_proposals.push_back(3); } std::vector< double > histogram_modifiers; itk::Image< double,3 >::Pointer fa_image = nullptr; if (fa_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( fa_file ); reader->Update(); fa_image = reader->GetOutput(); - int binsPerDimension = 20; + int binsPerDimension = 10; using ImageToHistogramFilterType = itk::Statistics::MaskedImageToHistogramFilter< itk::Image< double,3 >, itk::Image< unsigned char,3 > >; ImageToHistogramFilterType::HistogramType::MeasurementVectorType lowerBound(binsPerDimension); lowerBound.Fill(0.0); ImageToHistogramFilterType::HistogramType::MeasurementVectorType upperBound(binsPerDimension); upperBound.Fill(1.0); ImageToHistogramFilterType::HistogramType::SizeType size(1); size.Fill(binsPerDimension); ImageToHistogramFilterType::Pointer imageToHistogramFilter = ImageToHistogramFilterType::New(); imageToHistogramFilter->SetInput( fa_image ); imageToHistogramFilter->SetHistogramBinMinimum( lowerBound ); imageToHistogramFilter->SetHistogramBinMaximum( upperBound ); imageToHistogramFilter->SetHistogramSize( size ); imageToHistogramFilter->SetMaskImage(mask); imageToHistogramFilter->SetMaskValue(1); imageToHistogramFilter->Update(); ImageToHistogramFilterType::HistogramType* histogram = imageToHistogramFilter->GetOutput(); unsigned int max = 0; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { if (histogram->GetFrequency(i)>max) max = histogram->GetFrequency(i); } MITK_INFO << "FA histogram modifiers:"; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { - histogram_modifiers.push_back((double)max/histogram->GetFrequency(i)); - MITK_INFO << std::pow(histogram_modifiers.back(), 4); + histogram_modifiers.push_back(1.0 - (double)histogram->GetFrequency(i)/(double)max); + MITK_INFO << histogram_modifiers.back(); } if (fa_error) MITK_INFO << "Using FA error measure."; } itk::Image< double,3 >::Pointer md_image = nullptr; if (md_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( md_file ); reader->Update(); md_image = reader->GetOutput(); if (fa_error) MITK_INFO << "Using MD error measure."; } if (fa_error && fa_image.IsNull()) { MITK_INFO << "Incompatible options. Need FA image to calculate FA error."; return EXIT_FAILURE; } + if (possible_proposals.empty()) + { + MITK_INFO << "Incompatible options. Nothing to optimize."; + return EXIT_FAILURE; + } + itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(tracts); tractsToDwiFilter->SetParameters(parameters); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); { mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/initial.dwi"); } double old_tdi_thr = tdi_threshold; double old_sqrt = sqrt; - double new_tdi_thr; - double new_sqrt; + double new_tdi_thr = old_tdi_thr; + double new_sqrt = old_sqrt; MITK_INFO << "\n\n"; MITK_INFO << "Iterations: " << iterations; MITK_INFO << "start_temp: " << start_temp; MITK_INFO << "end_temp: " << end_temp; double alpha = log(end_temp/start_temp); int accepted = 0; double last_error = 9999999; if (fa_error) { MITK_INFO << "Calculating FA error"; last_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); } else { MITK_INFO << "Calculating raw-image error"; last_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); } MITK_INFO << "Initial E = " << last_error; MITK_INFO << "\n\n**************************************************************************************"; std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, possible_proposals.size()-1); for (int i=0; i::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(dynamic_cast(tracts.GetPointer())); tractsToDwiFilter->SetParameters(proposal); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); std::cout.rdbuf (old); // <-- restore double new_error = 9999999; if (fa_error && fa_image.IsNotNull()) new_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); else new_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); MITK_INFO << "E = " << new_error << "(" << new_error-last_error << ")"; if (last_errorGetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/optimized.dwi"); proposal.SaveParameters(out_folder + "/optimized.ffp"); std::cout.rdbuf (old); // <-- restore accepted++; old_tdi_thr = new_tdi_thr; old_sqrt = new_sqrt; MITK_INFO << "Accepted (acc. rate " << (float)accepted/(i+1) << ")"; parameters = FiberfoxParameters(proposal); last_error = new_error; } MITK_INFO << "\n\n\n"; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/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..0a616ad8bf 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp @@ -1,575 +1,558 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; typedef itk::Image< unsigned char, 3 > ItkUcharImageType; std::vector< mitk::FiberBundle::Pointer > CombineTractograms(std::vector< mitk::FiberBundle::Pointer > reference, std::vector< mitk::FiberBundle::Pointer > candidates, int skip=-1) { std::vector< mitk::FiberBundle::Pointer > fib; for (auto f : reference) fib.push_back(f); int c = 0; for (auto f : candidates) { if (c!=skip) fib.push_back(f); ++c; } return fib; } std::vector< std::string > get_file_list(const std::string& path, std::vector< std::string > extensions={".fib", ".trk"}) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); for (auto e : extensions) { if (ext==e) { file_list.push_back(path + '/' + filename); break; } } } } return file_list; } /*! \brief Score input candidate tracts using ACP analysis */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Anchor Constrained Plausibility"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription("Score input candidate tracts using ACP analysis"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "a", mitkCommandLineParser::InputFile, "Anchor tractogram:", "anchor tracts in one tractogram file", us::Any(), false); parser.addArgument("", "p", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); parser.addArgument("", "c", mitkCommandLineParser::InputDirectory, "Candidates folder:", "folder containing candidate tracts", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output folder:", "output folder", us::Any(), false); parser.addArgument("anchor_masks", "", mitkCommandLineParser::StringList, "Reference Masks:", "reference tract masks for accuracy evaluation"); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "scoring is only performed inside the mask image"); parser.addArgument("greedy_add", "", mitkCommandLineParser::Bool, "Greedy:", "if enabled, the candidate tracts are not jointly fitted to the residual image but one after the other employing a greedy scheme", false); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); parser.addArgument("filter_outliers", "", mitkCommandLineParser::Bool, "Filter outliers:", "perform second optimization run with an upper weight bound based on the first weight estimation (99% quantile)", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, Variance, VoxelVariance, Lasso, GroupLasso, GroupVariance, NONE (default)"); parser.addArgument("use_num_streamlines", "", mitkCommandLineParser::Bool, "Use number of streamlines as score:", "Don't fit candidates, simply use number of streamlines per candidate as score", false); parser.addArgument("use_weights", "", mitkCommandLineParser::Bool, "Use input weights as score:", "Don't fit candidates, simply use first input streamline weight per candidate as score", false); parser.addArgument("filter_zero_weights", "", mitkCommandLineParser::Bool, "Filter zero-weights", "Remove streamlines with weight 0 from candidates", false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string anchors_file = us::any_cast(parsedArgs["a"]); std::string peak_file_name = us::any_cast(parsedArgs["p"]); std::string candidate_tract_folder = us::any_cast(parsedArgs["c"]); std::string out_folder = us::any_cast(parsedArgs["o"]); bool greedy_add = false; if (parsedArgs.count("greedy_add")) greedy_add = us::any_cast(parsedArgs["greedy_add"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = false; if (parsedArgs.count("filter_outliers")) filter_outliers = us::any_cast(parsedArgs["filter_outliers"]); bool filter_zero_weights = false; if (parsedArgs.count("filter_zero_weights")) filter_zero_weights = us::any_cast(parsedArgs["filter_zero_weights"]); std::string mask_file = ""; if (parsedArgs.count("mask")) mask_file = us::any_cast(parsedArgs["mask"]); mitkCommandLineParser::StringContainerType anchor_mask_files_folders; if (parsedArgs.count("anchor_masks")) anchor_mask_files_folders = us::any_cast(parsedArgs["anchor_masks"]); std::string regu = "NONE"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); bool use_weights = false; if (parsedArgs.count("use_weights")) use_weights = us::any_cast(parsedArgs["use_weights"]); bool use_num_streamlines = false; if (parsedArgs.count("use_num_streamlines")) use_num_streamlines = us::any_cast(parsedArgs["use_num_streamlines"]); try { itk::TimeProbe clock; clock.Start(); if (!ist::PathExists(out_folder)) { MITK_INFO << "Creating output directory"; ist::MakeDirectory(out_folder); } MITK_INFO << "Loading data"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect ofstream logfile; logfile.open (out_folder + "log.txt"); itk::ImageFileWriter< PeakImgType >::Pointer peak_image_writer = itk::ImageFileWriter< PeakImgType >::New(); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); - float minSpacing = 1; - if(inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[2]) - minSpacing = inputImage->GetGeometry()->GetSpacing()[0]; - else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2]) - minSpacing = inputImage->GetGeometry()->GetSpacing()[1]; - else - minSpacing = inputImage->GetGeometry()->GetSpacing()[2]; - // Load mask file. Fit is only performed inside the mask itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr; if (mask_file.compare("")!=0) { mitk::Image::Pointer mitk_mask = mitk::IOUtil::Load(mask_file); mitk::CastToItkImage(mitk_mask, mask); } // Load masks covering the true positives for evaluation purposes std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks; std::vector< std::string > anchor_mask_files; for (auto filename : anchor_mask_files_folders) { if (itksys::SystemTools::PathExists(filename)) { auto list = get_file_list(filename, {".nrrd",".nii.gz",".nii"}); for (auto f : list) { MITK_INFO << f; itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(f); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); anchor_mask_files.push_back(f); } } else if (itksys::SystemTools::FileExists(filename)) { anchor_mask_files.push_back(filename); itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(filename); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); } } // Load peak image typedef mitk::ImageToItk< PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(inputImage); caster->Update(); PeakImgType::Pointer peak_image = caster->GetOutput(); // Load all candidate tracts std::vector< std::string > candidate_tract_files = get_file_list(candidate_tract_folder); std::vector< mitk::FiberBundle::Pointer > input_candidates; for (std::string f : candidate_tract_files) { mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNull()) continue; if (fib->GetNumFibers()<=0) continue; - fib->ResampleLinear(minSpacing/10.0); input_candidates.push_back(fib); } std::cout.rdbuf (old); // <-- restore MITK_INFO << "Loaded " << candidate_tract_files.size() << " candidate tracts."; MITK_INFO << "Loaded " << reference_masks.size() << " reference masks."; double rmse = 0.0; int iteration = 0; std::string name = "NOANCHOR"; // Load reference tractogram consisting of all known tracts std::vector< mitk::FiberBundle::Pointer > input_reference; mitk::FiberBundle::Pointer anchor_tractogram = mitk::IOUtil::Load(anchors_file); if ( !(anchor_tractogram.IsNull() || anchor_tractogram->GetNumFibers()==0) ) { - std::streambuf *old = cout.rdbuf(); // <-- save - std::stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect - anchor_tractogram->ResampleLinear(minSpacing/10.0); - std::cout.rdbuf (old); // <-- restore input_reference.push_back(anchor_tractogram); // Fit known tracts to peak image to obtain underexplained image MITK_INFO << "Fit anchor tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetTractograms(input_reference); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetPeakImage(peak_image); fitter->SetVerbose(true); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); rmse = fitter->GetRMSE(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[0] << " " << name << " RMSE: " << rmse << "\n"; name = ist::GetFilenameWithoutExtension(anchors_file); mitk::FiberBundle::Pointer anchor_tracts = fitter->GetTractograms().at(0); anchor_tracts->SetFiberColors(255,255,255); mitk::IOUtil::Save(anchor_tracts, out_folder + boost::lexical_cast((int)(100000*rms_diff[0])) + "_" + name + ".fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_" + name + ".nii.gz"); peak_image_writer->Update(); } if (use_weights || use_num_streamlines) { MITK_INFO << "Using tract weights as scores"; int c = 0; for (auto fib : input_candidates) { int mod = 1; double score = 0; if (use_weights) { score = fib->GetFiberWeight(0); mod = 100000; } else if (use_num_streamlines) score = fib->GetNumFibers(); fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(mod*score)) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { - float overlap = fib->GetOverlap(ref_mask, false); + float overlap = fib->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << score << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } } else if (!greedy_add) { MITK_INFO << "Fit candidate tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(true); fitter->SetPeakImage(peak_image); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetTractograms(input_candidates); fitter->SetFitIndividualFibers(true); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="Variance") fitter->SetRegularization(VnlCostFunction::REGU::VARIANCE); else if (regu=="Lasso") fitter->SetRegularization(VnlCostFunction::REGU::LASSO); else if (regu=="VoxelVariance") fitter->SetRegularization(VnlCostFunction::REGU::VOXEL_VARIANCE); else if (regu=="GroupLasso") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_LASSO); else if (regu=="GroupVariance") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_VARIANCE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); // vnl_vector log_rms_diff = rms_diff-rms_diff.min_value() + 1; // log_rms_diff = log_rms_diff.apply(std::log); // log_rms_diff /= log_rms_diff.max_value(); int c = 0; for (auto fib : input_candidates) { // fib->SetFiberWeights( log_rms_diff[c] ); // fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect if (filter_zero_weights) fib = fib->FilterByWeights(0); mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(100000*rms_diff[c])) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { - float overlap = fib->GetOverlap(ref_mask, false); + float overlap = fib->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } mitk::FiberBundle::Pointer out_fib = mitk::FiberBundle::New(); out_fib = out_fib->AddBundles(input_candidates); out_fib->ColorFibersByFiberWeights(false, true); mitk::IOUtil::Save(out_fib, out_folder + "AllCandidates.fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_AllCandidates.nii.gz"); peak_image_writer->Update(); } else { MITK_INFO << "RMSE: " << setprecision(5) << rmse; // fitter->SetPeakImage(peak_image); // Iteratively add candidate bundles in a greedy manner while (!input_candidates.empty()) { double next_rmse = rmse; double num_peaks = 0; mitk::FiberBundle::Pointer best_candidate = nullptr; PeakImgType::Pointer best_candidate_peak_image = nullptr; for (int i=0; i<(int)input_candidates.size(); ++i) { // WHY NECESSARY AGAIN?? itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(false); fitter->SetPeakImage(peak_image); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); // ****************************** fitter->SetTractograms({input_candidates.at(i)}); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect fitter->Update(); std::cout.rdbuf (old); // <-- restore double candidate_rmse = fitter->GetRMSE(); if (candidate_rmseGetNumCoveredDirections(); best_candidate = fitter->GetTractograms().at(0); best_candidate_peak_image = fitter->GetUnderexplainedImage(); } } if (best_candidate.IsNull()) break; // fitter->SetPeakImage(peak_image); peak_image = best_candidate_peak_image; int i=0; std::vector< mitk::FiberBundle::Pointer > remaining_candidates; std::vector< std::string > remaining_candidate_files; for (auto fib : input_candidates) { if (fib!=best_candidate) { remaining_candidates.push_back(fib); remaining_candidate_files.push_back(candidate_tract_files.at(i)); } else name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i)); ++i; } input_candidates = remaining_candidates; candidate_tract_files = remaining_candidate_files; iteration++; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect // Save winning candidate if (filter_zero_weights) best_candidate = best_candidate->FilterByWeights(0); mitk::IOUtil::Save(best_candidate, out_folder + boost::lexical_cast(iteration) + "_" + name + ".fib"); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); peak_image_writer->Update(); // Calculate best overlap with reference masks for evaluation purposes float best_overlap = 0; int best_overlap_index = -1; i = 0; for (auto ref_mask : reference_masks) { - float overlap = best_candidate->GetOverlap(ref_mask, false); + float overlap = best_candidate->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = i; } ++i; } std::cout.rdbuf (old); // <-- restore logfile << "RMSE: " << setprecision(5) << rmse << " " << name << " " << num_peaks << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; } } clock.Stop(); int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s"; logfile.close(); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/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/OpenCL/mitkOclDataSetToDataSetFilter.cpp b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp index 2cf7acab5d..be0075557e 100644 --- a/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp +++ b/Modules/OpenCL/mitkOclDataSetToDataSetFilter.cpp @@ -1,128 +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 "mitkOclDataSetToDataSetFilter.h" #include "mitkOclDataSet.h" #include "mitkException.h" mitk::OclDataSetToDataSetFilter::OclDataSetToDataSetFilter() { m_Output = mitk::OclDataSet::New(); } - mitk::OclDataSetToDataSetFilter::~OclDataSetToDataSetFilter() { } mitk::OclDataSet::Pointer mitk::OclDataSetToDataSetFilter::GetGPUOutput() { return this->m_Output; } void* mitk::OclDataSetToDataSetFilter::GetOutput() { void* pData = m_Output->TransferDataToCPU(m_CommandQue); return pData; } int mitk::OclDataSetToDataSetFilter::GetBytesPerElem() { return this->m_CurrentSizeOutput; } bool mitk::OclDataSetToDataSetFilter::InitExec(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE) { cl_int clErr = 0; if (m_Input.IsNull()) mitkThrow() << "Input DataSet is null."; // get DataSet size once const unsigned int uiDataSetWidth = dimensions[0]; const unsigned int uiDataSetHeight = dimensions[1]; const unsigned int uiDataSetDepth = dimensions[2]; // compute work sizes this->SetWorkingSize(8, uiDataSetWidth, 8, uiDataSetHeight, 8, uiDataSetDepth); cl_mem clBuffIn = m_Input->GetGPUBuffer(); cl_mem clBuffOut = m_Output->GetGPUBuffer(); if (!clBuffIn) { if (m_Input->TransferDataToGPU(m_CommandQue) != CL_SUCCESS) { mitkThrow() << "Could not create / initialize gpu DataSet."; } clBuffIn = m_Input->GetGPUBuffer(); } // output DataSet not initialized or output buffer size changed if (!clBuffOut || (size_t)m_Output->GetBufferSize() != outputDataSize) { MITK_DEBUG << "Create GPU DataSet call " << uiDataSetWidth << "x" << uiDataSetHeight << "x" << uiDataSetDepth; m_Output->SetBpE(outputBpE); m_Output->SetBufferSize(outputDataSize); clBuffOut = m_Output->CreateGPUBuffer(); m_CurrentSizeOutput = outputBpE; } clErr = 0; clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffIn); clErr |= clSetKernelArg(ckKernel, 1, sizeof(cl_mem), &clBuffOut); CHECK_OCL_ERR(clErr); if (clErr != CL_SUCCESS) mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); return(clErr == CL_SUCCESS); } bool mitk::OclDataSetToDataSetFilter::InitExecNoInput(cl_kernel ckKernel, unsigned int* dimensions, size_t outputDataSize, unsigned int outputBpE) { cl_int clErr = 0; // get DataSet size once const unsigned int uiDataSetWidth = dimensions[0]; const unsigned int uiDataSetHeight = dimensions[1]; const unsigned int uiDataSetDepth = dimensions[2]; // compute work sizes this->SetWorkingSize(8, uiDataSetWidth, 8, uiDataSetHeight, 8, uiDataSetDepth); cl_mem clBuffOut = m_Output->GetGPUBuffer(); // output DataSet not initialized or output buffer size changed if (!clBuffOut || (size_t)m_Output->GetBufferSize() != outputDataSize) { MITK_DEBUG << "Create GPU DataSet call " << uiDataSetWidth << "x" << uiDataSetHeight << "x" << uiDataSetDepth; m_Output->SetBpE(outputBpE); m_Output->SetBufferSize(outputDataSize); clBuffOut = m_Output->CreateGPUBuffer(); m_CurrentSizeOutput = outputBpE; } clErr = clSetKernelArg(ckKernel, 0, sizeof(cl_mem), &clBuffOut); CHECK_OCL_ERR(clErr); if (clErr != CL_SUCCESS) mitkThrow() << "OpenCL Part initialization failed with " << GetOclErrorAsString(clErr); return(clErr == CL_SUCCESS); -} \ No newline at end of file +} 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/PhotoacousticsAlgorithms/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt index 7b8587334b..7eb8df47cd 100644 --- a/Modules/PhotoacousticsAlgorithms/CMakeLists.txt +++ b/Modules/PhotoacousticsAlgorithms/CMakeLists.txt @@ -1,16 +1,19 @@ set(dependencies_list MitkCore MitkAlgorithmsExt) IF(MITK_USE_OpenCL) add_definitions(-DPHOTOACOUSTICS_USE_GPU) set(dependencies_list ${dependencies_list} MitkOpenCL) message("Using OpenCL in PhotoacousticAlgorithms") ENDIF(MITK_USE_OpenCL) MITK_CREATE_MODULE( SUBPROJECTS DEPENDS ${dependencies_list} #AUTOLOAD_WITH MitkCore - INCLUDE_DIRS PUBLIC Algorithms/ITKUltrasound Algorithms Algorithms/OCL + INCLUDE_DIRS PUBLIC include INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} PACKAGE_DEPENDS ITK|ITKFFT+ITKImageCompose+ITKImageIntensity -) \ No newline at end of file +) + +add_subdirectory(test) +add_subdirectory(MitkPABeamformingTool) diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt new file mode 100644 index 0000000000..73ded2d3cf --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/CMakeLists.txt @@ -0,0 +1,11 @@ +OPTION(BUILD_PhotoacousticBeamformingTool "Build MiniApp for beamforming of a PA image" ON) + +IF(BUILD_PhotoacousticBeamformingTool) + PROJECT( MitkPABeamformingTool ) + mitk_create_executable(PABeamformingTool + DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsAlgorithms + PACKAGE_DEPENDS + CPP_FILES PABeamformingTool.cpp) + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + ENDIF() diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp new file mode 100644 index 0000000000..1a9ce11188 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/PABeamformingTool.cpp @@ -0,0 +1,230 @@ +/*=================================================================== + +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 + +struct InputParameters +{ + mitk::Image::Pointer inputImage; + std::string outputFilename; + bool verbose; + float speedOfSound; + unsigned int cutoff; + float angle; + unsigned int samples; + mitk::BeamformingSettings::BeamformingAlgorithm algorithm; +}; + +InputParameters parseInput(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Photoacoustics Beamforming Tool"); + parser.setDescription("Reads a nrrd file as an input and applies a beamforming method as set with the parameters."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("Required parameters"); + parser.addArgument( + "inputImage", "i", mitkCommandLineParser::InputImage, + "Input image (mitk::Image)", "input image (.nrrd file)", + us::Any(), false); + parser.addArgument( + "output", "o", mitkCommandLineParser::OutputFile, + "Output filename", "output image (.nrrd file)", + us::Any(), false); + parser.endGroup(); + + parser.beginGroup("Optional parameters"); + parser.addArgument( + "verbose", "v", mitkCommandLineParser::Bool, + "Verbose Output", "Whether to produce verbose, or rather debug output. (default: false)"); + parser.addArgument( + "speed-of-sound", "sos", mitkCommandLineParser::Float, + "Speed of Sound [m/s]", "The average speed of sound as assumed for the reconstruction in [m/s]. (default: 1500)"); + parser.addArgument( + "cutoff", "co", mitkCommandLineParser::Int, + "cutoff margin on the top of the image [pixels]", "The number of pixels to be ignored for this filter in [pixels] (default: 0)."); + parser.addArgument( + "angle", "a", mitkCommandLineParser::Float, + "field of view of the transducer elements [degrees]", "The field of view of each individual transducer element [degrees] (default: 27)."); + parser.addArgument( + "samples", "s", mitkCommandLineParser::Int, + "samples per reconstruction line [pixels]", "The pixels along the y axis in the beamformed image [pixels] (default: 2048)."); + parser.addArgument( + "algorithm", "alg", mitkCommandLineParser::String, + "one of [\"DAS\", \"DMAS\", \"sDMAS\"]", "The beamforming algorithm to be used for reconstruction (default: DAS)."); + parser.endGroup(); + + InputParameters input; + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size() == 0) + exit(-1); + + if (parsedArgs.count("verbose")) + { + input.verbose = true; + } + else + { + input.verbose = false; + } + MITK_INFO(input.verbose) << "### VERBOSE OUTPUT ENABLED ###"; + + if (parsedArgs.count("inputImage")) + { + MITK_INFO(input.verbose) << "Reading input image..."; + input.inputImage = mitk::IOUtil::Load(us::any_cast(parsedArgs["inputImage"])); + MITK_INFO(input.verbose) << "Reading input image...[Done]"; + } + else + { + mitkThrow() << "No input image given."; + } + + if (parsedArgs.count("output")) + { + input.outputFilename = us::any_cast(parsedArgs["output"]); + } + else + { + mitkThrow() << "No output image path given.."; + } + + if (parsedArgs.count("speed-of-sound")) + { + input.speedOfSound = us::any_cast(parsedArgs["speed-of-sound"]); + } + else + { + input.speedOfSound = 1500; + } + + if (parsedArgs.count("cutoff")) + { + input.cutoff = us::any_cast(parsedArgs["cutoff"]); + } + else + { + input.cutoff = 0; + } + + if (parsedArgs.count("angle")) + { + input.angle = us::any_cast(parsedArgs["angle"]); + } + else + { + input.angle = 27; + } + + if (parsedArgs.count("samples")) + { + input.samples = us::any_cast(parsedArgs["samples"]); + } + else + { + input.samples = 2048; + } + + if (parsedArgs.count("algorithm")) + { + std::string algorithm = us::any_cast(parsedArgs["algorithm"]); + MITK_INFO(input.verbose) << "Parsing algorithm: " << algorithm; + if (algorithm == "DAS") + input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + else if (algorithm == "DMAS") + input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; + else if (algorithm == "sDMAS") + input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; + else + { + MITK_INFO(input.verbose) << "Not a valid beamforming algorithm: " << algorithm << " Reverting to DAS"; + input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + } + + MITK_INFO(input.verbose) << "Sucessfully set algorithm: " << algorithm; + } + else + { + input.algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + MITK_INFO(input.verbose) << "No matching algorithm found. Using DAS."; + } + + return input; +} + +mitk::BeamformingSettings::Pointer ParseSettings(InputParameters &input) +{ + mitk::BeamformingSettings::Pointer outputSettings = mitk::BeamformingSettings::New( + (float)(input.inputImage->GetGeometry()->GetSpacing()[0] / 1000), + (float)(input.speedOfSound), + (float)(input.inputImage->GetGeometry()->GetSpacing()[1] / 1000000), + input.angle, + true, + input.inputImage->GetDimension(1), + input.inputImage->GetDimension(0), + input.inputImage->GetDimensions(), + 0.04, + false, + 16, + mitk::BeamformingSettings::DelayCalc::Spherical, + mitk::BeamformingSettings::Apodization::Box, + input.inputImage->GetDimension(0), + input.algorithm + ); + + return outputSettings; +} + +int main(int argc, char * argv[]) +{ + auto input = parseInput(argc, argv); + + MITK_INFO(input.verbose) << "Beamforming input image..."; + + mitk::PhotoacousticFilterService::Pointer m_BeamformingService = mitk::PhotoacousticFilterService::New(); + + mitk::BeamformingSettings::Pointer settings = ParseSettings(input); + + mitk::CastToFloatImageFilter::Pointer castFilter = mitk::CastToFloatImageFilter::New(); + castFilter->SetInput(input.inputImage); + castFilter->Update(); + auto floatImage = castFilter->GetOutput(); + + auto output = m_BeamformingService->ApplyBeamforming(floatImage, settings); + MITK_INFO(input.verbose) << "Applying BModeFilter to image..."; + auto output2 = m_BeamformingService->ApplyBmodeFilter(output, mitk::PhotoacousticFilterService::EnvelopeDetection, false); + MITK_INFO(input.verbose) << "Applying BModeFilter to image...[Done]"; + + MITK_INFO(input.verbose) << "Saving image..."; + mitk::IOUtil::Save(output2, input.outputFilename); + MITK_INFO(input.verbose) << "Saving image...[Done]"; + + MITK_INFO(input.verbose) << "Beamforming input image...[Done]"; +} diff --git a/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/files.cmake b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/files.cmake new file mode 100644 index 0000000000..1bed148e42 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/MitkPABeamformingTool/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + PABeamformingTool.cpp +) diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl deleted file mode 100644 index 5dfd66d02d..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbs.cl +++ /dev/null @@ -1,38 +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. - -===================================================================*/ - -__kernel void ckBmodeAbs( - __global float* dSource, // input image - __global float* dDest, // output buffer - unsigned int size -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - // get image width and height - unsigned short inputS = get_global_size(1); - unsigned short inputL = get_global_size(0); - unsigned short slices = get_global_size(2); - - // terminate non-valid threads - if ( globalPosX + inputL * globalPosY + inputL * inputS * globalPosZ < size ) - { - dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = fabs(dSource[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ]); - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl b/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl deleted file mode 100644 index 842e5a5b52..0000000000 --- a/Modules/PhotoacousticsAlgorithms/Resources/BModeAbsLog.cl +++ /dev/null @@ -1,38 +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. - -===================================================================*/ - -__kernel void ckBmodeAbsLog( - __global float* dSource, // input image - __global float* dDest, // output buffer - unsigned int size -) -{ - // get thread identifier - unsigned int globalPosX = get_global_id(0); - unsigned int globalPosY = get_global_id(1); - unsigned int globalPosZ = get_global_id(2); - - // get image width and height - unsigned short inputS = get_global_size(1); - unsigned short inputL = get_global_size(0); - unsigned short slices = get_global_size(2); - - // terminate non-valid threads - if ( globalPosX + inputL * globalPosY + inputL * inputS * globalPosZ < size ) - { - dDest[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ] = log(fabs(dSource[ globalPosZ * inputL * inputS + globalPosY * inputL + globalPosX ])); - } -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl b/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl index 0be471b2b4..c0ee5224e4 100644 --- a/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl +++ b/Modules/PhotoacousticsAlgorithms/Resources/DelayCalculation.cl @@ -1,69 +1,70 @@ /*=================================================================== 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. ===================================================================*/ __kernel void ckDelayCalculationQuad( __global unsigned short *gDest, __global unsigned short *usedLines, unsigned int inputL, unsigned int inputS, unsigned int outputL, unsigned int outputS, char isPAImage, - float delayMultiplicatorRaw // parameters + float delayMultiplicatorRaw, + float percentOfImageReconstructed // parameters ) { uint globalPosX = get_global_id(0); uint globalPosY = get_global_id(1); if (globalPosX * 2 < outputL && globalPosY < outputS) { float l_i = 0; // we calculate the delays relative to line zero - float s_i = (float)globalPosY / (float)outputS * (float)inputS / 2; + float s_i = (float)globalPosY / (float)outputS * (float)inputS / (2-isPAImage) * percentOfImageReconstructed; float l_s = (float)globalPosX / (float)outputL * (float)inputL; // the currently calculated line float delayMultiplicator = delayMultiplicatorRaw / s_i; gDest[globalPosY * (outputL / 2) + globalPosX] = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1-isPAImage)*s_i; } } __kernel void ckDelayCalculationSphe( __global unsigned short *gDest, __global unsigned short *usedLines, unsigned int inputL, unsigned int inputS, unsigned int outputL, unsigned int outputS, char isPAImage, - float delayMultiplicatorRaw // parameters + float delayMultiplicatorRaw, + float percentOfImageReconstructed // parameters ) { uint globalPosX = get_global_id(0); uint globalPosY = get_global_id(1); if (globalPosX * 2 < outputL && globalPosY < outputS) { float l_i = 0; // we calculate the delays relative to line zero - float s_i = (float)globalPosY / (float)outputS * (float)inputS / 2; - + float s_i = (float)globalPosY / (float)outputS * (float)inputS / (2-isPAImage) * percentOfImageReconstructed; float l_s = (float)globalPosX / (float)outputL * (float)inputL; // the currently calculated line gDest[globalPosY * (outputL / 2) + globalPosX] = sqrt( pow(s_i, 2) + pow((delayMultiplicatorRaw * ((l_s - l_i)) / inputL), 2) ) + (1-isPAImage)*s_i; } } \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl b/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl index 638de2b279..aa63d1562e 100644 --- a/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl +++ b/Modules/PhotoacousticsAlgorithms/Resources/UsedLinesCalculation.cl @@ -1,50 +1,52 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ __kernel void ckUsedLines( __global unsigned short* dDest, // output buffer float partMult, unsigned int inputL, unsigned int inputS, unsigned int outputL, - unsigned int outputS + unsigned int outputS, + char isPAImage, + float percentOfImageReconstructed // parameters ) { // get thread identifier unsigned int globalPosX = get_global_id(0); unsigned int globalPosY = get_global_id(1); //unsigned short outputS = get_global_size(1); //unsigned short outputL = get_global_size(0); // terminate non-valid threads if ( globalPosX < outputL && globalPosY < outputS) { float l_i = (float)globalPosX / outputL * inputL; - float s_i = (float)globalPosY / outputS * inputS / 2; + float s_i = (float)globalPosY / (float)outputS * (float)inputS / (2-isPAImage) * percentOfImageReconstructed; float part = partMult * s_i; if (part < 1) part = 1; unsigned short maxLine = min((l_i + part) + 1, (float)inputL); unsigned short minLine = max((l_i - part), 0.0f); dDest[globalPosY * 3 * outputL + 3 * globalPosX] = (maxLine - minLine); //usedLines dDest[globalPosY * 3 * outputL + 3 * globalPosX + 1] = minLine; //minLine dDest[globalPosY * 3 * outputL + 3 * globalPosX + 2] = maxLine; //maxLine } } \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/files.cmake b/Modules/PhotoacousticsAlgorithms/files.cmake index b3fdaff026..7767967748 100644 --- a/Modules/PhotoacousticsAlgorithms/files.cmake +++ b/Modules/PhotoacousticsAlgorithms/files.cmake @@ -1,25 +1,29 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES - source/mitkPhotoacousticImage.cpp - source/mitkPhotoacousticBeamformingFilter.cpp + source/filters/mitkBeamformingFilter.cpp + source/filters/mitkBeamformingSettings.cpp + source/filters/mitkImageSliceSelectionFilter.cpp + source/filters/mitkCastToFloatImageFilter.cpp + source/filters/mitkCropImageFilter.cpp + source/filters/mitkBandpassFilter.cpp source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp + source/utils/mitkPhotoacousticFilterService.cpp + source/utils/mitkBeamformingUtils.cpp ) IF(MITK_USE_OpenCL) list(APPEND CPP_FILES source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp ) ENDIF(MITK_USE_OpenCL) set(RESOURCE_FILES - BModeAbs.cl - BModeAbsLog.cl UsedLinesCalculation.cl DelayCalculation.cl DMAS.cl DAS.cl sDMAS.cl ) diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h index aed8d626fe..2f692e24fd 100644 --- a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticBModeFilter.h @@ -1,140 +1,67 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITKPHOTOACOUSTICSBMODEFILTER_H_ #define _MITKPHOTOACOUSTICSBMODEFILTER_H_ -#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN -#include "mitkOclDataSetToDataSetFilter.h" -#endif - #include #include "mitkImageToImageFilter.h" namespace mitk { - #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN - - /*! - * \brief Class implementing a mitk::OclDataSetToDataSetFilter for BMode filtering on GPU - * - * The only parameter that needs to be provided is whether it should use a logfilter. - * Currently this class only performs an absolute BMode filter. - */ - class PhotoacousticOCLBModeFilter : public OclDataSetToDataSetFilter, public itk::Object - { - - public: - mitkClassMacroItkParent(PhotoacousticOCLBModeFilter, itk::Object); - itkNewMacro(Self); - - /** \brief Set the input image to be processed - */ - void SetInput(Image::Pointer image); - - void Update(); - - /** \brief Set parameters for the filter - * - * @param useLogFilter If true, the filter will apply a logfilter on the processed image - */ - void SetParameters(bool useLogFilter) - { - m_UseLogFilter = useLogFilter; - } - - /** - * @brief GetOutput Returns an mitk::Image constructed from the processed data - */ - mitk::Image::Pointer GetOutput(); - - protected: - - PhotoacousticOCLBModeFilter(); - - virtual ~PhotoacousticOCLBModeFilter(); - - bool Initialize(); - - void Execute(); - - mitk::PixelType GetOutputType() - { - return mitk::MakeScalarPixelType(); - } - - int GetBytesPerElem() - { - return sizeof(float); - } - - virtual us::Module* GetModule(); - - private: - /** The OpenCL kernel for the filter */ - cl_kernel m_PixelCalculation; - bool m_UseLogFilter; - - mitk::Image::Pointer m_InputImage; - unsigned int m_InputDim[3]; - unsigned int m_Size; - - }; - #endif - /*! * \brief Class implementing a mitk::ImageToImageFilter for BMode filtering on CPU * * The only parameter that needs to be provided is whether it should use a logfilter. * Currently this class only performs an absolute BMode filter. */ class PhotoacousticBModeFilter : public ImageToImageFilter { public: mitkClassMacro(PhotoacousticBModeFilter, ImageToImageFilter); - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); /** \brief Set parameters for the filter * * @param useLogFilter If true, the filter will apply a logfilter on the processed image */ - void SetParameters(bool useLogFilter) + void UseLogFilter(bool useLogFilter) { m_UseLogFilter = useLogFilter; } protected: PhotoacousticBModeFilter(); ~PhotoacousticBModeFilter() override; void GenerateInputRequestedRegion() override; void GenerateOutputInformation() override; void GenerateData() override; //##Description //## @brief Time when Header was last initialized itk::TimeStamp m_TimeOfHeaderInitialization; bool m_UseLogFilter; }; } -#endif +#endif /* _MITKPHOTOACOUSTICSBMODEFILTER_H_ */ diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h index 535b95d21d..7490c71f57 100644 --- a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h @@ -1,154 +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. ===================================================================*/ #ifndef _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ #define _MITKPHOTOACOUSTICSOCLBEAMFORMER_H_ #include #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN #include "mitkOclDataSetToDataSetFilter.h" - +#include "mitkBeamformingSettings.h" #include "mitkPhotoacousticOCLDelayCalculation.h" #include "mitkPhotoacousticOCLUsedLinesCalculation.h" -#include "mitkPhotoacousticBeamformingSettings.h" #include namespace mitk { /*! * \brief Class implementing a mitk::OclDataSetToDataSetFilter for beamforming on GPU * * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::PhotoacousticOCLBeamformingFilter::SetConfig(BeamformingSettings settings) * Additional configuration of the apodisation function is needed. */ -class PhotoacousticOCLBeamformingFilter : public OclDataSetToDataSetFilter, public itk::Object -{ - -public: - mitkClassMacroItkParent(PhotoacousticOCLBeamformingFilter, itk::Object); - itkNewMacro(Self); - - /** - * @brief SetInput Set the input data through an image. Arbitrary images are supported - */ - void SetInput(Image::Pointer image); - /** - * brief SetInput Manually set the input data while providing 3 dimensions and memory size of the input data (Bytes per element). - */ - void SetInput(void* data, unsigned int* dimensions, unsigned int BpE); - /** - * @brief GetOutput Get a pointer to the processed data. The standard datatype is float. - */ - void* GetOutput(); - - /** - * @brief GetOutputAsImage Returns an mitk::Image constructed from the processed data - */ - mitk::Image::Pointer GetOutputAsImage(); - - /** \brief Update the filter */ - void Update(); - - /** \brief Set the Apodisation function to apply when beamforming */ - void SetApodisation(float* apodisation, unsigned short apodArraySize) + class PhotoacousticOCLBeamformingFilter : public OclDataSetToDataSetFilter, public itk::Object { - m_ApodArraySize = apodArraySize; - m_Apodisation = apodisation; - } - - /** \brief Set beamforming settings to use when beamforming */ - void SetConfig(BeamformingSettings settings) - { - m_ConfOld = m_Conf; - m_Conf = settings; - } + public: + mitkClassMacroItkParent(PhotoacousticOCLBeamformingFilter, itk::Object); + mitkNewMacro1Param(Self, BeamformingSettings::Pointer); + + /** + * @brief SetInput Set the input data through an image. Arbitrary images are supported + */ + void SetInput(Image::Pointer image, unsigned int inputSlices); + /** + * brief SetInput Manually set the input data while providing 3 dimensions and memory size of the input data (Bytes per element). + */ + void SetInput(void* data, unsigned int* dimensions, unsigned int BpE); + /** + * @brief GetOutput Get a pointer to the processed data. The standard datatype is float. + */ + void* GetOutput(); + + /** + * @brief GetOutputAsImage Returns an mitk::Image constructed from the processed data + */ + mitk::Image::Pointer GetOutputAsImage(); + + /** \brief Update the filter */ + void Update(); + + /** \brief Set the Apodisation function to apply when beamforming */ + void SetApodisation(const float* apodisation, unsigned short apodArraySize) + { + m_ApodArraySize = apodArraySize; + m_Apodisation = apodisation; + } -protected: + protected: - PhotoacousticOCLBeamformingFilter(); - virtual ~PhotoacousticOCLBeamformingFilter(); + PhotoacousticOCLBeamformingFilter(BeamformingSettings::Pointer settings); + virtual ~PhotoacousticOCLBeamformingFilter(); - /** \brief Initialize the filter */ - bool Initialize(); + /** \brief Initialize the filter */ + bool Initialize(); - /** \brief Updated the used data for beamforming depending on whether the configuration has significantly changed */ - void UpdateDataBuffers(); + /** \brief Updated the used data for beamforming depending on whether the configuration has significantly changed */ + void UpdateDataBuffers(); - /** \brief Execute the filter */ - void Execute(); + /** \brief Execute the filter */ + void Execute(); - mitk::PixelType GetOutputType() - { - return mitk::MakeScalarPixelType(); - } + mitk::PixelType GetOutputType() + { + return mitk::MakeScalarPixelType(); + } - int GetBytesPerElem() - { - return sizeof(float); - } + int GetBytesPerElem() + { + return sizeof(float); + } - virtual us::Module* GetModule(); + virtual us::Module* GetModule(); -private: - /** The OpenCL kernel for the filter */ - cl_kernel m_PixelCalculation; + private: + /** The OpenCL kernel for the filter */ + cl_kernel m_PixelCalculation; - unsigned int m_OutputDim[3]; + unsigned int m_OutputDim[3]; - float* m_Apodisation; - unsigned short m_ApodArraySize; + const float* m_Apodisation; + unsigned short m_ApodArraySize; + unsigned int m_inputSlices; - unsigned short m_PAImage; + unsigned short m_PAImage; - BeamformingSettings m_Conf; - BeamformingSettings m_ConfOld; + BeamformingSettings::Pointer m_Conf; - mitk::Image::Pointer m_InputImage; + mitk::Image::Pointer m_InputImage; - size_t m_ChunkSize[3]; + size_t m_ChunkSize[3]; - mitk::OCLUsedLinesCalculation::Pointer m_UsedLinesCalculation; - mitk::OCLDelayCalculation::Pointer m_DelayCalculation; + mitk::OCLUsedLinesCalculation::Pointer m_UsedLinesCalculation; + mitk::OCLDelayCalculation::Pointer m_DelayCalculation; - cl_mem m_ApodizationBuffer; - cl_mem m_MemoryLocationsBuffer; - cl_mem m_DelaysBuffer; - cl_mem m_UsedLinesBuffer; -}; + cl_mem m_ApodizationBuffer; + cl_mem m_MemoryLocationsBuffer; + cl_mem m_DelaysBuffer; + cl_mem m_UsedLinesBuffer; + }; } #else namespace mitk { class PhotoacousticOCLBeamformingFilter : public itk::Object { public: mitkClassMacroItkParent(mitk::PhotoacousticOCLBeamformingFilter, itk::Object); itkNewMacro(Self); protected: /** Constructor */ PhotoacousticOCLBeamformingFilter() {} /** Destructor */ ~PhotoacousticOCLBeamformingFilter() override {} }; } #endif #endif diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h index 061f7c7448..3e60b4ec5c 100644 --- a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h @@ -1,99 +1,89 @@ /*=================================================================== 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 _MITKPHOTOACOUSTICSDELAYCALC_H_ #define _MITKPHOTOACOUSTICSDELAYCALC_H_ #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN #include "mitkOclDataSetToDataSetFilter.h" #include -#include "mitkPhotoacousticBeamformingSettings.h" +#include "mitkBeamformingSettings.h" namespace mitk { /*! * \brief Class implementing a mitk::OclDataSetToDataSetFilter to calculate the delays used for beamforming. * * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::OCLDelayCalculation::SetConfig(BeamformingSettings conf) * Additionally the output of an instance of mitk::OCLUsedLinesCalculation is needed to calculate the delays. */ class OCLDelayCalculation : public OclDataSetToDataSetFilter, public itk::Object { - public: mitkClassMacroItkParent(OCLDelayCalculation, itk::Object); - itkNewMacro(Self); + mitkNewMacro1Param(Self, mitk::BeamformingSettings::Pointer); void Update(); - /** \brief Sets a new configuration to use. - * - * @param conf The configuration set to use for the calculation of the delays. - */ - void SetConfig(BeamformingSettings conf) - { - m_Conf = conf; - } - /** \brief Sets the usedLines buffer object to use for the calculation of the delays. * * @param usedLines An buffer generated as the output of an instance of mitk::OCLUsedLinesCalculation. */ void SetInputs(cl_mem usedLines) { m_UsedLines = usedLines; } protected: - OCLDelayCalculation(); + OCLDelayCalculation(mitk::BeamformingSettings::Pointer settings); virtual ~OCLDelayCalculation(); /** Initialize the filter */ bool Initialize(); void Execute(); mitk::PixelType GetOutputType() { return mitk::MakeScalarPixelType(); } int GetBytesPerElem() { return sizeof(unsigned short); } virtual us::Module* GetModule(); int m_sizeThis; private: /** The OpenCL kernel for the filter */ cl_kernel m_PixelCalculation; - BeamformingSettings m_Conf; + BeamformingSettings::Pointer m_Conf; cl_mem m_UsedLines; unsigned int m_BufferSize; float m_DelayMultiplicatorRaw; char m_IsPAImage; size_t m_ChunkSize[3]; }; } #endif -#endif \ No newline at end of file +#endif diff --git a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h index e787d2009a..4394764e23 100644 --- a/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h +++ b/Modules/PhotoacousticsAlgorithms/include/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h @@ -1,90 +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 _MITKPHOTOACOUSTICSOCLUSEDLINESCALCULATION_H_ #define _MITKPHOTOACOUSTICSOCLUSEDLINESCALCULATION_H_ #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN #include "mitkOclDataSetToDataSetFilter.h" #include -#include "mitkPhotoacousticBeamformingSettings.h" +#include "mitkBeamformingSettings.h" namespace mitk { /*! * \brief Class implementing a mitk::OclDataSetToDataSetFilter to calculate which lines each sample should use when beamforming. * * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::OCLDelayCalculation::SetConfig(BeamformingSettings conf) */ class OCLUsedLinesCalculation : public OclDataSetToDataSetFilter, public itk::Object { - public: mitkClassMacroItkParent(OCLUsedLinesCalculation, itk::Object); - itkNewMacro(Self); + mitkNewMacro1Param(Self, mitk::BeamformingSettings::Pointer); void Update(); - /** \brief Sets a new configuration to use. - * - * @param conf The configuration set to use for the calculation of the used lines. - */ - void SetConfig(BeamformingSettings conf) - { - m_Conf = conf; - } - protected: /** Constructor */ - OCLUsedLinesCalculation(); + OCLUsedLinesCalculation(mitk::BeamformingSettings::Pointer settings); /** Destructor */ virtual ~OCLUsedLinesCalculation(); /** Initialize the filter */ bool Initialize(); void Execute(); mitk::PixelType GetOutputType() { return mitk::MakeScalarPixelType(); } int GetBytesPerElem() { return sizeof(unsigned short); } virtual us::Module* GetModule(); int m_sizeThis; - private: /** The OpenCL kernel for the filter */ cl_kernel m_PixelCalculation; - BeamformingSettings m_Conf; + BeamformingSettings::Pointer m_Conf; float m_part; size_t m_ChunkSize[3]; }; } #endif #endif diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBandpassFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkBandpassFilter.h new file mode 100644 index 0000000000..375e34ce34 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBandpassFilter.h @@ -0,0 +1,59 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_BANDPASS_FILTER +#define MITK_BANDPASS_FILTER + +#include "mitkImageToImageFilter.h" +#include "MitkPhotoacousticsAlgorithmsExports.h" +#include "mitkPhotoacousticFilterService.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for casting any mitk image to a float image + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT BandpassFilter : public ImageToImageFilter + { + public: + mitkClassMacro(BandpassFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + itkSetMacro(HighPass, float); + itkSetMacro(LowPass, float); + itkSetMacro(HighPassAlpha, float); + itkSetMacro(LowPassAlpha, float); + + protected: + BandpassFilter(); + + ~BandpassFilter() override; + + void SanityCheckPreconditions(); + + float m_HighPass; + float m_LowPass; + float m_HighPassAlpha; + float m_LowPassAlpha; + mitk::PhotoacousticFilterService::Pointer m_FilterService; + + void GenerateData() override; + }; +} // namespace mitk + +#endif //MITK_CAST_TO_FLOAT_IMAGE_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingFilter.h new file mode 100644 index 0000000000..8724808d36 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingFilter.h @@ -0,0 +1,89 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER +#define MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER + +#include "mitkImageToImageFilter.h" +#include +#include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" +#include "mitkBeamformingSettings.h" +#include "mitkBeamformingUtils.h" +#include "MitkPhotoacousticsAlgorithmsExports.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for beamforming on both CPU and GPU + * + * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::BeamformingFilter::Configure(BeamformingSettings settings) + * Whether the GPU is used can be set in the configuration. + * For significant problems or important messages a string is written, which can be accessed via GetMessageString(). + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT BeamformingFilter : public ImageToImageFilter + { + public: + mitkClassMacro(BeamformingFilter, ImageToImageFilter); + + mitkNewMacro1Param(Self, mitk::BeamformingSettings::Pointer); + itkCloneMacro(Self); + + /** \brief Sets a callback for progress checking + * + * An std::function can be set, through which progress of the currently updating filter is reported. + * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. + */ + void SetProgressHandle(std::function progressHandle); + + protected: + BeamformingFilter(mitk::BeamformingSettings::Pointer settings); + + ~BeamformingFilter() override; + + void GenerateInputRequestedRegion() override; + + void GenerateOutputInformation() override; + + void GenerateData() override; + + //##Description + //## @brief Time when Header was last initialized + itk::TimeStamp m_TimeOfHeaderInitialization; + + /** \brief The std::function, through which progress of the currently updating filter is reported. + */ + std::function m_ProgressHandle; + + float* m_OutputData; + float* m_InputData; + float* m_InputDataPuffer; + + /** \brief Current configuration set + */ + BeamformingSettings::Pointer m_Conf; + + /** + * The size of the apodization array when it last changed. + */ + int m_LastApodizationArraySize; + + /** \brief Pointer to the GPU beamforming filter class; for performance reasons the filter is initialized within the constructor and kept for all later computations. + */ + mitk::PhotoacousticOCLBeamformingFilter::Pointer m_BeamformingOclFilter; + }; +} // namespace mitk + +#endif //MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h new file mode 100644 index 0000000000..5b76798dee --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingSettings.h @@ -0,0 +1,223 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_BEAMFORMING_SETTINGS +#define MITK_BEAMFORMING_SETTINGS + +#include +#include +#include +#include + +namespace mitk { + /*! + * \brief Class holding the configuration data for the beamforming filters mitk::BeamformingFilter and mitk::PhotoacousticOCLBeamformingFilter + * + * A detailed description can be seen below. All parameters should be set manually for successfull beamforming. + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT BeamformingSettings : public itk::Object + { + public: + mitkClassMacroItkParent(BeamformingSettings, itk::Object); + mitkNewMacro1Param(BeamformingSettings, std::string); + itkCloneMacro(Self); + + /** \brief Available delay calculation methods: + * - Spherical delay for best results. + * - DEPRECATED quadratic Taylor approximation for slightly faster results with hardly any quality loss. + */ + enum DelayCalc { QuadApprox, Spherical }; + + /** \brief Available apodization functions: + * - Hamming function. + * - Von-Hann function. + * - Box function. + */ + enum Apodization { Hamm, Hann, Box }; + + /** \brief Available beamforming algorithms: + * - DAS (Delay and sum). + * - DMAS (Delay multiply and sum). + */ + enum BeamformingAlgorithm { DMAS, DAS, sDMAS }; + + itkGetConstMacro(PitchInMeters, float); + itkGetConstMacro(SpeedOfSound, float); + itkGetConstMacro(TimeSpacing, float); + itkGetConstMacro(Angle, float); + itkGetConstMacro(IsPhotoacousticImage, bool); + itkGetConstMacro(TransducerElements, unsigned int); + itkGetConstMacro(SamplesPerLine, unsigned int); + itkGetConstMacro(ReconstructionLines, unsigned int); + itkGetConstMacro(InputDim, const unsigned int*); + itkGetConstMacro(UseGPU, bool); + itkGetConstMacro(GPUBatchSize, unsigned int); + itkGetConstMacro(DelayCalculationMethod, DelayCalc); + itkGetConstMacro(ApodizationFunction, const float*); + itkGetConstMacro(Apod, Apodization); + itkGetConstMacro(ApodizationArraySize, int); + itkGetConstMacro(Algorithm, BeamformingAlgorithm); + itkGetConstMacro(ReconstructionDepth, float); + + /** \brief function for mitk::PhotoacousticOCLBeamformingFilter to check whether buffers need to be updated + * this method only checks parameters relevant for the openCL implementation + */ + static bool SettingsChangedOpenCL(const BeamformingSettings::Pointer lhs, const BeamformingSettings::Pointer rhs) + { + return !((abs(lhs->GetAngle() - rhs->GetAngle()) < 0.01f) && // 0.01 degree error margin + (lhs->GetApod() == rhs->GetApod()) && + (lhs->GetDelayCalculationMethod() == rhs->GetDelayCalculationMethod()) && + (lhs->GetIsPhotoacousticImage() == rhs->GetIsPhotoacousticImage()) && + (abs(lhs->GetPitchInMeters() - rhs->GetPitchInMeters()) < 0.000001f) && // 0.0001 mm error margin + (lhs->GetReconstructionLines() == rhs->GetReconstructionLines()) && + (lhs->GetSamplesPerLine() == rhs->GetSamplesPerLine()) && + (lhs->GetReconstructionDepth() == rhs->GetReconstructionDepth()) && + (abs(lhs->GetSpeedOfSound() - rhs->GetSpeedOfSound()) < 0.01f) && + (abs(lhs->GetTimeSpacing() - rhs->GetTimeSpacing()) < 0.00000000001f) && //0.01 ns error margin + (lhs->GetTransducerElements() == rhs->GetTransducerElements())); + } + + static Pointer New(float pitchInMeters, + float speedOfSound, + float timeSpacing, + float angle, + bool isPhotoacousticImage, + unsigned int samplesPerLine, + unsigned int reconstructionLines, + unsigned int* inputDim, + float reconstructionDepth, + bool useGPU, + unsigned int GPUBatchSize, + DelayCalc delayCalculationMethod, + Apodization apod, + unsigned int apodizationArraySize, + BeamformingAlgorithm algorithm) + { + Pointer smartPtr = new BeamformingSettings(pitchInMeters, + speedOfSound, + timeSpacing, + angle, + isPhotoacousticImage, + samplesPerLine, + reconstructionLines, + inputDim, + reconstructionDepth, + useGPU, + GPUBatchSize, + delayCalculationMethod, + apod, + apodizationArraySize, + algorithm); + smartPtr->UnRegister(); + return smartPtr; + } + + protected: + + /** + */ + BeamformingSettings(std::string xmlFile); + + /** + */ + BeamformingSettings(float pitchInMeters, + float speedOfSound, + float timeSpacing, + float angle, + bool isPhotoacousticImage, + unsigned int samplesPerLine, + unsigned int reconstructionLines, + unsigned int* inputDim, + float reconstructionDepth, + bool useGPU, + unsigned int GPUBatchSize, + DelayCalc delayCalculationMethod, + Apodization apod, + unsigned int apodizationArraySize, + BeamformingAlgorithm algorithm + ); + + ~BeamformingSettings(); + + /** \brief Pitch of the used transducer in [m]. + */ + float m_PitchInMeters; + + /** \brief Speed of sound in the used medium in [m/s]. + */ + float m_SpeedOfSound; + + /** \brief The time spacing of the input image + */ + float m_TimeSpacing; // [s] + + /** \brief The angle of the transducer elements + */ + float m_Angle; + + /** \brief Flag whether processed image is a photoacoustic image or an ultrasound image + */ + bool m_IsPhotoacousticImage; + + /** \brief How many transducer elements the used transducer had. + */ + unsigned int m_TransducerElements; + + /** \brief How many vertical samples should be used in the final image. + */ + unsigned int m_SamplesPerLine; + + /** \brief How many lines should be reconstructed in the final image. + */ + unsigned int m_ReconstructionLines; + + /** \brief Sets the dimensions of the inputImage. + */ + const unsigned int* m_InputDim; + + /** \brief The Depth up to which the filter should reconstruct the image [m] + */ + float m_ReconstructionDepth; + + /** \brief Decides whether GPU computing should be used + */ + bool m_UseGPU; + + unsigned int m_GPUBatchSize; + /** \brief Sets the amount of image slices in batches when GPU is used + */ + + /** \brief Sets how the delays for beamforming should be calculated. + */ + DelayCalc m_DelayCalculationMethod; + + const float* m_ApodizationFunction; + + /** \brief Sets the used apodization function. + */ + Apodization m_Apod; + + /** \brief Sets the resolution of the apodization array (must be greater than 0). + */ + int m_ApodizationArraySize; + + /** \brief Sets the used beamforming algorithm. + */ + BeamformingAlgorithm m_Algorithm; + }; +} +#endif //MITK_BEAMFORMING_SETTINGS diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingUtils.h b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingUtils.h new file mode 100644 index 0000000000..9060284cfd --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkBeamformingUtils.h @@ -0,0 +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. + +===================================================================*/ + +#ifndef MITK_BEAMFORMING_FILTER_UTILS +#define MITK_BEAMFORMING_FILTER_UTILS + +#include "mitkImageToImageFilter.h" +#include +#include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" +#include "mitkBeamformingSettings.h" + +namespace mitk { + /*! + * \brief Class implementing util functionality for beamforming on CPU + * + */ + class BeamformingUtils final + { + public: + + /** \brief Function to perform beamforming on CPU for a single line, using DAS and quadratic delay + */ + static void DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Function to perform beamforming on CPU for a single line, using DAS and spherical delay + */ + static void DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Function to perform beamforming on CPU for a single line, using DMAS and quadratic delay + */ + static void DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Function to perform beamforming on CPU for a single line, using DMAS and spherical delay + */ + static void DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and quadratic delay + */ + static void sDMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and spherical delay + */ + static void sDMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, const mitk::BeamformingSettings::Pointer config); + + /** \brief Pointer holding the Von-Hann apodization window for beamforming + * @param samples the resolution at which the window is created + */ + static float* VonHannFunction(int samples); + + /** \brief Function to create a Hamming apodization window + * @param samples the resolution at which the window is created + */ + static float* HammFunction(int samples); + + /** \brief Function to create a Box apodization window + * @param samples the resolution at which the window is created + */ + static float* BoxFunction(int samples); + + protected: + BeamformingUtils(); + + ~BeamformingUtils(); + }; +} // namespace mitk + +#endif //MITK_BEAMFORMING_FILTER_UTILS diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkCastToFloatImageFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkCastToFloatImageFilter.h new file mode 100644 index 0000000000..0a109c5602 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkCastToFloatImageFilter.h @@ -0,0 +1,45 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_CAST_TO_FLOAT_IMAGE_FILTER +#define MITK_CAST_TO_FLOAT_IMAGE_FILTER + +#include "mitkImageToImageFilter.h" +#include "MitkPhotoacousticsAlgorithmsExports.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for casting any mitk image to a float image + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT CastToFloatImageFilter : public ImageToImageFilter + { + public: + mitkClassMacro(CastToFloatImageFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + protected: + CastToFloatImageFilter(); + + ~CastToFloatImageFilter() override; + + void GenerateData() override; + }; +} // namespace mitk + +#endif //MITK_CAST_TO_FLOAT_IMAGE_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkCropImageFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkCropImageFilter.h new file mode 100644 index 0000000000..017cc8327f --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkCropImageFilter.h @@ -0,0 +1,69 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITK_CROP_IMAGE_FILTER +#define MITK_CROP_IMAGE_FILTER + +#include +#include "mitkImageToImageFilter.h" +#include "itkMacro.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for casting any mitk image to a float image + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT CropImageFilter : public ImageToImageFilter + { + public: + mitkClassMacro(CropImageFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + itkGetMacro(XPixelsCropStart, unsigned int); + itkSetMacro(XPixelsCropStart, unsigned int); + itkGetMacro(YPixelsCropStart, unsigned int); + itkSetMacro(YPixelsCropStart, unsigned int); + itkGetMacro(ZPixelsCropStart, unsigned int); + itkSetMacro(ZPixelsCropStart, unsigned int); + + itkGetMacro(XPixelsCropEnd, unsigned int); + itkSetMacro(XPixelsCropEnd, unsigned int); + itkGetMacro(YPixelsCropEnd, unsigned int); + itkSetMacro(YPixelsCropEnd, unsigned int); + itkGetMacro(ZPixelsCropEnd, unsigned int); + itkSetMacro(ZPixelsCropEnd, unsigned int); + + protected: + CropImageFilter(); + + ~CropImageFilter() override; + + void GenerateData() override; + + void SanityCheckPreconditions(); + + unsigned int m_XPixelsCropStart; + unsigned int m_YPixelsCropStart; + unsigned int m_ZPixelsCropStart; + unsigned int m_XPixelsCropEnd; + unsigned int m_YPixelsCropEnd; + unsigned int m_ZPixelsCropEnd; + }; +} // namespace mitk + +#endif //MITK_CROP_IMAGE_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkImageSliceSelectionFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkImageSliceSelectionFilter.h new file mode 100644 index 0000000000..ac51c1176d --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkImageSliceSelectionFilter.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 MITK_IMAGE_SLICE_SELECTION_FILTER +#define MITK_IMAGE_SLICE_SELECTION_FILTER + +#include "mitkImageToImageFilter.h" + +namespace mitk { + /*! + * \brief Class implementing an mitk::ImageToImageFilter for casting any mitk image to a float image + */ + + class ImageSliceSelectionFilter : public ImageToImageFilter + { + public: + mitkClassMacro(ImageSliceSelectionFilter, ImageToImageFilter); + + itkFactorylessNewMacro(Self); + itkCloneMacro(Self); + + protected: + ImageSliceSelectionFilter(); + + ~ImageSliceSelectionFilter() override; + + void GenerateData() override; + }; +} // namespace mitk + +#endif //MITK_IMAGE_SLICE_SELECTION_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h deleted file mode 100644 index 7908fccbae..0000000000 --- a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingFilter.h +++ /dev/null @@ -1,151 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER -#define MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER - -#include "mitkImageToImageFilter.h" -#include -#include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" -#include "mitkPhotoacousticBeamformingSettings.h" - -namespace mitk { - /*! - * \brief Class implementing an mitk::ImageToImageFilter for beamforming on both CPU and GPU - * - * The class must be given a configuration class instance of mitk::BeamformingSettings for beamforming parameters through mitk::BeamformingFilter::Configure(BeamformingSettings settings) - * Whether the GPU is used can be set in the configuration. - * For significant problems or important messages a string is written, which can be accessed via GetMessageString(). - */ - - class BeamformingFilter : public ImageToImageFilter - { - public: - mitkClassMacro(BeamformingFilter, ImageToImageFilter); - - itkFactorylessNewMacro(Self) - itkCloneMacro(Self) - - /** \brief Sets a new configuration to use - * - * @param settings The configuration set to use for beamforming - */ - void Configure(BeamformingSettings settings) - { - m_ConfOld = m_Conf; - m_Conf = settings; - } - - /** \brief Sets a new configuration to use - * - * The Filter writes important messages that can be retrieved through this method; if nothing is to be reported, it returns "noMessage". - * @return The message - */ - std::string GetMessageString() - { - return m_Message; - } - - /** \brief Sets a callback for progress checking - * - * An std::function can be set, through which progress of the currently updating filter is reported. - * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. - */ - void SetProgressHandle(std::function progressHandle); - - protected: - BeamformingFilter(); - - ~BeamformingFilter() override; - - void GenerateInputRequestedRegion() override; - - void GenerateOutputInformation() override; - - void GenerateData() override; - - //##Description - //## @brief Time when Header was last initialized - itk::TimeStamp m_TimeOfHeaderInitialization; - - /** \brief The std::function, through which progress of the currently updating filter is reported. - */ - std::function m_ProgressHandle; - - /** \brief Pointer holding the Von-Hann apodization window for beamforming - * @param samples the resolution at which the window is created - */ - float* VonHannFunction(int samples); - /** \brief Function to create a Hamming apodization window - * @param samples the resolution at which the window is created - */ - float* HammFunction(int samples); - /** \brief Function to create a Box apodization window - * @param samples the resolution at which the window is created - */ - float* BoxFunction(int samples); - - /** \brief Function to perform beamforming on CPU for a single line, using DAS and quadratic delay - */ - void DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - /** \brief Function to perform beamforming on CPU for a single line, using DAS and spherical delay - */ - void DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - /** \brief Function to perform beamforming on CPU for a single line, using DMAS and quadratic delay - */ - void DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - /** \brief Function to perform beamforming on CPU for a single line, using DMAS and spherical delay - */ - void DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and quadratic delay - */ - void sDMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - /** \brief Function to perform beamforming on CPU for a single line, using signed DMAS and spherical delay - */ - void sDMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize); - - float* m_OutputData; - float* m_InputData; - float* m_InputDataPuffer; - - /** \brief Pointer holding the Von-Hann apodization window for beamforming - */ - float* m_VonHannFunction; - /** \brief Pointer holding the Hamming apodization window for beamforming - */ - float* m_HammFunction; - /** \brief Pointer holding the Box apodization window for beamforming - */ - float* m_BoxFunction; - - /** \brief Current configuration set - */ - BeamformingSettings m_Conf; - /** \brief Previous configuration set to selectively update used data for beamforming - */ - BeamformingSettings m_ConfOld; - - /** \brief Pointer to the GPU beamforming filter class; for performance reasons the filter is initialized within the constructor and kept for all later computations. - */ - mitk::PhotoacousticOCLBeamformingFilter::Pointer m_BeamformingOclFilter; - - /** \brief The message returned by mitk::BeamformingFilter::GetMessageString() - */ - std::string m_Message; - }; -} // namespace mitk - -#endif //MITK_PHOTOACOUSTICS_BEAMFORMING_FILTER diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h deleted file mode 100644 index a48b5e78a3..0000000000 --- a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticBeamformingSettings.h +++ /dev/null @@ -1,137 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef MITK_PHOTOACOUSTICS_BEAMFORMING_SETTINGS -#define MITK_PHOTOACOUSTICS_BEAMFORMING_SETTINGS - - - -namespace mitk { - /*! - * \brief Class holding the configuration data for the beamforming filters mitk::BeamformingFilter and mitk::PhotoacousticOCLBeamformingFilter - * - * A detailed description can be seen below. All parameters should be set manually for successfull beamforming. - */ - - class BeamformingSettings - { - public: - /** \brief Pitch of the used transducer in [m]. - */ - float Pitch = 0.0003; - /** \brief Speed of sound in the used medium in [m/s]. - */ - float SpeedOfSound = 1540; - /** \brief This parameter is not neccessary to be set, as it's never used. - */ - float RecordTime = 0.00006; // [s] - /** \brief The time spacing of the input image - */ - float TimeSpacing = 0.0000000000001; // [s] - /** \brief The angle of the transducer elements - */ - float Angle = -1; - /** \brief Flag whether processed image is a photoacoustic image or an ultrasound image - */ - bool isPhotoacousticImage = true; - - /** \brief How many transducer elements the used transducer had. - */ - unsigned short TransducerElements = 128; - /** \brief How many vertical samples should be used in the final image. - */ - unsigned int SamplesPerLine = 2048; - /** \brief How many lines should be reconstructed in the final image. - */ - unsigned int ReconstructionLines = 128; - /** \brief Sets how many voxels should be cut off from the top of the image before beamforming, to potentially avoid artifacts. - */ - unsigned int upperCutoff = 0; - /** \brief Sets whether only the slices selected by mitk::BeamformingSettings::CropBounds should be beamformed. - */ - bool partial = false; - /** \brief Sets the first and last slice to be beamformed. - */ - unsigned int CropBounds[2] = { 0,0 }; - /** \brief Sets the dimensions of the inputImage. - */ - unsigned int inputDim[3] = { 1,1,1 }; - - /** \brief Decides whether GPU computing should be used - */ - bool UseGPU = true; - - /** \brief Available delay calculation methods: - * - Spherical delay for best results. - * - A quadratic Taylor approximation for slightly faster results with hardly any quality loss. - */ - enum DelayCalc { QuadApprox, Spherical }; - /** \brief Sets how the delays for beamforming should be calculated. - */ - DelayCalc DelayCalculationMethod = QuadApprox; - - /** \brief Available apodization functions: - * - Hamming function. - * - Von-Hann function. - * - Box function. - */ - enum Apodization { Hamm, Hann, Box }; - /** \brief Sets the used apodization function. - */ - Apodization Apod = Hann; - /** \brief Sets the resolution of the apodization array (must be greater than 0). - */ - int apodizationArraySize = 128; - - /** \brief Available beamforming algorithms: - * - DAS (Delay and sum). - * - DMAS (Delay multiply and sum). - */ - enum BeamformingAlgorithm { DMAS, DAS, sDMAS}; - /** \brief Sets the used beamforming algorithm. - */ - BeamformingAlgorithm Algorithm = DAS; - - /** \brief Sets whether after beamforming a bandpass should be automatically applied - */ - bool UseBP = false; - /** \brief Sets the position at which lower frequencies are completely cut off in Hz. - */ - float BPHighPass = 50; - /** \brief Sets the position at which higher frequencies are completely cut off in Hz. - */ - float BPLowPass = 50; - - /** \brief function for mitk::PhotoacousticOCLBeamformingFilter to check whether buffers need to be updated - * this method only checks parameters relevant for the openCL implementation - */ - static bool SettingsChangedOpenCL(const BeamformingSettings& lhs, const BeamformingSettings& rhs) - { - return !((abs(lhs.Angle - rhs.Angle) < 0.01f) && // 0.01 degree error margin - (lhs.Apod == rhs.Apod) && - (lhs.DelayCalculationMethod == rhs.DelayCalculationMethod) && - (lhs.isPhotoacousticImage == rhs.isPhotoacousticImage) && - (abs(lhs.Pitch - rhs.Pitch) < 0.000001f) && // 0.0001 mm error margin - (lhs.ReconstructionLines == rhs.ReconstructionLines) && - (abs(lhs.RecordTime - rhs.RecordTime) < 0.00000001f) && // 10 ns error margin - (lhs.SamplesPerLine == rhs.SamplesPerLine) && - (abs(lhs.SpeedOfSound - rhs.SpeedOfSound) < 0.01f) && - (abs(lhs.TimeSpacing - rhs.TimeSpacing) < 0.00000000001f) && //0.01 ns error margin - (lhs.TransducerElements == rhs.TransducerElements)); - } - }; -} -#endif \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h new file mode 100644 index 0000000000..cbe872a42d --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticFilterService.h @@ -0,0 +1,125 @@ +/*=================================================================== + +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 mitkPhotoacousticFilterService_H_HEADER_INCLUDED +#define mitkPhotoacousticFilterService_H_HEADER_INCLUDED + +#include "itkObject.h" +#include "mitkCommon.h" +#include "mitkImage.h" +#include + +#include "mitkBeamformingSettings.h" +#include "mitkBeamformingFilter.h" +#include "MitkPhotoacousticsAlgorithmsExports.h" + +namespace mitk { + /*! + * \brief Class holding methods to apply all Filters within the Photoacoustics Algorithms Module + * + * Implemented are: + * - A B-Mode Filter + * - A Resampling Filter + * - Beamforming on GPU and CPU + * - A Bandpass Filter + */ + + class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticFilterService : public itk::Object + { + public: + mitkClassMacroItkParent(mitk::PhotoacousticFilterService, itk::Object); + itkFactorylessNewMacro(Self); + + /** \brief Defines the methods for the B-Mode filter + * Currently implemented are an Envelope Detection filter and a simple Absolute filter. + */ + enum BModeMethod { EnvelopeDetection, Abs }; + + /** \brief Applies a B-Mode Filter + * + * Applies a B-Mode filter using the given parameters. + * @param inputImage The image to be processed. + * @param method The kind of B-Mode Filter to be used. + * @param UseLogFilter Setting this to true will apply a simple logarithm to the image after the B-Mode Filter has been applied. + * @param resampleSpacing If this is set to 0, nothing will be done; otherwise, the image is resampled to a spacing of resampleSpacing mm per pixel. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, + BModeMethod method = BModeMethod::Abs, + bool UseLogFilter = false); + + /** \brief Resamples the given image + * + * Resamples an image using the given parameters. + * @param inputImage The image to be processed. + * @param outputSize An array of dimensions the image should be resampled to. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, double outputSpacing[2]); + + /** \brief Beamforms the given image + * + * Resamples an image using the given parameters. + * @param inputImage The image to be processed. + * @param config The configuration set to be used for beamforming. + * @param progressHandle An std::function, through which progress of the currently updating filter is reported. + * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings::Pointer config, std::function progressHandle = [](int, std::string) {}); + + /** \brief Crops the given image + * + * Crops an image in 3 dimension using the given parameters. + * @param inputImage The image to be processed. + * @param above How many voxels will be cut from the top of the image. + * @param below How many voxels will be cut from the bottom of the image. + * @param right How many voxels will be cut from the right side of the image. + * @param left How many voxels will be cut from the left side of the image. + * @param minSlice The first slice to be present in the resulting image. + * @param maxSlice The last slice to be present in the resulting image. + * @return The processed image is returned after the filter has finished. For the purposes of this module, the returned image is always of type float. + */ + mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); + + /** \brief Applies a Bandpass filter to the given image + * + * Applies a bandpass filter to the given image using the given parameters. + * @param data The image to be processed. + * @param BPHighPass The position at which Lower frequencies are completely cut off in Hz. + * @param BPLowPass The position at which Higher frequencies are completely cut off in Hz. + * @param alphaHighPass The high pass tukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. + * @param alphaLowPass The low passtukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. + * @return The processed image is returned after the filter has finished. + */ + mitk::Image::Pointer ApplyBandpassFilter(mitk::Image::Pointer data, + float BPHighPass, float BPLowPass, + float alphaHighPass, float alphaLowPass); + + protected: + PhotoacousticFilterService(); + ~PhotoacousticFilterService() override; + + /** \brief + For performance reasons, an instance of the Beamforming filter is initialized as soon as possible and kept for all further uses. + */ + mitk::BeamformingFilter::Pointer m_BeamformingFilter; + + mitk::Image::Pointer ConvertToFloat(mitk::Image::Pointer); + }; +} // namespace mitk + +#endif /* mitkPhotoacousticFilterService_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h deleted file mode 100644 index 404c814412..0000000000 --- a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h +++ /dev/null @@ -1,129 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef mitkPhotoacousticImage_H_HEADER_INCLUDED -#define mitkPhotoacousticImage_H_HEADER_INCLUDED - -#include "itkObject.h" -#include "mitkCommon.h" -#include "mitkImage.h" -#include - -#include "mitkPhotoacousticBeamformingSettings.h" -#include "mitkPhotoacousticBeamformingFilter.h" -#include "MitkPhotoacousticsAlgorithmsExports.h" - -namespace mitk { - /*! - * \brief Class holding methods to apply all Filters within the Photoacoustics Algorithms Module - * - * Implemented are: - * - A B-Mode Filter - * - A Resampling Filter - * - Beamforming on GPU and CPU - * - A Bandpass Filter - */ - - class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object - { - public: - mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); - itkFactorylessNewMacro(Self); - /** \brief Defines the methods for the B-Mode filter - * Currently implemented are an Envelope Detection filter and a simple Absolute filter. - */ - enum BModeMethod { EnvelopeDetection, Abs }; - - /** \brief Applies a B-Mode Filter - * - * Applies a B-Mode filter using the given parameters. - * @param inputImage The image to be processed. - * @param method The kind of B-Mode Filter to be used. - * @param UseGPU Setting this to true will allow the Filter to use the GPU. - * @param UseLogFilter Setting this to true will apply a simple logarithm to the image after the B-Mode Filter has been applied. - * @param resampleSpacing If this is set to 0, nothing will be done; otherwise, the image is resampled to a spacing of resampleSpacing mm per pixel. - * @return The processed image is returned after the filter has finished. - */ - mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseGPU = false, bool UseLogFilter = false, float resampleSpacing = 0.15); - - // mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); - - /** \brief Resamples the given image - * - * Resamples an image using the given parameters. - * @param inputImage The image to be processed. - * @param outputSize An array of dimensions the image should be resampled to. - * @return The processed image is returned after the filter has finished. - */ - mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); - - /** \brief Beamforms the given image - * - * Resamples an image using the given parameters. - * @param inputImage The image to be processed. - * @param config The configuration set to be used for beamforming. - * @param message A string into which potentially critical messages will be written. - * @param progressHandle An std::function, through which progress of the currently updating filter is reported. - * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. - * @return The processed image is returned after the filter has finished. - */ - mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle = [](int, std::string) {}); - - /** \brief Crops the given image - * - * Crops an image in 3 dimension using the given parameters. - * @param inputImage The image to be processed. - * @param above How many voxels will be cut from the top of the image. - * @param below How many voxels will be cut from the bottom of the image. - * @param right How many voxels will be cut from the right side of the image. - * @param left How many voxels will be cut from the left side of the image. - * @param minSlice The first slice to be present in the resulting image. - * @param maxSlice The last slice to be present in the resulting image. - * @return The processed image is returned after the filter has finished. For the purposes of this module, the returned image is always of type float. - */ - mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); - - /** \brief Applies a Bandpass filter to the given image - * - * Applies a bandpass filter to the given image using the given parameters. - * @param data The image to be processed. - * @param recordTime The depth of the image in seconds. - * @param BPHighPass The position at which Lower frequencies are completely cut off in Hz. - * @param BPLowPass The position at which Higher frequencies are completely cut off in Hz. - * @param alpha The tukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. - * @return The processed image is returned after the filter has finished. - */ - mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, - float BPHighPass, float BPLowPass, - float alphaHighPass, float alphaLowPass); - - protected: - PhotoacousticImage(); - ~PhotoacousticImage() override; - - /** \brief For performance reasons, an instance of the Beamforming filter is initialized as soon as possible and kept for all further uses. - */ - mitk::BeamformingFilter::Pointer m_BeamformingFilter; - - /** \brief Function that creates a Tukey function for the bandpass - */ - itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, - int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, - float alphaHighPass, float alphaLowPass); - }; -} // namespace mitk - -#endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp deleted file mode 100644 index 343aecf11a..0000000000 --- a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.cpp +++ /dev/null @@ -1,520 +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 "mitkPhotoacousticImage.h" -#include "ITKFilter/ITKUltrasound/itkBModeImageFilter.h" -#include "ITKFilter/itkPhotoacousticBModeImageFilter.h" -#include "mitkImageCast.h" -#include "mitkITKImageImport.h" -#include "mitkPhotoacousticBeamformingFilter.h" -#include -#include -#include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" - - -// itk dependencies -#include "itkImage.h" -#include "itkResampleImageFilter.h" -#include "itkCastImageFilter.h" -#include "itkCropImageFilter.h" -#include "itkRescaleIntensityImageFilter.h" -#include "itkIntensityWindowingImageFilter.h" -#include -#include "itkMultiplyImageFilter.h" -#include "itkBSplineInterpolateImageFunction.h" -#include - -// needed itk image filters -#include "mitkITKImageImport.h" -#include "itkFFTShiftImageFilter.h" -#include "itkMultiplyImageFilter.h" -#include "itkComplexToModulusImageFilter.h" -#include -#include "ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" -#include "ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" - -mitk::PhotoacousticImage::PhotoacousticImage() -{ - MITK_INFO << "[PhotoacousticImage Debug] created that image"; -} - -mitk::PhotoacousticImage::~PhotoacousticImage() -{ - MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) -{ - // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage - typedef itk::Image< float, 3 > itkFloatImageType; - typedef itk::IdentityTransform TransformType; - - if (method == BModeMethod::Abs) - { - mitk::Image::Pointer input; - mitk::Image::Pointer out; - if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") - input = inputImage; - else - input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); - - if (!UseGPU) - { - PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); - - out = filter->GetOutput(); - - if (resampleSpacing == 0) - return out; - } - #ifdef PHOTOACOUSTICS_USE_GPU - else - { - PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); - - out = filter->GetOutput(); - - if (resampleSpacing == 0) - return out; - } - #endif - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - - itkFloatImageType::Pointer itkImage; - mitk::CastToItkImage(out, itkImage); - itkFloatImageType::SpacingType outputSpacing; - itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSize = inputSize; - - outputSpacing[0] = itkImage->GetSpacing()[0]; - outputSpacing[1] = resampleSpacing; - outputSpacing[2] = itkImage->GetSpacing()[2]; - - outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; - - typedef itk::IdentityTransform TransformType; - resampleImageFilter->SetInput(itkImage); - resampleImageFilter->SetSize(outputSize); - resampleImageFilter->SetOutputSpacing(outputSpacing); - resampleImageFilter->SetTransform(TransformType::New()); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); - } - else if (method == BModeMethod::ShapeDetection) - { - typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; - BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter - - typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; - PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - - itkFloatImageType::Pointer itkImage; - - mitk::CastToItkImage(inputImage, itkImage); - - itkFloatImageType::Pointer bmode; - - if (UseLogFilter) - { - bModeFilter->SetInput(itkImage); - bModeFilter->SetDirection(1); - bmode = bModeFilter->GetOutput(); - } - else - { - photoacousticBModeFilter->SetInput(itkImage); - photoacousticBModeFilter->SetDirection(1); - bmode = photoacousticBModeFilter->GetOutput(); - } - - // resampleSpacing == 0 means: do no resampling - if (resampleSpacing == 0) - { - return mitk::GrabItkImageMemory(bmode); - } - - itkFloatImageType::SpacingType outputSpacing; - itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSize = inputSize; - - outputSpacing[0] = itkImage->GetSpacing()[0]; - outputSpacing[1] = resampleSpacing; - outputSpacing[2] = itkImage->GetSpacing()[2]; - - outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; - - resampleImageFilter->SetInput(bmode); - resampleImageFilter->SetSize(outputSize); - resampleImageFilter->SetOutputSpacing(outputSpacing); - resampleImageFilter->SetTransform(TransformType::New()); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); - } - return nullptr; -} - -/*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) -{ - typedef itk::Image< float, 3 > itkFloatImageType; - typedef itk::MultiplyImageFilter MultiplyImageFilterType; - - itkFloatImageType::Pointer itkImage; - mitk::CastToItkImage(inputImage, itkImage); - - MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); - multiplyFilter->SetInput1(itkImage); - multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); - - return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); -}*/ - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) -{ - typedef itk::Image< float, 3 > itkFloatImageType; - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - typedef itk::LinearInterpolateImageFunction T_Interpolator; - itkFloatImageType::Pointer itkImage; - - mitk::CastToItkImage(inputImage, itkImage); - - itkFloatImageType::SpacingType outputSpacingItk; - itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSizeItk = inputSizeItk; - - outputSizeItk[0] = outputSize[0]; - outputSizeItk[1] = outputSize[1]; - outputSizeItk[2] = inputSizeItk[2]; - - outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); - outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); - outputSpacingItk[2] = itkImage->GetSpacing()[2]; - - typedef itk::IdentityTransform TransformType; - T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); - resampleImageFilter->SetInput(itkImage); - resampleImageFilter->SetSize(outputSizeItk); - resampleImageFilter->SetOutputSpacing(outputSpacingItk); - resampleImageFilter->SetTransform(TransformType::New()); - resampleImageFilter->SetInterpolator(_pInterpolator); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) -{ - - unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; - unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; - - void* inputData; - float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; - - ImageReadAccessor acc(inputImage); - inputData = const_cast(acc.GetData()); - - // convert the data to float by default - // as of now only those float, short, float are used at all... though it's easy to add other ones - if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") - { - // copy the data into the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") - { - // copy the data unsigned shorto the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") - { - // copy the data unsigned shorto the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else - { - MITK_INFO << "Could not determine pixel type"; - } - - mitk::Image::Pointer output = mitk::Image::New(); - output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); - output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); - output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); - - return output; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, int cutoff, std::function progressHandle) -{ - config.RecordTime = config.RecordTime - (cutoff) / inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping - progressHandle(0, "cropping image"); - if (!config.partial) - { - config.CropBounds[0] = 0; - config.CropBounds[1] = inputImage->GetDimension(2) - 1; - } - - Image::Pointer processedImage = ApplyCropping(inputImage, cutoff, 0, 0, 0, config.CropBounds[0], config.CropBounds[1]); - config.inputDim[0] = processedImage->GetDimension(0); - config.inputDim[1] = processedImage->GetDimension(1); - config.inputDim[2] = processedImage->GetDimension(2); - - // perform the beamforming - BeamformingFilter::Pointer Beamformer = BeamformingFilter::New(); - Beamformer->SetInput(processedImage); - Beamformer->Configure(config); - Beamformer->SetProgressHandle(progressHandle); - Beamformer->UpdateLargestPossibleRegion(); - - processedImage = Beamformer->GetOutput(); - - return processedImage; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha) -{ - bool powerOfTwo = false; - int finalPower = 0; - for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) - { - finalPower = i; - if (pow(2, i) == data->GetDimension(1)) - { - powerOfTwo = true; - } - } - if (!powerOfTwo) - { - unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; - data = ApplyResampling(data, dim); - } - - MITK_INFO << data->GetDimension(0); - - // do a fourier transform, multiply with an appropriate window for the filter, and transform back - typedef float PixelType; - typedef itk::Image< PixelType, 3 > RealImageType; - RealImageType::Pointer image; - - mitk::CastToItkImage(data, image); - - typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; - typedef ForwardFFTFilterType::OutputImageType ComplexImageType; - ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); - forwardFFTFilter->SetInput(image); - forwardFFTFilter->SetDirection(1); - try - { - forwardFFTFilter->UpdateOutputInformation(); - } - catch (itk::ExceptionObject & error) - { - std::cerr << "Error: " << error << std::endl; - MITK_WARN << "Bandpass could not be applied"; - return data; - } - - float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; - float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); - float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); - - RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alpha); - - typedef itk::MultiplyImageFilter< ComplexImageType, - RealImageType, - ComplexImageType > - MultiplyFilterType; - MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); - multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); - multiplyFilter->SetInput2(fftMultiplicator); - - /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); - toReal->SetInput(forwardFFTFilter->GetOutput()); - return GrabItkImageMemory(toReal->GetOutput()); - return GrabItkImageMemory(fftMultiplicator); *///DEBUG - - typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; - InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); - inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); - inverseFFTFilter->SetDirection(1); - - return GrabItkImageMemory(inverseFFTFilter->GetOutput()); -} - -itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha) -{ - float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; - - // tukey window - float width = reference->GetDimension(1) / 2 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; - float center = (float)cutoffFrequencyPixelHighPass / 2 + width / 2; - - - MITK_INFO << width << "width " << center << "center " << alpha; - - for (unsigned int n = 0; n < reference->GetDimension(1); ++n) - { - imageData[reference->GetDimension(0)*n] = 0; - } - - for (int n = 0; n < width; ++n) - { - if (n <= (alpha*(width - 1)) / 2) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alpha*(width - 1)) - 1))) / 2; - } - else if (n >= (width - 1)*(1 - alpha / 2) && n <= (width - 1)) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; - } - else - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; - } - } - - // Butterworth-Filter - /* - // first, write the HighPass - if (cutoffFrequencyPixelHighPass != reference->GetDimension(1) / 2) - { - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) - { - imageData[reference->GetDimension(0)*n] = 1 / (1 + pow( - (float)n / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelHighPass) - , 2 * butterworthOrder)); - } - } - else - { - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) - { - imageData[reference->GetDimension(0)*n] = 1; - } - } - - // now, the LowPass - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) - { - imageData[reference->GetDimension(0)*n] *= 1 / (1 + pow( - (float)(reference->GetDimension(1) / 2 - 1 - n) / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelLowPass) - , 2 * butterworthOrder)); - } - */ - - // mirror the first half of the image - for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) - { - imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; - } - - - // copy and paste to all lines - for (unsigned int line = 1; line < reference->GetDimension(0); ++line) - { - for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) - { - imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; - } - } - - typedef itk::Image< float, 3U > ImageType; - ImageType::RegionType region; - ImageType::IndexType start; - start.Fill(0); - - region.SetIndex(start); - - ImageType::SizeType size; - size[0] = reference->GetDimension(0); - size[1] = reference->GetDimension(1); - size[2] = reference->GetDimension(2); - - region.SetSize(size); - - ImageType::SpacingType SpacingItk; - SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; - SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; - SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; - - ImageType::Pointer image = ImageType::New(); - image->SetRegions(region); - image->Allocate(); - image->FillBuffer(itk::NumericTraits::Zero); - image->SetSpacing(SpacingItk); - - ImageType::IndexType pixelIndex; - - for (ImageType::IndexValueType slice = 0; slice < reference->GetDimension(2); ++slice) - { - for (ImageType::IndexValueType line = 0; line < reference->GetDimension(0); ++line) - { - for (ImageType::IndexValueType sample = 0; sample < reference->GetDimension(1); ++sample) - { - pixelIndex[0] = line; - pixelIndex[1] = sample; - pixelIndex[2] = slice; - - image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); - } - } - } - - delete[] imageData; - - return image; -} \ No newline at end of file diff --git a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h deleted file mode 100644 index 2200124e8d..0000000000 --- a/Modules/PhotoacousticsAlgorithms/mitkPhotoacousticImage.h +++ /dev/null @@ -1,50 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef mitkPhotoacousticImage_H_HEADER_INCLUDED -#define mitkPhotoacousticImage_H_HEADER_INCLUDED - -#include "itkObject.h" -#include "mitkCommon.h" -#include "mitkImage.h" -#include - -#include "mitkPhotoacousticBeamformingFilter.h" -#include "MitkPhotoacousticsAlgorithmsExports.h" - -namespace mitk { - - class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object - { - public: - mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); - itkFactorylessNewMacro(Self); - enum BModeMethod { ShapeDetection, Abs }; - mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseGPU = false, bool UseLogFilter = false, float resampleSpacing = 0.15); -// mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); - mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); - mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, int cutoff, std::function progressHandle = [](int, std::string) {}); - mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); - mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha); - protected: - PhotoacousticImage(); - virtual ~PhotoacousticImage(); - - itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha); - }; -} // namespace mitk - -#endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp index f9db6a7105..8408229d5a 100644 --- a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticBModeFilter.cpp @@ -1,221 +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. ===================================================================*/ #include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" #include "usServiceReference.h" #include -#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN - -mitk::PhotoacousticOCLBModeFilter::PhotoacousticOCLBModeFilter() - : m_PixelCalculation(NULL) -{ - this->AddSourceFile("BModeAbs.cl"); - this->AddSourceFile("BModeAbsLog.cl"); - - this->m_FilterID = "BModeFilter"; - - this->Initialize(); -} - -mitk::PhotoacousticOCLBModeFilter::~PhotoacousticOCLBModeFilter() -{ - if (this->m_PixelCalculation) - { - clReleaseKernel(m_PixelCalculation); - } -} - -void mitk::PhotoacousticOCLBModeFilter::Update() -{ - //Check if context & program available - if (!this->Initialize()) - { - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - - // clean-up also the resources - resources->InvalidateStorage(); - mitkThrow() << "Filter is not initialized. Cannot update."; - } - else { - // Execute - this->Execute(); - } -} - -void mitk::PhotoacousticOCLBModeFilter::Execute() -{ - try - { - size_t outputSize = m_InputDim[0] * m_InputDim[1] * m_InputDim[2]; - this->InitExec(this->m_PixelCalculation, m_InputDim, outputSize, sizeof(float)); - } - catch (const mitk::Exception& e) - { - MITK_ERROR << "Catched exception while initializing filter: " << e.what(); - return; - } - - cl_int clErr; - clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Size)); - - CHECK_OCL_ERR(clErr); - - // execute the filter on a 3D NDRange - this->ExecuteKernel(m_PixelCalculation, 3); - - // signalize the GPU-side data changed - m_Output->Modified(GPU_DATA); -} - -us::Module *mitk::PhotoacousticOCLBModeFilter::GetModule() -{ - return us::GetModuleContext()->GetModule(); -} - -bool mitk::PhotoacousticOCLBModeFilter::Initialize() -{ - bool buildErr = true; - cl_int clErr = 0; - - if (OclFilter::Initialize()) - { - if(m_UseLogFilter) - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbsLog", &clErr); - else - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckBmodeAbs", &clErr); - buildErr |= CHECK_OCL_ERR(clErr); - } - return (OclFilter::IsInitialized() && buildErr); -} - -void mitk::PhotoacousticOCLBModeFilter::SetInput(mitk::Image::Pointer image) -{ - OclDataSetToDataSetFilter::SetInput(image); - - m_InputImage = image; - m_InputDim[0] = m_InputImage->GetDimension(0); - m_InputDim[1] = m_InputImage->GetDimension(1); - m_InputDim[2] = m_InputImage->GetDimension(2); - m_Size = m_InputDim[0] * m_InputDim[1] * m_InputDim[2]; -} - -mitk::Image::Pointer mitk::PhotoacousticOCLBModeFilter::GetOutput() -{ - mitk::Image::Pointer outputImage = mitk::Image::New(); - - if (m_Output->IsModified(GPU_DATA)) - { - void* pData = m_Output->TransferDataToCPU(m_CommandQue); - - const unsigned int dimension = 3; - unsigned int dimensions[3] = { m_InputDim[0], m_InputDim[1], m_InputDim[2] }; - - const mitk::SlicedGeometry3D::Pointer p_slg = m_InputImage->GetSlicedGeometry(); - - MITK_DEBUG << "Creating new MITK Image."; - - outputImage->Initialize(this->GetOutputType(), dimension, dimensions); - outputImage->SetSpacing(p_slg->GetSpacing()); - outputImage->SetGeometry(m_InputImage->GetGeometry()); - outputImage->SetImportVolume(pData, 0, 0, mitk::Image::ReferenceMemory); - } - - MITK_DEBUG << "Image Initialized."; - - return outputImage; -} - -#endif - - mitk::PhotoacousticBModeFilter::PhotoacousticBModeFilter() : m_UseLogFilter(false) { this->SetNumberOfIndexedInputs(1); this->SetNumberOfRequiredInputs(1); } mitk::PhotoacousticBModeFilter::~PhotoacousticBModeFilter() { } void mitk::PhotoacousticBModeFilter::GenerateInputRequestedRegion() { Superclass::GenerateInputRequestedRegion(); - mitk::Image* output = this->GetOutput(); - mitk::Image* input = const_cast (this->GetInput()); + mitk::Image::Pointer output = this->GetOutput(); + mitk::Image::Pointer input = this->GetInput(); + if (!output->IsInitialized()) - { return; - } input->SetRequestedRegionToLargestPossibleRegion(); - - //GenerateTimeInInputRegion(output, input); } void mitk::PhotoacousticBModeFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) return; - itkDebugMacro(<< "GenerateOutputInformation()"); - - output->Initialize(input); + output->Initialize(input->GetPixelType(), input->GetDimension(), input->GetDimensions()); output->GetGeometry()->SetSpacing(input->GetGeometry()->GetSpacing()); output->GetGeometry()->Modified(); output->SetPropertyList(input->GetPropertyList()->Clone()); m_TimeOfHeaderInitialization.Modified(); } void mitk::PhotoacousticBModeFilter::GenerateData() { GenerateOutputInformation(); mitk::Image::Pointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if (!output->IsInitialized()) return; mitk::ImageReadAccessor reader(input); unsigned int size = output->GetDimension(0) * output->GetDimension(1) * output->GetDimension(2); - float* InputData = (float*)const_cast(reader.GetData()); + const float* InputData = (const float*)(reader.GetData()); float* OutputData = new float[size]; - if(!m_UseLogFilter) + if (!m_UseLogFilter) for (unsigned int i = 0; i < size; ++i) { OutputData[i] = abs(InputData[i]); } else { for (unsigned int i = 0; i < size; ++i) { OutputData[i] = log(abs(InputData[i])); } } - output->SetImportVolume(OutputData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); - + output->SetImportVolume(OutputData, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + delete[] OutputData; m_TimeOfHeaderInitialization.Modified(); -} \ No newline at end of file +} diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp index 575c29b240..3c3759fe24 100644 --- a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.cpp @@ -1,264 +1,259 @@ /*=================================================================== 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(PHOTOACOUSTICS_USE_GPU) || DOXYGEN #include "./OpenCLFilter/mitkPhotoacousticOCLBeamformingFilter.h" #include "usServiceReference.h" -mitk::PhotoacousticOCLBeamformingFilter::PhotoacousticOCLBeamformingFilter() -: m_PixelCalculation( NULL ), m_InputImage(mitk::Image::New()), m_ApodizationBuffer(nullptr), m_MemoryLocationsBuffer(nullptr), m_DelaysBuffer(nullptr), m_UsedLinesBuffer(nullptr) +mitk::PhotoacousticOCLBeamformingFilter::PhotoacousticOCLBeamformingFilter(BeamformingSettings::Pointer settings) : + m_PixelCalculation(NULL), + m_inputSlices(1), + m_Conf(settings), + m_InputImage(mitk::Image::New()), + m_ApodizationBuffer(nullptr), + m_MemoryLocationsBuffer(nullptr), + m_DelaysBuffer(nullptr), + m_UsedLinesBuffer(nullptr) { + MITK_INFO << "Instantiating OCL beamforming Filter..."; this->AddSourceFile("DAS.cl"); this->AddSourceFile("DMAS.cl"); this->AddSourceFile("sDMAS.cl"); this->m_FilterID = "OpenCLBeamformingFilter"; this->Initialize(); unsigned int dim[] = { 128, 2048, 2 }; - mitk::Vector3D spacing; - spacing[0] = 1; - spacing[1] = 1; - spacing[2] = 1; - m_InputImage->Initialize(mitk::MakeScalarPixelType(), 3, dim); - m_InputImage->SetSpacing(spacing); m_ChunkSize[0] = 128; m_ChunkSize[1] = 128; m_ChunkSize[2] = 8; - m_UsedLinesCalculation = mitk::OCLUsedLinesCalculation::New(); - m_DelayCalculation = mitk::OCLDelayCalculation::New(); + m_UsedLinesCalculation = mitk::OCLUsedLinesCalculation::New(m_Conf); + m_DelayCalculation = mitk::OCLDelayCalculation::New(m_Conf); + MITK_INFO << "Instantiating OCL beamforming Filter...[Done]"; } mitk::PhotoacousticOCLBeamformingFilter::~PhotoacousticOCLBeamformingFilter() { - if ( this->m_PixelCalculation ) + if (this->m_PixelCalculation) { - clReleaseKernel( m_PixelCalculation ); + clReleaseKernel(m_PixelCalculation); } if (m_ApodizationBuffer) clReleaseMemObject(m_ApodizationBuffer); } void mitk::PhotoacousticOCLBeamformingFilter::Update() { //Check if context & program available if (!this->Initialize()) { us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); // clean-up also the resources resources->InvalidateStorage(); - mitkThrow() <<"Filter is not initialized. Cannot update."; + mitkThrow() << "Filter is not initialized. Cannot update."; } - else{ + else { // Execute this->Execute(); } } void mitk::PhotoacousticOCLBeamformingFilter::UpdateDataBuffers() { /*us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); cl_ulong globalMemSize = oclGetGlobalMemSize(resources->GetCurrentDevice());*/ //Initialize the Output try { - MITK_DEBUG << "Updating Workgroup size for new dimensions"; - size_t outputSize = (size_t)m_Conf.ReconstructionLines * (size_t)m_Conf.SamplesPerLine * (size_t)m_Conf.inputDim[2]; - m_OutputDim[0] = m_Conf.ReconstructionLines; - m_OutputDim[1] = m_Conf.SamplesPerLine; - m_OutputDim[2] = m_Conf.inputDim[2]; + size_t outputSize = (size_t)m_Conf->GetReconstructionLines() * (size_t)m_Conf->GetSamplesPerLine() * + (size_t)m_inputSlices; + m_OutputDim[0] = m_Conf->GetReconstructionLines(); + m_OutputDim[1] = m_Conf->GetSamplesPerLine(); + m_OutputDim[2] = m_inputSlices; this->InitExec(this->m_PixelCalculation, m_OutputDim, outputSize, sizeof(float)); } catch (const mitk::Exception& e) { MITK_ERROR << "Caught exception while initializing filter: " << e.what(); return; } - if (BeamformingSettings::SettingsChangedOpenCL(m_Conf, m_ConfOld)) - { - cl_int clErr = 0; - MITK_DEBUG << "Updating GPU Buffers for new configuration"; + //TODO FIXME + cl_int clErr = 0; + MITK_DEBUG << "Updating GPU Buffers for new configuration"; - // create the apodisation buffer + // create the apodisation buffer - if (m_Apodisation == nullptr) - { - MITK_INFO << "No apodisation function set; Beamforming will be done without any apodisation."; - m_Apodisation = new float[1]; - m_Apodisation[0] = 1; - m_ApodArraySize = 1; - } + if (m_Apodisation == nullptr) + { + MITK_INFO << "No apodisation function set; Beamforming will be done without any apodisation."; + m_Apodisation = new float[1]{ 1 }; + m_ApodArraySize = 1; + } - us::ServiceReference ref = GetModuleContext()->GetServiceReference(); - OclResourceService* resources = GetModuleContext()->GetService(ref); - cl_context gpuContext = resources->GetContext(); + us::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + cl_context gpuContext = resources->GetContext(); - if (m_ApodizationBuffer) clReleaseMemObject(m_ApodizationBuffer); + if (m_ApodizationBuffer) clReleaseMemObject(m_ApodizationBuffer); - this->m_ApodizationBuffer = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * m_ApodArraySize, m_Apodisation, &clErr); - CHECK_OCL_ERR(clErr); + this->m_ApodizationBuffer = clCreateBuffer(gpuContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, sizeof(float) * m_ApodArraySize, const_cast(m_Apodisation), &clErr); + CHECK_OCL_ERR(clErr); - // calculate used lines + // calculate used lines - m_UsedLinesCalculation->SetConfig(m_Conf); - m_UsedLinesCalculation->Update(); - m_UsedLinesBuffer = m_UsedLinesCalculation->GetGPUOutput()->GetGPUBuffer(); + m_UsedLinesCalculation->Update(); + m_UsedLinesBuffer = m_UsedLinesCalculation->GetGPUOutput()->GetGPUBuffer(); - // calculate the Delays - m_DelayCalculation->SetConfig(m_Conf); - m_DelayCalculation->SetInputs(m_UsedLinesBuffer); - m_DelayCalculation->Update(); + // calculate the Delays + m_DelayCalculation->SetInputs(m_UsedLinesBuffer); + m_DelayCalculation->Update(); - m_DelaysBuffer = m_DelayCalculation->GetGPUOutput()->GetGPUBuffer(); + m_DelaysBuffer = m_DelayCalculation->GetGPUOutput()->GetGPUBuffer(); - m_ConfOld = m_Conf; - } + //m_ConfOld = m_Conf; } void mitk::PhotoacousticOCLBeamformingFilter::Execute() { cl_int clErr = 0; UpdateDataBuffers(); + unsigned int reconstructionLines = this->m_Conf->GetReconstructionLines(); + unsigned int samplesPerLine = this->m_Conf->GetSamplesPerLine(); + clErr = clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_mem), &(this->m_UsedLinesBuffer)); clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_mem), &(this->m_DelaysBuffer)); clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_mem), &(this->m_ApodizationBuffer)); clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_ushort), &(this->m_ApodArraySize)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 8, sizeof(cl_uint), &(this->m_Conf.inputDim[2])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 9, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 10, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 8, sizeof(cl_uint), &(m_OutputDim[2])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 9, sizeof(cl_uint), &(reconstructionLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 10, sizeof(cl_uint), &(samplesPerLine)); - // execute the filter on a 3D NDRange + // execute the filter on a 2D/3D NDRange if (m_OutputDim[2] == 1 || m_ChunkSize[2] == 1) { - if(!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) + if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) mitkThrow() << "openCL Error when executing Kernel"; } else { - if(!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 3, m_ChunkSize, 16, 50)) + if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 3, m_ChunkSize, 16, 50)) mitkThrow() << "openCL Error when executing Kernel"; } // signalize the GPU-side data changed - m_Output->Modified( GPU_DATA ); + m_Output->Modified(GPU_DATA); } us::Module *mitk::PhotoacousticOCLBeamformingFilter::GetModule() { return us::GetModuleContext()->GetModule(); } bool mitk::PhotoacousticOCLBeamformingFilter::Initialize() { bool buildErr = true; cl_int clErr = 0; - if ( OclFilter::Initialize() ) + if (OclFilter::Initialize()) { - switch (m_Conf.Algorithm) + switch (m_Conf->GetAlgorithm()) + { + case BeamformingSettings::BeamformingAlgorithm::DAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); + break; + } + case BeamformingSettings::BeamformingAlgorithm::DMAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMAS", &clErr); + break; + } + case BeamformingSettings::BeamformingAlgorithm::sDMAS: + { + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "cksDMAS", &clErr); + break; + } + default: { - case BeamformingSettings::BeamformingAlgorithm::DAS: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); - break; - } - case BeamformingSettings::BeamformingAlgorithm::DMAS: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDMAS", &clErr); - break; - } - case BeamformingSettings::BeamformingAlgorithm::sDMAS: - { - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "cksDMAS", &clErr); - break; - } - default: - { - MITK_INFO << "No beamforming algorithm specified, setting to DAS"; - this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); - break; - } + MITK_INFO << "No beamforming algorithm specified, setting to DAS"; + this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDAS", &clErr); + break; } - buildErr |= CHECK_OCL_ERR( clErr ); + } + buildErr |= CHECK_OCL_ERR(clErr); } CHECK_OCL_ERR(clErr); - return (OclFilter::IsInitialized() && buildErr ); + return (OclFilter::IsInitialized() && buildErr); } -void mitk::PhotoacousticOCLBeamformingFilter::SetInput(mitk::Image::Pointer image) +void mitk::PhotoacousticOCLBeamformingFilter::SetInput(mitk::Image::Pointer image, unsigned int inputSlices) { OclDataSetToDataSetFilter::SetInput(image); - m_InputImage = image; - m_Conf.inputDim[0] = m_InputImage->GetDimension(0); - m_Conf.inputDim[1] = m_InputImage->GetDimension(1); - m_Conf.inputDim[2] = m_InputImage->GetDimension(2); + m_inputSlices = inputSlices; } void mitk::PhotoacousticOCLBeamformingFilter::SetInput(void* data, unsigned int* dimensions, unsigned int BpE) { OclDataSetToDataSetFilter::SetInput(data, dimensions[0] * dimensions[1] * dimensions[2], BpE); - - m_Conf.inputDim[0] = dimensions[0]; - m_Conf.inputDim[1] = dimensions[1]; - m_Conf.inputDim[2] = dimensions[2]; } mitk::Image::Pointer mitk::PhotoacousticOCLBeamformingFilter::GetOutputAsImage() { mitk::Image::Pointer outputImage = mitk::Image::New(); if (m_Output->IsModified(GPU_DATA)) { void* pData = m_Output->TransferDataToCPU(m_CommandQue); const unsigned int dimension = 3; unsigned int dimensions[3] = { (unsigned int)m_OutputDim[0], (unsigned int)m_OutputDim[1], (unsigned int)m_OutputDim[2] }; const mitk::SlicedGeometry3D::Pointer p_slg = m_InputImage->GetSlicedGeometry(); MITK_DEBUG << "Creating new MITK Image."; outputImage->Initialize(this->GetOutputType(), dimension, dimensions); outputImage->SetSpacing(p_slg->GetSpacing()); - outputImage->SetImportVolume(pData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); + outputImage->SetImportVolume(pData, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + free(pData); } MITK_DEBUG << "Image Initialized."; return outputImage; } void* mitk::PhotoacousticOCLBeamformingFilter::GetOutput() { return OclDataSetToDataSetFilter::GetOutput(); } #endif diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp index bbee18bc42..cc236090bc 100644 --- a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.cpp @@ -1,125 +1,136 @@ /*=================================================================== 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 #include "./OpenCLFilter/mitkPhotoacousticOCLDelayCalculation.h" #include "usServiceReference.h" #include "mitkImageReadAccessor.h" -mitk::OCLDelayCalculation::OCLDelayCalculation() - : m_PixelCalculation(NULL) +mitk::OCLDelayCalculation::OCLDelayCalculation(mitk::BeamformingSettings::Pointer settings) + : m_PixelCalculation(NULL), + m_Conf(settings) { this->AddSourceFile("DelayCalculation.cl"); this->m_FilterID = "DelayCalculation"; m_ChunkSize[0] = 128; m_ChunkSize[1] = 128; m_ChunkSize[2] = 8; this->Initialize(); } mitk::OCLDelayCalculation::~OCLDelayCalculation() { if (this->m_PixelCalculation) { clReleaseKernel(m_PixelCalculation); } } void mitk::OCLDelayCalculation::Update() { //Check if context & program available if (!this->Initialize()) { us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); // clean-up also the resources resources->InvalidateStorage(); mitkThrow() << "Filter is not initialized. Cannot update."; } else { // Execute this->Execute(); } } void mitk::OCLDelayCalculation::Execute() { cl_int clErr = 0; - - unsigned int gridDim[3] = { m_Conf.ReconstructionLines / 2, m_Conf.SamplesPerLine, 1 }; + + unsigned int gridDim[3] = { m_Conf->GetReconstructionLines() / 2, m_Conf->GetSamplesPerLine(), 1 }; m_BufferSize = gridDim[0] * gridDim[1] * 1; try { this->InitExecNoInput(this->m_PixelCalculation, gridDim, m_BufferSize, sizeof(unsigned short)); } catch (const mitk::Exception& e) { MITK_ERROR << "Caught exception while initializing Delay Calculation filter: " << e.what(); return; } // This calculation is the same for all kernels, so for performance reasons simply perform it here instead of within the kernels - if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) - m_DelayMultiplicatorRaw = pow(1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * m_Conf.Pitch * (float)m_Conf.TransducerElements / (float)m_Conf.inputDim[0], 2) / 2; - else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) - m_DelayMultiplicatorRaw = 1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*(float)m_Conf.TransducerElements); + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::QuadApprox) + m_DelayMultiplicatorRaw = pow(1 / (m_Conf->GetTimeSpacing()*m_Conf->GetSpeedOfSound()) * + m_Conf->GetPitchInMeters() * (float)m_Conf->GetTransducerElements() / (float)m_Conf->GetInputDim()[0], 2) / 2; + else if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::Spherical) + m_DelayMultiplicatorRaw = 1 / (m_Conf->GetTimeSpacing()*m_Conf->GetSpeedOfSound()) * + (m_Conf->GetPitchInMeters()*(float)m_Conf->GetTransducerElements()); // as openCL does not support bool as a kernel argument, we need to buffer this value in a char... - m_IsPAImage = m_Conf.isPhotoacousticImage; - + m_IsPAImage = m_Conf->GetIsPhotoacousticImage(); + + unsigned int reconstructionLines = this->m_Conf->GetReconstructionLines(); + unsigned int samplesperLine = this->m_Conf->GetSamplesPerLine(); + + float percentOfImageReconstructed = (float)(m_Conf->GetReconstructionDepth()) / + (float)(m_Conf->GetInputDim()[1] * m_Conf->GetSpeedOfSound() * m_Conf->GetTimeSpacing() / (float)(2 - (int)m_Conf->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + clErr = clSetKernelArg(this->m_PixelCalculation, 1, sizeof(cl_mem), &(this->m_UsedLines)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(reconstructionLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(samplesperLine)); clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_char), &(this->m_IsPAImage)); clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_float), &(this->m_DelayMultiplicatorRaw)); - + clErr |= clSetKernelArg(this->m_PixelCalculation, 8, sizeof(cl_float), &(percentOfImageReconstructed)); + CHECK_OCL_ERR(clErr); // execute the filter on a 3D NDRange if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) mitkThrow() << "openCL Error when executing Kernel"; // signalize the GPU-side data changed m_Output->Modified(GPU_DATA); } us::Module *mitk::OCLDelayCalculation::GetModule() { return us::GetModuleContext()->GetModule(); } bool mitk::OCLDelayCalculation::Initialize() { bool buildErr = true; cl_int clErr = 0; if (OclFilter::Initialize()) { - if(m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::QuadApprox) this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDelayCalculationQuad", &clErr); - if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::Spherical) this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckDelayCalculationSphe", &clErr); buildErr |= CHECK_OCL_ERR(clErr); } return (OclFilter::IsInitialized() && buildErr); -} \ No newline at end of file +} diff --git a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp index 08f79410c3..dda6a3eef9 100644 --- a/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.cpp @@ -1,114 +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. ===================================================================*/ #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN #include "./OpenCLFilter/mitkPhotoacousticOCLUsedLinesCalculation.h" #include "usServiceReference.h" #include "mitkImageReadAccessor.h" -mitk::OCLUsedLinesCalculation::OCLUsedLinesCalculation() - : m_PixelCalculation(NULL) +mitk::OCLUsedLinesCalculation::OCLUsedLinesCalculation(mitk::BeamformingSettings::Pointer settings) + : m_PixelCalculation(NULL), + m_Conf(settings) { this->AddSourceFile("UsedLinesCalculation.cl"); this->m_FilterID = "UsedLinesCalculation"; m_ChunkSize[0] = 128; m_ChunkSize[1] = 128; m_ChunkSize[2] = 8; this->Initialize(); } mitk::OCLUsedLinesCalculation::~OCLUsedLinesCalculation() { if (this->m_PixelCalculation) { clReleaseKernel(m_PixelCalculation); } } void mitk::OCLUsedLinesCalculation::Update() { //Check if context & program available if (!this->Initialize()) { us::ServiceReference ref = GetModuleContext()->GetServiceReference(); OclResourceService* resources = GetModuleContext()->GetService(ref); // clean-up also the resources resources->InvalidateStorage(); mitkThrow() << "Filter is not initialized. Cannot update."; } else { // Execute this->Execute(); } } void mitk::OCLUsedLinesCalculation::Execute() { cl_int clErr = 0; - unsigned int gridDim[3] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, 1 }; + unsigned int gridDim[3] = { m_Conf->GetReconstructionLines(), m_Conf->GetSamplesPerLine(), 1 }; size_t outputSize = gridDim[0] * gridDim[1] * 3; try { this->InitExecNoInput(this->m_PixelCalculation, gridDim, outputSize, sizeof(unsigned short)); } catch (const mitk::Exception& e) { MITK_ERROR << "Caught exception while initializing UsedLines filter: " << e.what(); return; } // This calculation is the same for all kernels, so for performance reasons simply perform it here instead of within the kernels - m_part = (tan(m_Conf.Angle / 360 * 2 * itk::Math::pi) * ((m_Conf.SpeedOfSound * m_Conf.TimeSpacing)) / (m_Conf.Pitch * m_Conf.TransducerElements)) * m_Conf.inputDim[0]; - + m_part = (tan(m_Conf->GetAngle() / 360 * 2 * itk::Math::pi) * + ((m_Conf->GetSpeedOfSound() * m_Conf->GetTimeSpacing())) / + (m_Conf->GetPitchInMeters() * m_Conf->GetTransducerElements())) * m_Conf->GetInputDim()[0]; + + unsigned int reconLines = this->m_Conf->GetReconstructionLines(); + unsigned int samplesPerLine = this->m_Conf->GetSamplesPerLine(); + char isPAImage = this->m_Conf->GetIsPhotoacousticImage(); + + float percentOfImageReconstructed = (float)(m_Conf->GetReconstructionDepth()) / + (float)(m_Conf->GetInputDim()[1] * m_Conf->GetSpeedOfSound() * m_Conf->GetTimeSpacing() / (float)(2 - (int)m_Conf->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + clErr = clSetKernelArg(this->m_PixelCalculation, 1, sizeof(cl_float), &(this->m_part)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf.inputDim[0])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf.inputDim[1])); - clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(this->m_Conf.ReconstructionLines)); - clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(this->m_Conf.SamplesPerLine)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 2, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[0])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 3, sizeof(cl_uint), &(this->m_Conf->GetInputDim()[1])); + clErr |= clSetKernelArg(this->m_PixelCalculation, 4, sizeof(cl_uint), &(reconLines)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 5, sizeof(cl_uint), &(samplesPerLine)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 6, sizeof(cl_char), &(isPAImage)); + clErr |= clSetKernelArg(this->m_PixelCalculation, 7, sizeof(cl_float), &(percentOfImageReconstructed)); CHECK_OCL_ERR(clErr); // execute the filter on a 2D NDRange if (!this->ExecuteKernelChunksInBatches(m_PixelCalculation, 2, m_ChunkSize, 16, 50)) mitkThrow() << "openCL Error when executing Kernel"; // signalize the GPU-side data changed m_Output->Modified(GPU_DATA); } us::Module *mitk::OCLUsedLinesCalculation::GetModule() { return us::GetModuleContext()->GetModule(); } bool mitk::OCLUsedLinesCalculation::Initialize() { bool buildErr = true; cl_int clErr = 0; if (OclFilter::Initialize()) { this->m_PixelCalculation = clCreateKernel(this->m_ClProgram, "ckUsedLines", &clErr); buildErr |= CHECK_OCL_ERR(clErr); } return (OclFilter::IsInitialized() && buildErr); } #endif diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkBandpassFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBandpassFilter.cpp new file mode 100644 index 0000000000..1e36f07613 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBandpassFilter.cpp @@ -0,0 +1,266 @@ +/*=================================================================== +mitkCastToFloatImageFilter +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 + +#include "mitkBandpassFilter.h" + +#include "../ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" +#include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" +#include "itkComplexToModulusImageFilter.h" +#include "itkMultiplyImageFilter.h" +#include "mitkIOUtil.h" +#include "mitkITKImageImport.h" +#include "mitkImageCast.h" + +mitk::BandpassFilter::BandpassFilter() + : m_HighPass(0), + m_LowPass(50), + m_HighPassAlpha(1), + m_LowPassAlpha(1), + m_FilterService(mitk::PhotoacousticFilterService::New()) +{ + MITK_INFO << "Instantiating BandpassFilter..."; + SetNumberOfIndexedInputs(1); + SetNumberOfIndexedOutputs(1); + MITK_INFO << "Instantiating BandpassFilter...[Done]"; +} + +mitk::BandpassFilter::~BandpassFilter() +{ + MITK_INFO << "Destructed BandpassFilter."; +} + +void mitk::BandpassFilter::SanityCheckPreconditions() +{ + auto input = GetInput(); + + std::string type = input->GetPixelType().GetTypeAsString(); + if (!(type == "scalar (float)" || type == " (float)")) + { + MITK_ERROR << "This filter can currently only handle float type images."; + mitkThrow() << "This filter can currently only handle float type images."; + } + if (m_HighPass > m_LowPass) + { + MITK_ERROR << "High Pass is higher than Low Pass; aborting."; + mitkThrow() << "High Pass is higher than Low Pass; aborting."; + } +} + +itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, + float cutoffFrequencyPixelHighPass, + float cutoffFrequencyPixelLowPass, + float alphaHighPass, + float alphaLowPass) +{ + float *imageData = new float[reference->GetDimension(0) * reference->GetDimension(1)]; + + float width = cutoffFrequencyPixelLowPass - cutoffFrequencyPixelHighPass; + float center = cutoffFrequencyPixelHighPass + width / 2.f; + + for (unsigned int n = 0; n < reference->GetDimension(1); ++n) + { + imageData[reference->GetDimension(0) * n] = 0; + } + for (int n = 0; n < width; ++n) + { + imageData[reference->GetDimension(0) * (int)(n + center - (width / 2.f))] = 1; + if (n <= (alphaHighPass * (width - 1)) / 2.f) + { + if (alphaHighPass > 0.00001f) + { + imageData[reference->GetDimension(0) * (int)(n + center - (width / 2.f))] = + (1 + cos(itk::Math::pi * (2 * n / (alphaHighPass * (width - 1)) - 1))) / 2; + } + else + { + imageData[reference->GetDimension(0) * (int)(n + center - (width / 2.f))] = 1; + } + } + else if (n >= (width - 1) * (1 - alphaLowPass / 2.f)) + { + if (alphaLowPass > 0.00001f) + { + imageData[reference->GetDimension(0) * (int)(n + center - (width / 2.f))] = + (1 + cos(itk::Math::pi * (2 * n / (alphaLowPass * (width - 1)) + 1 - 2 / alphaLowPass))) / 2; + } + else + { + imageData[reference->GetDimension(0) * (int)(n + center - (width / 2.f))] = 1; + } + } + } + + for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) + { + imageData[reference->GetDimension(0) * n] = + imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; + } + + for (unsigned int line = 1; line < reference->GetDimension(0); ++line) + { + for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) + { + imageData[reference->GetDimension(0) * sample + line] = imageData[reference->GetDimension(0) * sample]; + } + } + + typedef itk::Image ImageType; + ImageType::RegionType region; + ImageType::IndexType start; + start.Fill(0); + + region.SetIndex(start); + + ImageType::SizeType size; + size[0] = reference->GetDimension(0); + size[1] = reference->GetDimension(1); + size[2] = reference->GetDimension(2); + + region.SetSize(size); + + ImageType::SpacingType SpacingItk; + SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; + SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; + SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; + + ImageType::Pointer image = ImageType::New(); + image->SetRegions(region); + image->Allocate(); + image->FillBuffer(itk::NumericTraits::Zero); + image->SetSpacing(SpacingItk); + + ImageType::IndexType pixelIndex; + + for (unsigned int slice = 0; slice < reference->GetDimension(2); ++slice) + { + for (unsigned int line = 0; line < reference->GetDimension(0); ++line) + { + for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) + { + pixelIndex[0] = line; + pixelIndex[1] = sample; + pixelIndex[2] = slice; + + image->SetPixel(pixelIndex, imageData[line + sample * reference->GetDimension(0)]); + } + } + } + + delete[] imageData; + + return image; +} + +void mitk::BandpassFilter::GenerateData() +{ + SanityCheckPreconditions(); + auto input = GetInput(); + auto output = GetOutput(); + mitk::Image::Pointer resampledInput = input; + + double powerOfTwo = std::log2(input->GetDimension(1)); + int finalSize = 0; + + // check if this is a power of two by checking that log2 is int + if (std::fmod(powerOfTwo, 1.0) >= std::numeric_limits::epsilon()) + { + finalSize = (int)pow(2, std::ceil(powerOfTwo)); + double spacing_x = input->GetGeometry()->GetSpacing()[0]; + double spacing_y = input->GetGeometry()->GetSpacing()[1] * ((double)input->GetDimensions()[1]) / finalSize; + double dim[2] = {spacing_x, spacing_y}; + resampledInput = m_FilterService->ApplyResampling(input, dim); + } + + // do a fourier transform, multiply with an appropriate window for the filter, and transform back + typedef itk::Image RealImageType; + RealImageType::Pointer image; + + mitk::CastToItkImage(resampledInput, image); + typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; + typedef ForwardFFTFilterType::OutputImageType ComplexImageType; + ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); + forwardFFTFilter->SetInput(image); + forwardFFTFilter->SetDirection(1); + + try + { + forwardFFTFilter->UpdateOutputInformation(); + } + catch (itk::ExceptionObject &error) + { + std::cerr << "Error: " << error << std::endl; + MITK_ERROR << "Bandpass could not be applied"; + mitkThrow() << "bandpass error"; + } + + if (m_HighPass > m_LowPass) + mitkThrow() << "High pass frequency higher than low pass frequency, abort"; + + float singleVoxel = + 2 * M_PI / ((float)resampledInput->GetGeometry()->GetSpacing()[1] * resampledInput->GetDimension(1)); // [MHz] + float cutoffPixelHighPass = std::min((m_HighPass / singleVoxel), (float)resampledInput->GetDimension(1) / 2.0f); + float cutoffPixelLowPass = std::min((m_LowPass / singleVoxel), (float)resampledInput->GetDimension(1) / 2.0f); + + MITK_INFO << "SingleVoxel: " << singleVoxel; + MITK_INFO << "HighPass: " << m_HighPass; + MITK_INFO << "LowPass: " << m_LowPass; + + MITK_INFO << "cutoffPixelHighPass: " << cutoffPixelHighPass; + MITK_INFO << "cutoffPixelLowPass: " << cutoffPixelLowPass; + + RealImageType::Pointer fftMultiplicator = + BPFunction(resampledInput, cutoffPixelHighPass, cutoffPixelLowPass, m_HighPassAlpha, m_LowPassAlpha); + + typedef itk::MultiplyImageFilter MultiplyFilterType; + MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); + multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); + multiplyFilter->SetInput2(fftMultiplicator); + + /* + GrabItkImageMemory(fftMultiplicator, output); + mitk::IOUtil::Save(output, "D:/fftImage.nrrd"); + + typedef itk::ComplexToModulusImageFilter< ComplexImageType, RealImageType > modulusType; + modulusType::Pointer modul = modulusType::New(); + + modul->SetInput(multiplyFilter->GetOutput()); + GrabItkImageMemory(modul->GetOutput(), output); + mitk::IOUtil::Save(output, "D:/fftout.nrrd"); + + modul->SetInput(forwardFFTFilter->GetOutput()); + GrabItkImageMemory(modul->GetOutput(), output); + mitk::IOUtil::Save(output, "D:/fftin.nrrd");*/ + + typedef itk::FFT1DComplexConjugateToRealImageFilter InverseFilterType; + InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); + inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); + inverseFFTFilter->SetDirection(1); + + GrabItkImageMemory(inverseFFTFilter->GetOutput(), output); + + double spacing_x = input->GetGeometry()->GetSpacing()[0]; + double spacing_y = input->GetGeometry()->GetSpacing()[1]; + double dim[2] = {spacing_x, spacing_y}; + auto resampledOutput = m_FilterService->ApplyResampling(output, dim); + + output->Initialize(mitk::MakeScalarPixelType(), 3, input->GetDimensions()); + output->SetSpacing(resampledOutput->GetGeometry()->GetSpacing()); + ImageReadAccessor copy(resampledOutput); + output->SetImportVolume(copy.GetData()); +} diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingFilter.cpp new file mode 100644 index 0000000000..b1f655f1bf --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingFilter.cpp @@ -0,0 +1,297 @@ +/*=================================================================== +mitkBeamformingFilter +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 "mitkImageReadAccessor.h" +#include +#include +#include +#include +#include +#include "mitkImageCast.h" +#include "mitkBeamformingFilter.h" +#include "mitkBeamformingUtils.h" + +mitk::BeamformingFilter::BeamformingFilter(mitk::BeamformingSettings::Pointer settings) : + m_OutputData(nullptr), + m_InputData(nullptr), + m_Conf(settings) +{ + MITK_INFO << "Instantiating BeamformingFilter..."; + this->SetNumberOfIndexedInputs(1); + this->SetNumberOfRequiredInputs(1); + + m_ProgressHandle = [](int, std::string) {}; +#if defined(PHOTOACOUSTICS_USE_GPU) + m_BeamformingOclFilter = mitk::PhotoacousticOCLBeamformingFilter::New(m_Conf); +#else + m_BeamformingOclFilter = mitk::PhotoacousticOCLBeamformingFilter::New(); +#endif + + MITK_INFO << "Instantiating BeamformingFilter...[Done]"; +} + +void mitk::BeamformingFilter::SetProgressHandle(std::function progressHandle) +{ + m_ProgressHandle = progressHandle; +} + +mitk::BeamformingFilter::~BeamformingFilter() +{ + MITK_INFO << "Destructed BeamformingFilter"; +} + +void mitk::BeamformingFilter::GenerateInputRequestedRegion() +{ + Superclass::GenerateInputRequestedRegion(); + + mitk::Image* output = this->GetOutput(); + mitk::Image* input = const_cast (this->GetInput()); + if (!output->IsInitialized()) + { + return; + } + + input->SetRequestedRegionToLargestPossibleRegion(); +} + +void mitk::BeamformingFilter::GenerateOutputInformation() +{ + mitk::Image::ConstPointer input = this->GetInput(); + mitk::Image::Pointer output = this->GetOutput(); + + if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) + return; + + mitk::Vector3D spacing; + spacing[0] = m_Conf->GetPitchInMeters() * m_Conf->GetTransducerElements() * 1000 / m_Conf->GetReconstructionLines(); + float desiredYSpacing = m_Conf->GetReconstructionDepth() * 1000 / m_Conf->GetSamplesPerLine(); + float maxYSpacing = m_Conf->GetSpeedOfSound() * m_Conf->GetTimeSpacing() * input->GetDimension(1) / m_Conf->GetSamplesPerLine() * 1000; + spacing[1] = desiredYSpacing < maxYSpacing ? desiredYSpacing : maxYSpacing; + spacing[2] = 1; + + unsigned int dim[] = { m_Conf->GetReconstructionLines(), m_Conf->GetSamplesPerLine(), input->GetDimension(2)}; + output->Initialize(mitk::MakeScalarPixelType(), 3, dim); + output->GetGeometry()->SetSpacing(spacing); + output->GetGeometry()->Modified(); + output->SetPropertyList(input->GetPropertyList()->Clone()); + + m_TimeOfHeaderInitialization.Modified(); +} + +void mitk::BeamformingFilter::GenerateData() +{ + mitk::Image::Pointer input = this->GetInput(); + if (!(input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)")) + { + MITK_ERROR << "Pixel type of input needs to be float for this filter to work."; + mitkThrow() << "Pixel type of input needs to be float for this filter to work."; + } + + GenerateOutputInformation(); + mitk::Image::Pointer output = this->GetOutput(); + + if (!output->IsInitialized()) + return; + + auto begin = std::chrono::high_resolution_clock::now(); // debbuging the performance... + + if (!m_Conf->GetUseGPU()) + { + int progInterval = output->GetDimension(2) / 20 > 1 ? output->GetDimension(2) / 20 : 1; + // the interval at which we update the gui progress bar + + float inputDim[2] = { (float)input->GetDimension(0), (float)input->GetDimension(1) }; + float outputDim[2] = { (float)output->GetDimension(0), (float)output->GetDimension(1) }; + + for (unsigned int i = 0; i < output->GetDimension(2); ++i) // seperate Slices should get Beamforming seperately applied + { + mitk::ImageReadAccessor inputReadAccessor(input, input->GetSliceData(i)); + m_InputData = (float*)inputReadAccessor.GetData(); + + m_OutputData = new float[m_Conf->GetReconstructionLines()*m_Conf->GetSamplesPerLine()]; + + // fill the image with zeros + for (int l = 0; l < outputDim[0]; ++l) + { + for (int s = 0; s < outputDim[1]; ++s) + { + m_OutputData[l*(short)outputDim[1] + s] = 0; + } + } + + std::thread *threads = new std::thread[(short)outputDim[0]]; + + // every line will be beamformed in a seperate thread + if (m_Conf->GetAlgorithm() == BeamformingSettings::BeamformingAlgorithm::DAS) + { + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::DASQuadraticLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + else if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::DASSphericalLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + } + else if (m_Conf->GetAlgorithm() == BeamformingSettings::BeamformingAlgorithm::DMAS) + { + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::DMASQuadraticLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + else if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::DMASSphericalLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + } + else if (m_Conf->GetAlgorithm() == BeamformingSettings::BeamformingAlgorithm::sDMAS) + { + if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::QuadApprox) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::sDMASQuadraticLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + else if (m_Conf->GetDelayCalculationMethod() == BeamformingSettings::DelayCalc::Spherical) + { + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line] = std::thread(&BeamformingUtils::sDMASSphericalLine, m_InputData, + m_OutputData, inputDim, outputDim, line, m_Conf); + } + } + } + // wait for all lines to finish + for (short line = 0; line < outputDim[0]; ++line) + { + threads[line].join(); + } + + output->SetSlice(m_OutputData, i); + + if (i % progInterval == 0) + m_ProgressHandle((int)((i + 1) / (float)output->GetDimension(2) * 100), "performing reconstruction"); + + delete[] m_OutputData; + m_OutputData = nullptr; + m_InputData = nullptr; + } + } +#if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN + else + { + try + { + // first, we check whether the data is float, other formats are unsupported + if (!(input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)")) + { + MITK_ERROR << "Pixel type is not float, abort"; + mitkThrow() << "Pixel type is not float, abort"; + } + + unsigned long availableMemory = m_BeamformingOclFilter->GetDeviceMemory(); + + unsigned int batchSize = m_Conf->GetGPUBatchSize(); + unsigned int batches = (unsigned int)((float)input->GetDimension(2) / batchSize) + (input->GetDimension(2) % batchSize > 0); + + unsigned int batchDim[] = { input->GetDimension(0), input->GetDimension(1), batchSize }; + unsigned int batchDimLast[] = { input->GetDimension(0), input->GetDimension(1), input->GetDimension(2) % batchSize }; + + // the following safeguard is probably only needed for absurdly small GPU memory + if((unsigned long)batchSize * + ((unsigned long)(batchDim[0] * batchDim[1]) * 4 + // single input image (float) + (unsigned long)(m_Conf->GetReconstructionLines() * m_Conf->GetSamplesPerLine()) * 4) // single output image (float) + > availableMemory - + (unsigned long)(m_Conf->GetReconstructionLines() / 2 * m_Conf->GetSamplesPerLine()) * 2 - // Delays buffer (unsigned short) + (unsigned long)(m_Conf->GetReconstructionLines() * m_Conf->GetSamplesPerLine()) * 3 * 2 - // UsedLines buffer (unsigned short) + 50 * 1024 * 1024)// 50 MB buffer for local data, system purposes etc + { + MITK_ERROR << "device memory too small for GPU beamforming; try decreasing the batch size"; + return; + } + + mitk::ImageReadAccessor copy(input); + + for (unsigned int i = 0; i < batches; ++i) + { + m_ProgressHandle(100.f * (float)i / (float)batches, "performing reconstruction"); + + mitk::Image::Pointer inputBatch = mitk::Image::New(); + unsigned int num_Slices = 1; + if (i == batches - 1 && (input->GetDimension(2) % batchSize > 0)) + { + inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDimLast); + num_Slices = batchDimLast[2]; + } + else + { + inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDim); + num_Slices = batchDim[2]; + } + + inputBatch->SetSpacing(input->GetGeometry()->GetSpacing()); + + inputBatch->SetImportVolume(&(((float*)copy.GetData())[input->GetDimension(0) * input->GetDimension(1) * batchSize * i])); + + m_BeamformingOclFilter->SetApodisation(m_Conf->GetApodizationFunction(), m_Conf->GetApodizationArraySize()); + m_BeamformingOclFilter->SetInput(inputBatch, num_Slices); + m_BeamformingOclFilter->Update(); + + void* out = m_BeamformingOclFilter->GetOutput(); + + for (unsigned int slice = 0; slice < num_Slices; ++slice) + { + output->SetImportSlice( + &(((float*)out)[m_Conf->GetReconstructionLines() * m_Conf->GetSamplesPerLine() * slice]), + batchSize * i + slice, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + } + } + } + catch (mitk::Exception &e) + { + std::string errorMessage = "Caught unexpected exception "; + errorMessage.append(e.what()); + MITK_ERROR << errorMessage; + + float* dummyData = new float[m_Conf->GetReconstructionLines() * m_Conf->GetSamplesPerLine() * m_Conf->GetInputDim()[2]]; + output->SetImportVolume(dummyData, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + } + } +#endif + m_TimeOfHeaderInitialization.Modified(); + + auto end = std::chrono::high_resolution_clock::now(); + MITK_INFO << "Beamforming of " << output->GetDimension(2) << " Images completed in " << ((float)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; +} diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp new file mode 100644 index 0000000000..b052f15a5c --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkBeamformingSettings.cpp @@ -0,0 +1,105 @@ +/*=================================================================== +mitkBeamformingSettings +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 "mitkBeamformingSettings.h" +#include "mitkBeamformingUtils.h" +#include "itkMutexLock.h" + +mitk::BeamformingSettings::BeamformingSettings(std::string xmlFile) +{ + if((xmlFile.length())>0) + { + MITK_ERROR << "Not implemented yet."; + mitkThrow() << "Not implemented yet."; + } +} + +mitk::BeamformingSettings::BeamformingSettings(float pitchInMeters, + float speedOfSound, + float timeSpacing, + float angle, + bool isPhotoacousticImage, + unsigned int samplesPerLine, + unsigned int reconstructionLines, + unsigned int* inputDim, + float reconstructionDepth, + bool useGPU, + unsigned int GPUBatchSize, + DelayCalc delayCalculationMethod, + Apodization apod, + unsigned int apodizationArraySize, + BeamformingAlgorithm algorithm +) : + m_PitchInMeters(pitchInMeters), + m_SpeedOfSound(speedOfSound), + m_TimeSpacing(timeSpacing), + m_Angle(angle), + m_IsPhotoacousticImage(isPhotoacousticImage), + m_SamplesPerLine(samplesPerLine), + m_ReconstructionLines(reconstructionLines), + m_ReconstructionDepth(reconstructionDepth), + m_UseGPU(useGPU), + m_GPUBatchSize(GPUBatchSize), + m_DelayCalculationMethod(delayCalculationMethod), + m_Apod(apod), + m_ApodizationArraySize(apodizationArraySize), + m_Algorithm(algorithm) +{ + if (inputDim == nullptr) + { + MITK_ERROR << "No input dimension given."; + mitkThrow() << "No input dimension given."; + } + + switch (GetApod()) + { + case BeamformingSettings::Apodization::Hann: + m_ApodizationFunction = mitk::BeamformingUtils::VonHannFunction(GetApodizationArraySize()); + break; + case BeamformingSettings::Apodization::Hamm: + m_ApodizationFunction = mitk::BeamformingUtils::HammFunction(GetApodizationArraySize()); + break; + case BeamformingSettings::Apodization::Box: + default: + m_ApodizationFunction = mitk::BeamformingUtils::BoxFunction(GetApodizationArraySize()); + break; + } + + m_InputDim = new unsigned int[3]{ inputDim[0], inputDim[1], inputDim[2] }; + + m_TransducerElements = m_InputDim[0]; +} + +mitk::BeamformingSettings::~BeamformingSettings() +{ + MITK_INFO << "Destructing beamforming settings..."; + //Free memory + if (m_ApodizationFunction != nullptr) + { + MITK_INFO << "Deleting apodization function..."; + delete[] m_ApodizationFunction; + MITK_INFO << "Deleting apodization function...[Done]"; + } + + if (m_InputDim != nullptr) + { + MITK_INFO << "Deleting input dim..."; + delete[] m_InputDim; + MITK_INFO << "Deleting input dim...[Done]"; + } + + MITK_INFO << "Destructing beamforming settings...[Done]"; +} diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkCastToFloatImageFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkCastToFloatImageFilter.cpp new file mode 100644 index 0000000000..cc26284be8 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkCastToFloatImageFilter.cpp @@ -0,0 +1,92 @@ +/*=================================================================== +mitkCastToFloatImageFilter +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 "mitkCastToFloatImageFilter.h" +#include "mitkImageReadAccessor.h" +#include "mitkImageWriteAccessor.h" + +mitk::CastToFloatImageFilter::CastToFloatImageFilter() +{ + MITK_INFO << "Instantiating CastToFloatImageFilter..."; + SetNumberOfIndexedInputs(1); + SetNumberOfIndexedOutputs(1); + MITK_INFO << "Instantiating CastToFloatImageFilter...[Done]"; +} + +mitk::CastToFloatImageFilter::~CastToFloatImageFilter() +{ + MITK_INFO << "Destructed CastToFloatImageFilter."; +} + +template +float* CastData(const void* inputArray, unsigned long length) +{ + float* outputArray = new float[length]; + for (unsigned long i = 0; i < length; ++i) + { + outputArray[i] = (float)((TPixelType*)inputArray)[i]; + } + return outputArray; +} + +void mitk::CastToFloatImageFilter::GenerateData() +{ + mitk::Image::Pointer inputImage = GetInput(); + mitk::Image::Pointer outputImage = GetOutput(); + + std::string type = inputImage->GetPixelType().GetTypeAsString(); + + if (type == "scalar (float)" || type == " (float)") + { + outputImage->Initialize(mitk::MakeScalarPixelType(), inputImage->GetDimension(), inputImage->GetDimensions()); + outputImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); + outputImage->SetImportVolume(mitk::ImageWriteAccessor(inputImage).GetData(), 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + MITK_INFO << "Input is already float type. Nothing to do here."; + return; + } + if (outputImage.IsNull()) + { + outputImage = mitk::Image::New(); + } + + unsigned long length = 1; + for (unsigned int i = 0, limit = inputImage->GetDimension(); i < limit; ++i) + length *= inputImage->GetDimensions()[i]; + + float* outputData; + + mitk::ImageReadAccessor readAccess(inputImage); + + if (type == "scalar (short)" || type == " (short)") + outputData = CastData(readAccess.GetData(), length); + else if (type == "scalar (unsigned short)" || type == " (unsigned short)" || type == " (unsigned_short)" || type == "scalar (unsigned_short)") + outputData = CastData(readAccess.GetData(), length); + else if (type == "scalar (int)" || type == " (int)") + outputData = CastData(readAccess.GetData(), length); + else if (type == "scalar (unsigned int)" || type == " (unsigned int)" || type == " (unsigned_int)" || type == "scalar (unsigned_int)") + outputData = CastData(readAccess.GetData(), length); + else if (type == "scalar (double)" || type == " (double)") + outputData = CastData(readAccess.GetData(), length); + else if (type == "scalar (long)" || type == " (long)") + outputData = CastData(readAccess.GetData(), length); + else + mitkThrow() << "The given image has a datatype that is not yet supported. Given datatype: " << type; + + outputImage->Initialize(mitk::MakeScalarPixelType(), inputImage->GetDimension(), inputImage->GetDimensions()); + outputImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); + outputImage->SetImportVolume(outputData, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + delete[] outputData; +} diff --git a/Modules/PhotoacousticsAlgorithms/source/filters/mitkCropImageFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkCropImageFilter.cpp new file mode 100644 index 0000000000..3996284f79 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkCropImageFilter.cpp @@ -0,0 +1,120 @@ +/*=================================================================== +mitkCropImageFilter +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 "mitkCropImageFilter.h" +#include +#include + +mitk::CropImageFilter::CropImageFilter() : + m_XPixelsCropStart(0), + m_YPixelsCropStart(0), + m_ZPixelsCropStart(0), + m_XPixelsCropEnd(0), + m_YPixelsCropEnd(0), + m_ZPixelsCropEnd(0) +{ + MITK_INFO << "Instantiating CropImageFilter..."; + SetNumberOfIndexedInputs(1); + SetNumberOfIndexedOutputs(1); + MITK_INFO << "Instantiating CropImageFilter...[Done]"; +} + +mitk::CropImageFilter::~CropImageFilter() +{ + MITK_INFO << "Destructed CastToFloatImageFilter."; +} + +void mitk::CropImageFilter::SanityCheckPreconditions() +{ + mitk::Image::Pointer inputImage = GetInput(); + + std::string type = inputImage->GetPixelType().GetTypeAsString(); + if (!(type == "scalar (float)" || type == " (float)")) + { + MITK_ERROR << "This filter can currently only handle float type images."; + mitkThrow() << "This filter can currently only handle float type images."; + } + + if (m_XPixelsCropStart + m_XPixelsCropEnd >= inputImage->GetDimension(0)) + { + MITK_ERROR << "X Crop area too large for selected input image"; + mitkThrow() << "X Crop area too large for selected input image"; + } + if (m_YPixelsCropStart + m_YPixelsCropEnd >= inputImage->GetDimension(1)) + { + MITK_ERROR << "Y Crop area too large for selected input image"; + mitkThrow() << "Y Crop area too large for selected input image"; + } + + if (inputImage->GetDimension() == 3) + { + if (m_ZPixelsCropStart + m_ZPixelsCropEnd >= inputImage->GetDimension(2)) + { + MITK_INFO << m_ZPixelsCropStart + m_ZPixelsCropEnd << "vs" << inputImage->GetDimension(2); + MITK_ERROR << "Z Crop area too large for selected input image"; + mitkThrow() << "Z Crop area too large for selected input image"; + } + } + else + { + if (m_ZPixelsCropStart + m_ZPixelsCropEnd > 0) + { + mitkThrow() << "Z Crop area too large for selected input image"; + } + } +} + +void mitk::CropImageFilter::GenerateData() +{ + mitk::Image::Pointer inputImage = GetInput(); + mitk::Image::Pointer outputImage = GetOutput(); + + SanityCheckPreconditions(); + unsigned int* outputDim; + unsigned int* inputDim = inputImage->GetDimensions(); + if (inputImage->GetDimension() == 2) + outputDim = new unsigned int[2]{ inputImage->GetDimension(0) - m_XPixelsCropStart - m_XPixelsCropEnd, + inputImage->GetDimension(1) - m_YPixelsCropStart - m_YPixelsCropEnd }; + else + outputDim = new unsigned int[3]{ inputImage->GetDimension(0) - m_XPixelsCropStart - m_XPixelsCropEnd, + inputImage->GetDimension(1) - m_YPixelsCropStart - m_YPixelsCropEnd, + inputImage->GetDimension(2) - m_ZPixelsCropStart - m_ZPixelsCropEnd }; + + outputImage->Initialize(mitk::MakeScalarPixelType(), inputImage->GetDimension(), outputDim); + outputImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); + + ImageReadAccessor accR(inputImage); + const float* inputData = (const float*)(accR.GetData()); + + ImageWriteAccessor accW(outputImage); + float* outputData = (float*)(accW.GetData()); + + unsigned int zLength = inputImage->GetDimension() == 3 ? outputDim[2] : 0; + + for (unsigned int sl = 0; sl < zLength; ++sl) + { + for (unsigned int l = 0; l < outputDim[0]; ++l) + { + for (unsigned int s = 0; s < outputDim[1]; ++s) + { + outputData[l + s*outputDim[0] + sl*outputDim[0] * outputDim[1]] = + inputData[(l + m_XPixelsCropStart) + (s + m_YPixelsCropStart)*inputDim[0] + + (sl + m_ZPixelsCropStart)*inputDim[0] * inputDim[1]]; + } + } + } + delete[] outputDim; +} diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp b/Modules/PhotoacousticsAlgorithms/source/filters/mitkImageSliceSelectionFilter.cpp similarity index 51% copy from Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp copy to Modules/PhotoacousticsAlgorithms/source/filters/mitkImageSliceSelectionFilter.cpp index 028e8bbd7e..b90b5a726e 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/filters/mitkImageSliceSelectionFilter.cpp @@ -1,40 +1,34 @@ /*=================================================================== - +mitkImageSliceSelectionFilter 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 "mitkImageSliceSelectionFilter.h" -#include "org_mitk_gui_qt_cest_Activator.h" - -#include - -#include "QmitkCESTStatisticsView.h" - -namespace mitk { - -void org_mitk_gui_qt_cest_Activator::start(ctkPluginContext* context) +mitk::ImageSliceSelectionFilter::ImageSliceSelectionFilter() { - BERRY_REGISTER_EXTENSION_CLASS(QmitkCESTStatisticsView, context) + MITK_INFO << "Instantiating CropImageFilter..."; + SetNumberOfIndexedInputs(1); + SetNumberOfIndexedOutputs(1); + MITK_INFO << "Instantiating CropImageFilter...[Done]"; } -void org_mitk_gui_qt_cest_Activator::stop(ctkPluginContext* context) +mitk::ImageSliceSelectionFilter::~ImageSliceSelectionFilter() { - Q_UNUSED(context) + MITK_INFO << "Destructed CastToFloatImageFilter."; } +void mitk::ImageSliceSelectionFilter::GenerateData() +{ } - -#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/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp deleted file mode 100644 index 20abc2c982..0000000000 --- a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticBeamformingFilter.cpp +++ /dev/null @@ -1,801 +0,0 @@ -/*=================================================================== -mitkPhotoacousticBeamformingFilter -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 "mitkImageReadAccessor.h" -#include -#include -#include -#include -#include -#include "mitkImageCast.h" -#include "mitkPhotoacousticBeamformingFilter.h" - -mitk::BeamformingFilter::BeamformingFilter() : m_OutputData(nullptr), m_InputData(nullptr), m_Message("noMessage") -{ - this->SetNumberOfIndexedInputs(1); - this->SetNumberOfRequiredInputs(1); - - m_ProgressHandle = [](int, std::string) {}; - - m_BeamformingOclFilter = mitk::PhotoacousticOCLBeamformingFilter::New(); - - m_VonHannFunction = VonHannFunction(m_Conf.apodizationArraySize); - m_HammFunction = HammFunction(m_Conf.apodizationArraySize); - m_BoxFunction = BoxFunction(m_Conf.apodizationArraySize); -} - -void mitk::BeamformingFilter::SetProgressHandle(std::function progressHandle) -{ - m_ProgressHandle = progressHandle; -} - -mitk::BeamformingFilter::~BeamformingFilter() -{ - delete[] m_VonHannFunction; - delete[] m_HammFunction; - delete[] m_BoxFunction; -} - -void mitk::BeamformingFilter::GenerateInputRequestedRegion() -{ - Superclass::GenerateInputRequestedRegion(); - - mitk::Image* output = this->GetOutput(); - mitk::Image* input = const_cast (this->GetInput()); - if (!output->IsInitialized()) - { - return; - } - - input->SetRequestedRegionToLargestPossibleRegion(); - //GenerateTimeInInputRegion(output, input); -} - -void mitk::BeamformingFilter::GenerateOutputInformation() -{ - mitk::Image::ConstPointer input = this->GetInput(); - mitk::Image::Pointer output = this->GetOutput(); - - if ((output->IsInitialized()) && (this->GetMTime() <= m_TimeOfHeaderInitialization.GetMTime())) - return; - - itkDebugMacro(<< "GenerateOutputInformation()"); - - unsigned int dim[] = { m_Conf.ReconstructionLines, m_Conf.SamplesPerLine, input->GetDimension(2) }; - output->Initialize(mitk::MakeScalarPixelType(), 3, dim); - - mitk::Vector3D spacing; - spacing[0] = m_Conf.Pitch * m_Conf.TransducerElements * 1000 / m_Conf.ReconstructionLines; - spacing[1] = (m_Conf.TimeSpacing * m_Conf.inputDim[1]) / 2 * m_Conf.SpeedOfSound * 1000 / m_Conf.SamplesPerLine; - spacing[2] = 1; - - output->GetGeometry()->SetSpacing(spacing); - output->GetGeometry()->Modified(); - output->SetPropertyList(input->GetPropertyList()->Clone()); - - m_TimeOfHeaderInitialization.Modified(); -} - - -void mitk::BeamformingFilter::GenerateData() -{ - GenerateOutputInformation(); - mitk::Image::Pointer input = this->GetInput(); - mitk::Image::Pointer output = this->GetOutput(); - - if (!output->IsInitialized()) - return; - - float* ApodWindow; - if (m_ConfOld.apodizationArraySize != m_Conf.apodizationArraySize) - { - delete[] m_VonHannFunction; - delete[] m_HammFunction; - delete[] m_BoxFunction; - m_VonHannFunction = VonHannFunction(m_Conf.apodizationArraySize); - m_HammFunction = HammFunction(m_Conf.apodizationArraySize); - m_BoxFunction = BoxFunction(m_Conf.apodizationArraySize); - - m_ConfOld = m_Conf; - } - - // set the appropiate apodization window - switch (m_Conf.Apod) - { - case BeamformingSettings::Apodization::Hann: - ApodWindow = m_VonHannFunction; - break; - case BeamformingSettings::Apodization::Hamm: - ApodWindow = m_HammFunction; - break; - case BeamformingSettings::Apodization::Box: - ApodWindow = m_BoxFunction; - break; - default: - ApodWindow = m_BoxFunction; - break; - } - - auto begin = std::chrono::high_resolution_clock::now(); // debbuging the performance... - - if (!m_Conf.UseGPU) - { - int progInterval = output->GetDimension(2) / 20 > 1 ? output->GetDimension(2) / 20 : 1; - // the interval at which we update the gui progress bar - - float inputDim[2] = { (float)input->GetDimension(0), (float)input->GetDimension(1) }; - float outputDim[2] = { (float)output->GetDimension(0), (float)output->GetDimension(1) }; - - for (unsigned int i = 0; i < output->GetDimension(2); ++i) // seperate Slices should get Beamforming seperately applied - { - mitk::ImageReadAccessor inputReadAccessor(input, input->GetSliceData(i)); - - // first, we check whether the dara is float, other formats are unsupported - if (input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)") - { - m_InputData = (float*)inputReadAccessor.GetData(); - } - else - { - MITK_INFO << "Pixel type is not float, abort"; - return; - } - - m_OutputData = new float[m_Conf.ReconstructionLines*m_Conf.SamplesPerLine]; - - // fill the image with zeros - for (int l = 0; l < outputDim[0]; ++l) - { - for (int s = 0; s < outputDim[1]; ++s) - { - m_OutputData[l*(short)outputDim[1] + s] = 0; - } - } - - std::thread *threads = new std::thread[(short)outputDim[0]]; - - // every line will be beamformed in a seperate thread - if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::DAS) - { - if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - } - else if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::DMAS) - { - if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::DMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - } - else if (m_Conf.Algorithm == BeamformingSettings::BeamformingAlgorithm::sDMAS) - { - if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::QuadApprox) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::sDMASQuadraticLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - else if (m_Conf.DelayCalculationMethod == BeamformingSettings::DelayCalc::Spherical) - { - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line] = std::thread(&BeamformingFilter::sDMASSphericalLine, this, m_InputData, m_OutputData, inputDim, outputDim, line, ApodWindow, m_Conf.apodizationArraySize); - } - } - } - // wait for all lines to finish - for (short line = 0; line < outputDim[0]; ++line) - { - threads[line].join(); - } - - output->SetSlice(m_OutputData, i); - - if (i % progInterval == 0) - m_ProgressHandle((int)((i + 1) / (float)output->GetDimension(2) * 100), "performing reconstruction"); - - delete[] m_OutputData; - m_OutputData = nullptr; - m_InputData = nullptr; - } - } - #if defined(PHOTOACOUSTICS_USE_GPU) || DOXYGEN - else - { - try - { - // first, we check whether the data is float, other formats are unsupported - if (!(input->GetPixelType().GetTypeAsString() == "scalar (float)" || input->GetPixelType().GetTypeAsString() == " (float)")) - { - MITK_ERROR << "Pixel type is not float, abort"; - return; - } - - unsigned long availableMemory = m_BeamformingOclFilter->GetDeviceMemory(); - - unsigned int batchSize = 16; - unsigned int batches = (unsigned int)((float)input->GetDimension(2)/batchSize) + (input->GetDimension(2)%batchSize > 0); - - unsigned int batchDim[] = { input->GetDimension(0), input->GetDimension(1), batchSize }; - unsigned int batchDimLast[] = { input->GetDimension(0), input->GetDimension(1), input->GetDimension(2) % batchSize }; - - // the following safeguard is probably only needed for absurdly small GPU memory - for (batchSize = 16; - (unsigned long)batchSize * - ((unsigned long)(batchDim[0] * batchDim[1]) * 4 + // single input image (float) - (unsigned long)(m_Conf.ReconstructionLines * m_Conf.SamplesPerLine) * 4) // single output image (float) - > availableMemory - - (unsigned long)(m_Conf.ReconstructionLines / 2 * m_Conf.SamplesPerLine) * 2 - // Delays buffer (unsigned short) - (unsigned long)(m_Conf.ReconstructionLines * m_Conf.SamplesPerLine) * 3 * 2 - // UsedLines buffer (unsigned short) - 50 * 1024 * 1024; // 50 MB buffer for local data, system purposes etc - --batchSize) - {} - if (batchSize < 1) - { - MITK_ERROR << "device memory too small for GPU beamforming"; - return; - } - - mitk::ImageReadAccessor copy(input); - - for(unsigned int i = 0; i < batches; ++i) - { - m_ProgressHandle(input->GetDimension(2)/batches * i, "performing reconstruction"); - - mitk::Image::Pointer inputBatch = mitk::Image::New(); - if(i == batches - 1 && (input->GetDimension(2)%batchSize > 0)) - { - inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDimLast); - m_Conf.inputDim[2] = batchDimLast[2]; - } - else - { - inputBatch->Initialize(mitk::MakeScalarPixelType(), 3, batchDim); - m_Conf.inputDim[2] = batchDim[2]; - } - - inputBatch->SetSpacing(input->GetGeometry()->GetSpacing()); - - inputBatch->SetImportVolume(&(((float*)copy.GetData())[input->GetDimension(0) * input->GetDimension(1) * batchSize * i])); - - m_BeamformingOclFilter->SetApodisation(ApodWindow, m_Conf.apodizationArraySize); - m_BeamformingOclFilter->SetConfig(m_Conf); - m_BeamformingOclFilter->SetInput(inputBatch); - m_BeamformingOclFilter->Update(); - - void* out = m_BeamformingOclFilter->GetOutput(); - - for(unsigned int slice = 0; slice < m_Conf.inputDim[2]; ++slice) - { - output->SetImportSlice( - &(((float*)out)[m_Conf.ReconstructionLines * m_Conf.SamplesPerLine * slice]), - batchSize * i + slice, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); - } - } - } - catch (mitk::Exception &e) - { - std::string errorMessage = "Caught unexpected exception "; - errorMessage.append(e.what()); - MITK_ERROR << errorMessage; - - float* dummyData = new float[m_Conf.ReconstructionLines * m_Conf.SamplesPerLine * m_Conf.inputDim[2]]; - output->SetImportVolume(dummyData, 0, 0, mitk::Image::ImportMemoryManagementType::ManageMemory); - - m_Message = "An openCL error occurred; all GPU operations in this and the next session may be corrupted."; - } - } - #endif - m_TimeOfHeaderInitialization.Modified(); - - auto end = std::chrono::high_resolution_clock::now(); - MITK_INFO << "Beamforming of " << output->GetDimension(2) << " Images completed in " << ((float)std::chrono::duration_cast(end - begin).count()) / 1000000 << "ms" << std::endl; -} - -float* mitk::BeamformingFilter::VonHannFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = (1 - cos(2 * itk::Math::pi * n / (samples - 1))) / 2; - } - - return ApodWindow; -} - -float* mitk::BeamformingFilter::HammFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = 0.54 - 0.46*cos(2 * itk::Math::pi*n / (samples - 1)); - } - - return ApodWindow; -} - -float* mitk::BeamformingFilter::BoxFunction(int samples) -{ - float* ApodWindow = new float[samples]; - - for (int n = 0; n < samples; ++n) - { - ApodWindow[n] = 1; - } - - return ApodWindow; -} - -void mitk::BeamformingFilter::DASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short AddSample = 0; - short maxLine = 0; - short minLine = 0; - float delayMultiplicator = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / m_Conf.TransducerElements; - float apod_mult = 1; - - short usedLines = (maxLine - minLine); - - //quadratic delay - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - m_Conf.isPhotoacousticImage)*s_i; - if (AddSample < inputS && AddSample >= 0) - output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; - else - --usedLines; - } - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; - } -} - -void mitk::BeamformingFilter::DASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short AddSample = 0; - short maxLine = 0; - short minLine = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; - float apod_mult = 1; - - short usedLines = (maxLine - minLine); - - //exact delay - - l_i = (float)line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - for (short l_s = minLine; l_s < maxLine; ++l_s) - { - AddSample = (int)sqrt( - pow(s_i, 2) - + - pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) - ) + (1 - m_Conf.isPhotoacousticImage)*s_i; - if (AddSample < inputS && AddSample >= 0) - output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * apodisation[(short)((l_s - minLine)*apod_mult)]; - else - --usedLines; - } - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; - } -} - - -void mitk::BeamformingFilter::DMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float delayMultiplicator = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - short usedLines = (maxLine - minLine); - - //quadratic delay - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.isPhotoacousticImage)*s_i; - } - - float s_1 = 0; - float s_2 = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; - s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; - - mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); - - delete[] AddSample; - } -} - -void mitk::BeamformingFilter::DMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - - short usedLines = (maxLine - minLine); - - //exact delay - - l_i = (float)line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)sqrt( - pow(s_i, 2) - + - pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)minLine + (float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) - ) + (1 - m_Conf.isPhotoacousticImage)*s_i; - } - - float s_1 = 0; - float s_2 = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) - { - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; - s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; - - mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); - - delete[] AddSample; - } -} - -void mitk::BeamformingFilter::sDMASQuadraticLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float delayMultiplicator = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - short usedLines = (maxLine - minLine); - - //quadratic delay - l_i = line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - delayMultiplicator = pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (m_Conf.Pitch*m_Conf.TransducerElements) / inputL), 2) / s_i / 2; - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + (1 - m_Conf.isPhotoacousticImage)*s_i; - } - - float s_1 = 0; - float s_2 = 0; - float sign = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) - { - s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; - sign += s_1; - - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; - - mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); - - delete[] AddSample; - } -} - -void mitk::BeamformingFilter::sDMASSphericalLine(float* input, float* output, float inputDim[2], float outputDim[2], const short& line, float* apodisation, const short& apodArraySize) -{ - float& inputS = inputDim[1]; - float& inputL = inputDim[0]; - - float& outputS = outputDim[1]; - float& outputL = outputDim[0]; - - short maxLine = 0; - short minLine = 0; - float l_i = 0; - float s_i = 0; - - float part = 0.07 * inputL; - float tan_phi = std::tan(m_Conf.Angle / 360 * 2 * itk::Math::pi); - float part_multiplicator = tan_phi * m_Conf.TimeSpacing * m_Conf.SpeedOfSound / m_Conf.Pitch * inputL / (float)m_Conf.TransducerElements; - float apod_mult = 1; - - float mult = 0; - - short usedLines = (maxLine - minLine); - - //exact delay - - l_i = (float)line / outputL * inputL; - - for (short sample = 0; sample < outputS; ++sample) - { - s_i = (float)sample / outputS * inputS / 2; - - part = part_multiplicator*s_i; - - if (part < 1) - part = 1; - - maxLine = (short)std::min((l_i + part) + 1, inputL); - minLine = (short)std::max((l_i - part), 0.0f); - usedLines = (maxLine - minLine); - - apod_mult = (float)apodArraySize / (float)usedLines; - - //calculate the AddSamples beforehand to save some time - short* AddSample = new short[maxLine - minLine]; - for (short l_s = 0; l_s < maxLine - minLine; ++l_s) - { - AddSample[l_s] = (short)sqrt( - pow(s_i, 2) - + - pow((1 / (m_Conf.TimeSpacing*m_Conf.SpeedOfSound) * (((float)minLine + (float)l_s - l_i)*m_Conf.Pitch*(float)m_Conf.TransducerElements) / inputL), 2) - ) + (1 - m_Conf.isPhotoacousticImage)*s_i; - } - - float s_1 = 0; - float s_2 = 0; - float sign = 0; - - for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) - { - if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) - { - s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; - sign += s_1; - - for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) - { - if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) - { - s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; - - mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; - output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); - } - } - } - else - --usedLines; - } - - output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); - - delete[] AddSample; - } -} diff --git a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp deleted file mode 100644 index 4a268f824d..0000000000 --- a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp +++ /dev/null @@ -1,517 +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 "mitkPhotoacousticImage.h" -#include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" -#include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" -#include "mitkImageCast.h" -#include "mitkITKImageImport.h" -#include "mitkPhotoacousticBeamformingFilter.h" -#include -#include -#include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" - - -// itk dependencies -#include "itkImage.h" -#include "itkResampleImageFilter.h" -#include "itkCastImageFilter.h" -#include "itkCropImageFilter.h" -#include "itkRescaleIntensityImageFilter.h" -#include "itkIntensityWindowingImageFilter.h" -#include -#include "itkMultiplyImageFilter.h" -#include "itkBSplineInterpolateImageFunction.h" -#include - -// needed itk image filters -#include "mitkITKImageImport.h" -#include "itkFFTShiftImageFilter.h" -#include "itkMultiplyImageFilter.h" -#include "itkComplexToModulusImageFilter.h" -#include -#include "../ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" -#include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" - -mitk::PhotoacousticImage::PhotoacousticImage() : m_BeamformingFilter(BeamformingFilter::New()) -{ - MITK_INFO << "[PhotoacousticImage Debug] created that image"; -} - -mitk::PhotoacousticImage::~PhotoacousticImage() -{ - MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) -{ - // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage - typedef itk::Image< float, 3 > itkFloatImageType; - typedef itk::IdentityTransform TransformType; - - if (method == BModeMethod::Abs) - { - mitk::Image::Pointer input; - mitk::Image::Pointer out; - if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") - input = inputImage; - else - input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); - - if (!UseGPU) - { - PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); - - out = filter->GetOutput(); - - if (resampleSpacing == 0) - return out; - } - #ifdef PHOTOACOUSTICS_USE_GPU - else - { - PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); - filter->SetParameters(UseLogFilter); - filter->SetInput(input); - filter->Update(); - - out = filter->GetOutput(); - - if (resampleSpacing == 0) - return out; - } - #endif - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - - itkFloatImageType::Pointer itkImage; - mitk::CastToItkImage(out, itkImage); - itkFloatImageType::SpacingType outputSpacing; - itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSize = inputSize; - - outputSpacing[0] = itkImage->GetSpacing()[0]; - outputSpacing[1] = resampleSpacing; - outputSpacing[2] = itkImage->GetSpacing()[2]; - - outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; - - typedef itk::IdentityTransform TransformType; - resampleImageFilter->SetInput(itkImage); - resampleImageFilter->SetSize(outputSize); - resampleImageFilter->SetOutputSpacing(outputSpacing); - resampleImageFilter->SetTransform(TransformType::New()); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); - } - else if (method == BModeMethod::EnvelopeDetection) - { - typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; - BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter - - typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; - PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - - itkFloatImageType::Pointer itkImage; - - mitk::CastToItkImage(inputImage, itkImage); - - itkFloatImageType::Pointer bmode; - - if (UseLogFilter) - { - bModeFilter->SetInput(itkImage); - bModeFilter->SetDirection(1); - bmode = bModeFilter->GetOutput(); - } - else - { - photoacousticBModeFilter->SetInput(itkImage); - photoacousticBModeFilter->SetDirection(1); - bmode = photoacousticBModeFilter->GetOutput(); - } - - // resampleSpacing == 0 means: do no resampling - if (resampleSpacing == 0) - { - return mitk::GrabItkImageMemory(bmode); - } - - itkFloatImageType::SpacingType outputSpacing; - itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSize = inputSize; - - outputSpacing[0] = itkImage->GetSpacing()[0]; - outputSpacing[1] = resampleSpacing; - outputSpacing[2] = itkImage->GetSpacing()[2]; - - outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; - - resampleImageFilter->SetInput(bmode); - resampleImageFilter->SetSize(outputSize); - resampleImageFilter->SetOutputSpacing(outputSpacing); - resampleImageFilter->SetTransform(TransformType::New()); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); - } - return nullptr; -} - -/*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) -{ - typedef itk::Image< float, 3 > itkFloatImageType; - typedef itk::MultiplyImageFilter MultiplyImageFilterType; - - itkFloatImageType::Pointer itkImage; - mitk::CastToItkImage(inputImage, itkImage); - - MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); - multiplyFilter->SetInput1(itkImage); - multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); - - return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); -}*/ - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) -{ - typedef itk::Image< float, 3 > itkFloatImageType; - - typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; - ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); - typedef itk::LinearInterpolateImageFunction T_Interpolator; - itkFloatImageType::Pointer itkImage; - - mitk::CastToItkImage(inputImage, itkImage); - - itkFloatImageType::SpacingType outputSpacingItk; - itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); - itkFloatImageType::SizeType outputSizeItk = inputSizeItk; - - outputSizeItk[0] = outputSize[0]; - outputSizeItk[1] = outputSize[1]; - outputSizeItk[2] = inputSizeItk[2]; - - outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); - outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); - outputSpacingItk[2] = itkImage->GetSpacing()[2]; - - typedef itk::IdentityTransform TransformType; - T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); - resampleImageFilter->SetInput(itkImage); - resampleImageFilter->SetSize(outputSizeItk); - resampleImageFilter->SetOutputSpacing(outputSpacingItk); - resampleImageFilter->SetTransform(TransformType::New()); - resampleImageFilter->SetInterpolator(_pInterpolator); - - resampleImageFilter->UpdateLargestPossibleRegion(); - return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) -{ - - unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; - unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; - - void* inputData; - float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; - - ImageReadAccessor acc(inputImage); - inputData = const_cast(acc.GetData()); - - // convert the data to float by default - // as of now only float, short, double are used at all. - if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") - { - // copy the data into the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") - { - // copy the data to the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") - { - // copy the data to the cropped image - for (unsigned short sl = 0; sl < outputDim[2]; ++sl) - { - for (unsigned short l = 0; l < outputDim[0]; ++l) - { - for (unsigned short s = 0; s < outputDim[1]; ++s) - { - outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; - } - } - } - } - else - { - MITK_INFO << "Could not determine pixel type"; - } - - mitk::Image::Pointer output = mitk::Image::New(); - output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); - output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); - output->SetImportVolume(outputData, 0, 0, mitk::Image::CopyMemory); - delete[] outputData; - return output; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle) -{ - Image::Pointer processedImage = inputImage; - if (inputImage->GetDimension() != 3) - { - processedImage->Initialize(mitk::MakeScalarPixelType(), 3, inputImage->GetDimensions()); - processedImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); - - mitk::ImageReadAccessor copy(inputImage); - - processedImage->SetImportVolume(copy.GetData()); - } - - config.RecordTime = config.RecordTime - (float)(config.upperCutoff) / (float)inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping - progressHandle(0, "converting image"); - if (!config.partial) - { - config.CropBounds[0] = 0; - config.CropBounds[1] = inputImage->GetDimension(2) - 1; - } - processedImage = ApplyCropping(inputImage, config.upperCutoff, 0, 0, 0, config.CropBounds[0], config.CropBounds[1]); - - config.inputDim[0] = processedImage->GetDimension(0); - config.inputDim[1] = processedImage->GetDimension(1); - config.inputDim[2] = processedImage->GetDimension(2); - - // perform the beamforming - m_BeamformingFilter->SetInput(processedImage); - m_BeamformingFilter->Configure(config); - m_BeamformingFilter->SetProgressHandle(progressHandle); - m_BeamformingFilter->UpdateLargestPossibleRegion(); - - processedImage = m_BeamformingFilter->GetOutput(); - message = m_BeamformingFilter->GetMessageString(); - - return processedImage; -} - -mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, - float BPHighPass, float BPLowPass, - float alphaHighPass, float alphaLowPass) -{ - bool powerOfTwo = false; - int finalPower = 0; - for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) - { - finalPower = i; - if (pow(2, i) == data->GetDimension(1)) - { - powerOfTwo = true; - } - } - if (!powerOfTwo) - { - unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; - data = ApplyResampling(data, dim); - } - - MITK_INFO << data->GetDimension(0); - - // do a fourier transform, multiply with an appropriate window for the filter, and transform back - typedef float PixelType; - typedef itk::Image< PixelType, 3 > RealImageType; - RealImageType::Pointer image; - - mitk::CastToItkImage(data, image); - - typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; - typedef ForwardFFTFilterType::OutputImageType ComplexImageType; - ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); - forwardFFTFilter->SetInput(image); - forwardFFTFilter->SetDirection(1); - try - { - forwardFFTFilter->UpdateOutputInformation(); - } - catch (itk::ExceptionObject & error) - { - std::cerr << "Error: " << error << std::endl; - MITK_WARN << "Bandpass could not be applied"; - return data; - } - - float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; - float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); - float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); - - RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alphaHighPass, alphaLowPass); - - typedef itk::MultiplyImageFilter< ComplexImageType, - RealImageType, - ComplexImageType > - MultiplyFilterType; - MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); - multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); - multiplyFilter->SetInput2(fftMultiplicator); - - /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); - toReal->SetInput(forwardFFTFilter->GetOutput()); - return GrabItkImageMemory(toReal->GetOutput()); - return GrabItkImageMemory(fftMultiplicator); *///DEBUG - - typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; - InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); - inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); - inverseFFTFilter->SetDirection(1); - - return GrabItkImageMemory(inverseFFTFilter->GetOutput()); -} - -itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, - int cutoffFrequencyPixelHighPass, - int cutoffFrequencyPixelLowPass, - float alphaHighPass, float alphaLowPass) -{ - float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; - - float width = reference->GetDimension(1) / 2.0 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; - float center = (float)cutoffFrequencyPixelHighPass / 2.0 + width / 2.0; - - for (unsigned int n = 0; n < reference->GetDimension(1); ++n) - { - imageData[reference->GetDimension(0)*n] = 0; - } - for (int n = 0; n < width; ++n) - { - imageData[reference->GetDimension(0)*n] = 1; - if (n <= (alphaHighPass*(width - 1)) / 2.0) - { - if (alphaHighPass > 0.00001) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = - (1 + cos(itk::Math::pi*(2 * n / (alphaHighPass*(width - 1)) - 1))) / 2; - } - else - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; - } - } - else if (n >= (width - 1)*(1 - alphaLowPass / 2)) //??? - { - if (alphaLowPass > 0.00001) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = - (1 + cos(itk::Math::pi*(2 * n / (alphaLowPass*(width - 1)) + 1 - 2 / alphaLowPass))) / 2; - } - else - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; - } - } - //MITK_INFO << "n:" << n << " is " << imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))]; - } - MITK_INFO << "width: " << width << ", center: " << center << ", alphaHighPass: " << alphaHighPass << ", alphaLowPass: " << alphaLowPass; - - // mirror the first half of the image - for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) - { - imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; - } - - - // copy and paste to all lines - for (unsigned int line = 1; line < reference->GetDimension(0); ++line) - { - for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) - { - imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; - } - } - - typedef itk::Image< float, 3U > ImageType; - ImageType::RegionType region; - ImageType::IndexType start; - start.Fill(0); - - region.SetIndex(start); - - ImageType::SizeType size; - size[0] = reference->GetDimension(0); - size[1] = reference->GetDimension(1); - size[2] = reference->GetDimension(2); - - region.SetSize(size); - - ImageType::SpacingType SpacingItk; - SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; - SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; - SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; - - ImageType::Pointer image = ImageType::New(); - image->SetRegions(region); - image->Allocate(); - image->FillBuffer(itk::NumericTraits::Zero); - image->SetSpacing(SpacingItk); - - ImageType::IndexType pixelIndex; - - for (unsigned int slice = 0; slice < reference->GetDimension(2); ++slice) - { - for (unsigned int line = 0; line < reference->GetDimension(0); ++line) - { - for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) - { - pixelIndex[0] = line; - pixelIndex[1] = sample; - pixelIndex[2] = slice; - - image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); - } - } - } - - delete[] imageData; - - return image; -} diff --git a/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp b/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp new file mode 100644 index 0000000000..b000906692 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/utils/mitkBeamformingUtils.cpp @@ -0,0 +1,563 @@ +/*=================================================================== +mitkPhotoacousticBeamformingFilter +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 "mitkImageReadAccessor.h" +#include +#include +#include +#include +#include +#include "mitkImageCast.h" +#include "mitkBeamformingUtils.h" + +mitk::BeamformingUtils::BeamformingUtils() +{ +} + +mitk::BeamformingUtils::~BeamformingUtils() +{ +} + +float* mitk::BeamformingUtils::VonHannFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = (1 - cos(2 * itk::Math::pi * n / (samples - 1))) / 2; + } + + return ApodWindow; +} + +float* mitk::BeamformingUtils::HammFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 0.54 - 0.46*cos(2 * itk::Math::pi*n / (samples - 1)); + } + + return ApodWindow; +} + +float* mitk::BeamformingUtils::BoxFunction(int samples) +{ + float* ApodWindow = new float[samples]; + + for (int n = 0; n < samples; ++n) + { + ApodWindow[n] = 1; + } + + return ApodWindow; +} + +void mitk::BeamformingUtils::DASQuadraticLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / + config->GetPitchInMeters() * inputL / config->GetTransducerElements(); + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = delayMultiplicator * pow((l_s - l_i), 2) + s_i + (1 - config->GetIsPhotoacousticImage())*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * + apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + +void mitk::BeamformingUtils::DASSphericalLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short AddSample = 0; + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * + config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); + float apod_mult = 1; + + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + for (short l_s = minLine; l_s < maxLine; ++l_s) + { + AddSample = (int)sqrt( + pow(s_i, 2) + + + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (((float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) + ) + (1 - config->GetIsPhotoacousticImage())*s_i; + if (AddSample < inputS && AddSample >= 0) + output[sample*(short)outputL + line] += input[l_s + AddSample*(short)inputL] * + apodisation[(short)((l_s - minLine)*apod_mult)]; + else + --usedLines; + } + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / usedLines; + } +} + +void mitk::BeamformingUtils::DMASQuadraticLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * + config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); + float apod_mult = 1; + + float mult = 0; + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + + (1 - config->GetIsPhotoacousticImage())*s_i; + } + + float s_1 = 0; + float s_2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} + +void mitk::BeamformingUtils::DMASSphericalLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * + config->GetSpeedOfSound() / config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); + float apod_mult = 1; + + float mult = 0; + + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)sqrt( + pow(s_i, 2) + + + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (((float)minLine + (float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) + ) + (1 - config->GetIsPhotoacousticImage())*s_i; + } + + float s_1 = 0; + float s_2 = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)); + + delete[] AddSample; + } +} + +void mitk::BeamformingUtils::sDMASQuadraticLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float delayMultiplicator = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / + config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); + float apod_mult = 1; + + float mult = 0; + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + delayMultiplicator = pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (config->GetPitchInMeters()*config->GetTransducerElements()) / inputL), 2) / s_i / 2; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)(delayMultiplicator * pow((minLine + l_s - l_i), 2) + s_i) + + (1 - config->GetIsPhotoacousticImage())*s_i; + } + + float s_1 = 0; + float s_2 = 0; + float sign = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + sign += s_1; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); + + delete[] AddSample; + } +} + +void mitk::BeamformingUtils::sDMASSphericalLine( + float* input, float* output, float inputDim[2], float outputDim[2], + const short& line, const mitk::BeamformingSettings::Pointer config) +{ + const float* apodisation = config->GetApodizationFunction(); + const short apodArraySize = config->GetApodizationArraySize(); + + float& inputS = inputDim[1]; + float& inputL = inputDim[0]; + + float& outputS = outputDim[1]; + float& outputL = outputDim[0]; + + short maxLine = 0; + short minLine = 0; + float l_i = 0; + float s_i = 0; + + float part = 0.07 * inputL; + float tan_phi = std::tan(config->GetAngle() / 360 * 2 * itk::Math::pi); + float part_multiplicator = tan_phi * config->GetTimeSpacing() * config->GetSpeedOfSound() / + config->GetPitchInMeters() * inputL / (float)config->GetTransducerElements(); + float apod_mult = 1; + + float mult = 0; + + short usedLines = (maxLine - minLine); + + float percentOfImageReconstructed = (float)(config->GetReconstructionDepth()) / + (float)(inputS * config->GetSpeedOfSound() * config->GetTimeSpacing() / (float)(2 - (int)config->GetIsPhotoacousticImage())); + percentOfImageReconstructed = percentOfImageReconstructed <= 1 ? percentOfImageReconstructed : 1; + + l_i = (float)line / outputL * inputL; + + for (short sample = 0; sample < outputS; ++sample) + { + s_i = (float)sample / outputS * inputS / (float)(2 - (int)config->GetIsPhotoacousticImage()) * percentOfImageReconstructed; + + part = part_multiplicator*s_i; + + if (part < 1) + part = 1; + + maxLine = (short)std::min((l_i + part) + 1, inputL); + minLine = (short)std::max((l_i - part), 0.0f); + usedLines = (maxLine - minLine); + + apod_mult = (float)apodArraySize / (float)usedLines; + + //calculate the AddSamples beforehand to save some time + short* AddSample = new short[maxLine - minLine]; + for (short l_s = 0; l_s < maxLine - minLine; ++l_s) + { + AddSample[l_s] = (short)sqrt( + pow(s_i, 2) + + + pow((1 / (config->GetTimeSpacing()*config->GetSpeedOfSound()) * + (((float)minLine + (float)l_s - l_i)*config->GetPitchInMeters()*(float)config->GetTransducerElements()) / inputL), 2) + ) + (1 - config->GetIsPhotoacousticImage())*s_i; + } + + float s_1 = 0; + float s_2 = 0; + float sign = 0; + + for (short l_s1 = minLine; l_s1 < maxLine - 1; ++l_s1) + { + if (AddSample[l_s1 - minLine] < inputS && AddSample[l_s1 - minLine] >= 0) + { + s_1 = input[l_s1 + AddSample[l_s1 - minLine] * (short)inputL]; + sign += s_1; + + for (short l_s2 = l_s1 + 1; l_s2 < maxLine; ++l_s2) + { + if (AddSample[l_s2 - minLine] < inputS && AddSample[l_s2 - minLine] >= 0) + { + s_2 = input[l_s2 + AddSample[l_s2 - minLine] * (short)inputL]; + + mult = s_2 * apodisation[(int)((l_s2 - minLine)*apod_mult)] * s_1 * apodisation[(int)((l_s1 - minLine)*apod_mult)]; + output[sample*(short)outputL + line] += sqrt(fabs(mult)) * ((mult > 0) - (mult < 0)); + } + } + } + else + --usedLines; + } + + output[sample*(short)outputL + line] = output[sample*(short)outputL + line] / (float)(pow(usedLines, 2) - (usedLines - 1)) * ((sign > 0) - (sign < 0)); + + delete[] AddSample; + } +} diff --git a/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp b/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp new file mode 100644 index 0000000000..2ab8cbca1c --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/source/utils/mitkPhotoacousticFilterService.cpp @@ -0,0 +1,233 @@ +/*=================================================================== + +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 "mitkPhotoacousticFilterService.h" + +#include "mitkITKImageImport.h" +#include +#include +#include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" +#include "mitkConvert2Dto3DImageFilter.h" +#include +#include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" +#include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" +#include + +// itk dependencies +#include "itkImage.h" +#include "itkResampleImageFilter.h" +#include "itkCastImageFilter.h" +#include "itkCropImageFilter.h" +#include "itkRescaleIntensityImageFilter.h" +#include "itkIntensityWindowingImageFilter.h" +#include +#include "itkBSplineInterpolateImageFunction.h" +#include + +// needed itk image filters +#include "mitkImageCast.h" + +mitk::PhotoacousticFilterService::PhotoacousticFilterService() +{ + MITK_INFO << "[PhotoacousticFilterService] created filter service"; +} + +mitk::PhotoacousticFilterService::~PhotoacousticFilterService() +{ + MITK_INFO << "[PhotoacousticFilterService] destructed filter service"; +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBmodeFilter( + mitk::Image::Pointer inputImage, + BModeMethod method, bool UseLogFilter) +{ + // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage + typedef itk::Image< float, 3 > itkFloatImageType; + + auto floatImage = ConvertToFloat(inputImage); + + if (method == BModeMethod::Abs) + { + PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); + filter->UseLogFilter(UseLogFilter); + filter->SetInput(floatImage); + filter->Update(); + return filter->GetOutput(); + } + + typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; + BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter + + typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; + PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(floatImage, itkImage); + + if (UseLogFilter) + { + bModeFilter->SetInput(itkImage); + bModeFilter->SetDirection(1); + itkImage = bModeFilter->GetOutput(); + } + else + { + photoacousticBModeFilter->SetInput(itkImage); + photoacousticBModeFilter->SetDirection(1); + itkImage = photoacousticBModeFilter->GetOutput(); + } + + return mitk::GrabItkImageMemory(itkImage); +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyResampling( + mitk::Image::Pointer inputImage, + double outputSpacing[2]) +{ + typedef itk::Image< float, 3 > itkFloatImageType; + + auto floatImage = ConvertToFloat(inputImage); + + typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; + ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); + + itkFloatImageType::Pointer itkImage; + + mitk::CastToItkImage(floatImage, itkImage); + + itkFloatImageType::SpacingType outputSpacingItk; + itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); + itkFloatImageType::SizeType outputSizeItk = inputSizeItk; + + outputSpacingItk[0] = outputSpacing[0]; + outputSpacingItk[1] = outputSpacing[1]; + outputSpacingItk[2] = itkImage->GetSpacing()[2]; + + outputSizeItk[0] = outputSizeItk[0] * (floatImage->GetGeometry()->GetSpacing()[0] / outputSpacing[0]); + outputSizeItk[1] = outputSizeItk[1] * (floatImage->GetGeometry()->GetSpacing()[1] / outputSpacing[1]); + + resampleImageFilter->SetInput(itkImage); + resampleImageFilter->SetSize(outputSizeItk); + resampleImageFilter->SetOutputSpacing(outputSpacingItk); + + resampleImageFilter->UpdateLargestPossibleRegion(); + return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyCropping( + mitk::Image::Pointer inputImage, + int above, int below, + int right, int left, + int zStart, int zEnd) +{ + try + { + auto floatImage = ConvertToFloat(inputImage); + mitk::CropImageFilter::Pointer cropImageFilter = mitk::CropImageFilter::New(); + cropImageFilter->SetInput(floatImage); + cropImageFilter->SetXPixelsCropStart(left); + cropImageFilter->SetXPixelsCropEnd(right); + cropImageFilter->SetYPixelsCropStart(above); + cropImageFilter->SetYPixelsCropEnd(below); + cropImageFilter->SetZPixelsCropStart(zStart); + cropImageFilter->SetZPixelsCropEnd(zEnd); + cropImageFilter->Update(); + return cropImageFilter->GetOutput(); + } + catch (mitk::Exception &e) + { + std::string errorMessage = "Caught unexpected exception "; + errorMessage.append(e.what()); + MITK_ERROR << errorMessage; + + return inputImage; + } +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBeamforming( + mitk::Image::Pointer inputImage, + BeamformingSettings::Pointer config, + std::function progressHandle) +{ + Image::Pointer processedImage = mitk::Image::New(); + + if (inputImage->GetDimension() != 3) + { + mitk::Convert2Dto3DImageFilter::Pointer dimensionImageFilter = mitk::Convert2Dto3DImageFilter::New(); + dimensionImageFilter->SetInput(inputImage); + dimensionImageFilter->Update(); + processedImage = dimensionImageFilter->GetOutput(); + } + else + { + processedImage = inputImage; + } + + m_BeamformingFilter = mitk::BeamformingFilter::New(config); + m_BeamformingFilter->SetInput(ConvertToFloat(processedImage)); + m_BeamformingFilter->SetProgressHandle(progressHandle); + m_BeamformingFilter->UpdateLargestPossibleRegion(); + + processedImage = m_BeamformingFilter->GetOutput(); + + return processedImage; +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ApplyBandpassFilter( + mitk::Image::Pointer data, + float BPHighPass, float BPLowPass, + float alphaHighPass, float alphaLowPass) +{ + try + { + auto floatData = ConvertToFloat(data); + mitk::BandpassFilter::Pointer bandpassFilter = mitk::BandpassFilter::New(); + bandpassFilter->SetInput(floatData); + bandpassFilter->SetHighPass(BPHighPass); + bandpassFilter->SetLowPass(BPLowPass); + bandpassFilter->SetHighPassAlpha(alphaHighPass); + bandpassFilter->SetLowPassAlpha(alphaLowPass); + bandpassFilter->Update(); + return bandpassFilter->GetOutput(); + } + + catch (mitk::Exception &e) + { + std::string errorMessage = "Caught unexpected exception "; + errorMessage.append(e.what()); + MITK_ERROR << errorMessage; + + return data; + } +} + +mitk::Image::Pointer mitk::PhotoacousticFilterService::ConvertToFloat(mitk::Image::Pointer inputImage) +{ + if ((inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || + inputImage->GetPixelType().GetTypeAsString() == " (float)")) + { + return inputImage; + } + + mitk::CastToFloatImageFilter::Pointer castToFloatImageFilter = mitk::CastToFloatImageFilter::New(); + castToFloatImageFilter->SetInput(inputImage); + castToFloatImageFilter->Update(); + return castToFloatImageFilter->GetOutput(); +} diff --git a/Modules/PhotoacousticsAlgorithms/test/CMakeLists.txt b/Modules/PhotoacousticsAlgorithms/test/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/PhotoacousticsLib/test/files.cmake b/Modules/PhotoacousticsAlgorithms/test/files.cmake similarity index 54% copy from Modules/PhotoacousticsLib/test/files.cmake copy to Modules/PhotoacousticsAlgorithms/test/files.cmake index ae1e015083..2fe7e9fa64 100644 --- a/Modules/PhotoacousticsLib/test/files.cmake +++ b/Modules/PhotoacousticsAlgorithms/test/files.cmake @@ -1,40 +1,24 @@ set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## ON THE FENCE TESTS ################################################# # none ################## DISABLED TESTS ##################################################### ################# RUNNING TESTS ####################################################### - mitkSlicedVolumeGeneratorTest.cpp - mitkPhotoacousticTissueGeneratorTest.cpp - mitkPhotoacousticVectorTest.cpp - mitkPhotoacoustic3dVolumeTest.cpp - mitkPhotoacousticVolumeTest.cpp - mitkPhotoacousticVesselTest.cpp - mitkPhotoacousticVesselTreeTest.cpp - mitkPhotoacousticVesselMeanderStrategyTest.cpp - mitkMcxyzXmlTest.cpp - mitkPhotoacousticComposedVolumeTest.cpp - mitkPhotoacousticNoiseGeneratorTest.cpp - mitkPhotoacousticIOTest.cpp - mitkMCThreadHandlerTest.cpp - mitkSimulationBatchGeneratorTest.cpp - mitkPropertyCalculatorTest.cpp -) -set(RESOURCE_FILES - pointsource.xml - circlesource.xml - rectanglesource.xml - twopointsources.xml - allsources.xml + mitkPAFilterServiceTest.cpp + mitkCastToFloatImageFilterTest.cpp + mitkBandpassFilterTest.cpp + mitkBeamformingFilterTest.cpp + mitkCropImageFilterTest.cpp ) +set(RESOURCE_FILES) diff --git a/Modules/PhotoacousticsAlgorithms/test/mitkBandpassFilterTest.cpp b/Modules/PhotoacousticsAlgorithms/test/mitkBandpassFilterTest.cpp new file mode 100644 index 0000000000..b3b319f35b --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/mitkBandpassFilterTest.cpp @@ -0,0 +1,194 @@ +/*=================================================================== + +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 + +#include +#include +#include +#include +#include +#include +#include + +#include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" +#include "mitkImageCast.h" +#include "mitkITKImageImport.h" +#include "itkComplexToModulusImageFilter.h" + +class mitkBandpassFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkBandpassFilterTestSuite); + MITK_TEST(testHighPass); + MITK_TEST(testLowPass); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::BandpassFilter::Pointer m_BandpassFilter; + const unsigned int NUM_ITERATIONS = 15; + const unsigned int DATA_XY_DIM = 512; + const unsigned int DATA_Z_DIM = 8; + const float TIME_SPACING = 0.00625; // [us] + const float FREQUENCY_RESOLUTION = 2 * M_PI / (TIME_SPACING * DATA_XY_DIM); // [MHz] + const float MAX_FREQUENCY = FREQUENCY_RESOLUTION * DATA_XY_DIM / 2.f; // [MHz] + const float HIGHPASS_FREQENCY = MAX_FREQUENCY * 0.8f; // [MHz] + const float LOWPASS_FREQENCY = MAX_FREQUENCY * 0.1f; // [MHz] + const float ALPHA = 0; // 0 = box, 1 = von Hann; changing this may make the test invalid + const float EPSILON_FFT = 0.00001f; + +public: + + void setUp() override + { + m_BandpassFilter = mitk::BandpassFilter::New(); + } + + void test(float HighPass, float LowPass, float HighPassAlpha, float LowPassAlpha, bool useLow, bool useHigh) + { + std::random_device r; + std::default_random_engine randGen(r()); + std::uniform_real_distribution randDistrHighPass(HighPass * 0.01f, HighPass * 0.2f); + std::uniform_real_distribution randDistrLowPass(LowPass * 1.5f, LowPass * 2.f); + float* data = new float[DATA_XY_DIM*DATA_XY_DIM*DATA_Z_DIM]; + + mitk::Image::Pointer inputImage = mitk::Image::New(); + unsigned int dimension[3]{ DATA_XY_DIM, DATA_XY_DIM, DATA_Z_DIM }; + inputImage->Initialize(mitk::MakeScalarPixelType(), 3, dimension); + mitk::Vector3D spacing; + spacing[0] = 1; + spacing[1] = TIME_SPACING; + spacing[2] = 1; + inputImage->SetSpacing(spacing); + + for (unsigned int iteration = 0; iteration < NUM_ITERATIONS; ++iteration) + { + // fill image with zeros + for (unsigned int i = 0; i < DATA_XY_DIM*DATA_XY_DIM*DATA_Z_DIM; ++i) + { + data[i] = 0; + } + + // write specific frequencies to the image + if (useHigh) + addFrequency(randDistrHighPass(randGen), TIME_SPACING, data, dimension); + if (useLow) + addFrequency(randDistrLowPass(randGen), TIME_SPACING, data, dimension); + + inputImage->SetImportVolume(data, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + + m_BandpassFilter->SetInput(inputImage); + + if (!useHigh) + HighPass = 0; + m_BandpassFilter->SetHighPass(HighPass); + + if(!useLow) + LowPass = MAX_FREQUENCY; + m_BandpassFilter->SetLowPass(LowPass); + + m_BandpassFilter->SetHighPassAlpha(HighPassAlpha); + m_BandpassFilter->SetLowPassAlpha(LowPassAlpha); + + m_BandpassFilter->Update(); + mitk::Image::Pointer outputImage = m_BandpassFilter->GetOutput(); + + // do a fourier transform, and check whether the part of the image that has been filtered is zero + typedef itk::Image< float, 3 > RealImageType; + RealImageType::Pointer image; + + mitk::CastToItkImage(outputImage, image); + + typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; + // typedef ForwardFFTFilterType::OutputImageType ComplexImageType; + ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); + forwardFFTFilter->SetInput(image); + forwardFFTFilter->SetDirection(1); + forwardFFTFilter->UpdateOutputInformation(); + forwardFFTFilter->Update(); + + auto fftResult = forwardFFTFilter->GetOutput(); + + // the resulting image should consist only of zeros, as we filtered the frequencies out + for (unsigned int z = 0; z < DATA_Z_DIM; ++z) + { + for (unsigned int y = 0; y < DATA_XY_DIM / 2; ++y) + { + if (y < (unsigned int)std::floor(HighPass / FREQUENCY_RESOLUTION) || y > (unsigned int)std::ceil(LowPass / FREQUENCY_RESOLUTION)) + { + for (unsigned int x = 0; x < DATA_XY_DIM; ++x) + { + // unsigned int outPos = x + y * DATA_XY_DIM + z * DATA_XY_DIM * DATA_XY_DIM; + std::complex value = fftResult->GetPixel({ x,y,z }); + CPPUNIT_ASSERT_MESSAGE(std::string("Expected 0, got (" + std::to_string(value.real()) + " + " + std::to_string(value.imag()) + "i) at " + std::to_string(x)+"-"+std::to_string(y)+"-"+std::to_string(z)), + (abs(value.real()) < EPSILON_FFT) && (abs(value.imag() < EPSILON_FFT))); + } + } + } + + for (unsigned int y = DATA_XY_DIM / 2; y < DATA_XY_DIM; ++y) + { + if (y > DATA_XY_DIM - (unsigned int)std::floor(HighPass / FREQUENCY_RESOLUTION) || y < DATA_XY_DIM - (unsigned int)std::ceil(LowPass / FREQUENCY_RESOLUTION)) + { + for (unsigned int x = 0; x < DATA_XY_DIM; ++x) + { + // unsigned int outPos = x + y * DATA_XY_DIM + z * DATA_XY_DIM * DATA_XY_DIM; + std::complex value = fftResult->GetPixel({ x,y,z }); + CPPUNIT_ASSERT_MESSAGE(std::string("Expected 0, got (" + std::to_string(value.real()) + " + " + std::to_string(value.imag()) + "i) at " + std::to_string(x) + "-" + std::to_string(y) + "-" + std::to_string(z)), + (abs(value.real()) < EPSILON_FFT) && (abs(value.imag() < EPSILON_FFT))); + } + } + } + } + } + + delete[] data; + } + + // write a fixed-frequency signal to the image + void addFrequency(float freq, float timeSpacing, float* data, unsigned int* dim) + { + for (unsigned int z = 0; z < dim[2]; ++z) + { + for (unsigned int y = 0; y < dim[1]; ++y) + { + for (unsigned int x = 0; x < dim[0]; ++x) + { + data[x + y*dim[0] + z*dim[0] * dim[1]] += std::sin(freq * timeSpacing * y); + } + } + } + } + + void testHighPass() + { + MITK_INFO << "Performing HighPass test"; + test(HIGHPASS_FREQENCY, 0, ALPHA, ALPHA, false, true); + } + + void testLowPass() + { + MITK_INFO << "Performing LowPass test"; + test(0, LOWPASS_FREQENCY, ALPHA, ALPHA, true, false); + } + + void tearDown() override + { + m_BandpassFilter = nullptr; + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkBandpassFilter) diff --git a/Modules/PhotoacousticsAlgorithms/test/mitkBeamformingFilterTest.cpp b/Modules/PhotoacousticsAlgorithms/test/mitkBeamformingFilterTest.cpp new file mode 100644 index 0000000000..8258e991e2 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/mitkBeamformingFilterTest.cpp @@ -0,0 +1,280 @@ +/*=================================================================== + +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 + +class SyntheticPAImageData +{ +public: + SyntheticPAImageData(float spacing_x, float spacing_y, unsigned int samples, unsigned int num_transducers, float speedOfSound) + { + m_Spacing_x = spacing_x; + m_Spacing_y = spacing_y; + m_TransducerElements = num_transducers; + m_Samples = samples; + m_SpeedOfSound = speedOfSound; + m_Data = new float[m_Samples*m_TransducerElements]; + + for (size_t i = 0; i < m_Samples * m_TransducerElements; ++i) + { + m_Data[i] = 0; + } + } + + ~SyntheticPAImageData() + { + delete[] m_Data; + } + + void AddWave(float origin_depth, float origin_x, float base_value= 10000) + { + AddLine(origin_depth, origin_x, base_value); + AddLine(origin_depth + 0.0001f, origin_x, -base_value); + } + + const float* GetData() + { + return (const float*)m_Data; + } + +private: + void AddLine(float origin_depth, unsigned int origin_x, float base_value = 10000) + { + for (unsigned int x = 0; x < m_TransducerElements; ++x) + { + float distance = std::abs((int)x - (int)origin_x); + float delay_in_seconds = std::sqrt(std::pow(origin_depth, 2) + std::pow(distance*m_Spacing_x, 2)) / m_SpeedOfSound; + int pixels = std::round(delay_in_seconds / m_Spacing_y); + + for (int index = -4; index < 9; ++index) + { + if ((int)pixels + index < (int)m_Samples && (int)pixels + index > 0) + { + m_Data[(size_t)(x + (pixels + index)*m_TransducerElements)] += base_value / std::sqrt(distance + 1); + } + } + } + } + + float* m_Data; + float m_Spacing_x; + float m_Spacing_y; + unsigned int m_TransducerElements; + unsigned int m_Samples; + float m_SpeedOfSound; +}; + +class mitkBeamformingFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkBeamformingFilterTestSuite); + MITK_TEST(testBeamformingCPU_DAS); + MITK_TEST(testBeamformingGPU_DAS); + MITK_TEST(testBeamformingCPU_DMAS); + MITK_TEST(testBeamformingGPU_DMAS); + MITK_TEST(testBeamformingCPU_sDMAS); + MITK_TEST(testBeamformingGPU_sDMAS); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::BeamformingFilter::Pointer m_BeamformingFilter; + const unsigned int NUM_ITERATIONS = 15; + const unsigned int SAMPLES = 5000 * 2; + const unsigned int RECONSTRUCTED_SAMPLES = 2048; + const unsigned int ELEMENTS = 128; + const unsigned int RECONSTRUCTED_LINES = 128; + const float SPEED_OF_SOUND = 1540; // m/s + const float SPACING_X = 0.3; // mm + const float SPACING_Y = 0.00625 / 2; // us + const unsigned int GPU_BATCH_SIZE = 16; + +public: + + void setUp() override + { + + } + + void test() + { + std::random_device r; + std::default_random_engine randGen(r()); + float maxDepthInMeters = SAMPLES * (SPACING_Y / 1000000) * SPEED_OF_SOUND / 2; + std::uniform_real_distribution randDistrDepth(maxDepthInMeters*0.1, maxDepthInMeters*0.8); + + for (unsigned int iteration = 0; iteration < NUM_ITERATIONS; ++iteration) + { + // create some synthetic input data + float depth_in_meters1 = randDistrDepth(randGen); + float depth_in_meters2 = randDistrDepth(randGen); + float depth_in_meters3 = randDistrDepth(randGen); + + unsigned int element1 = 29; + unsigned int element2 = 63; + unsigned int element3 = 98; + + SyntheticPAImageData image(SPACING_X / 1000.f, SPACING_Y / 1000000.f, SAMPLES, ELEMENTS, SPEED_OF_SOUND); + image.AddWave(depth_in_meters1, 29); + image.AddWave(depth_in_meters2, 63); + image.AddWave(depth_in_meters3, 98); + + mitk::Image::Pointer inputImage = mitk::Image::New(); + unsigned int dimension[3]{ ELEMENTS, SAMPLES, 1 }; + inputImage->Initialize(mitk::MakeScalarPixelType(), 3, dimension); + mitk::Vector3D spacing; + spacing[0] = SPACING_X; + spacing[1] = SPACING_Y; + spacing[2] = 1; + inputImage->SetSpacing(spacing); + inputImage->SetImportVolume((const void*)image.GetData(), mitk::Image::CopyMemory); + + // setup the beamforming filter + m_BeamformingFilter->SetInput(inputImage); + m_BeamformingFilter->Update(); + + mitk::Image::Pointer outputImage = m_BeamformingFilter->GetOutput(); + mitk::ImageReadAccessor readAccess(outputImage); + const float* outputData = (const float*)readAccess.GetData(); + + unsigned int pos1[3] = { element1, (unsigned int)std::round(depth_in_meters1 * 1000.f / outputImage->GetGeometry()->GetSpacing()[1]), 0 }; + unsigned int pos2[3] = { element2, (unsigned int)std::round(depth_in_meters2 * 1000.f / outputImage->GetGeometry()->GetSpacing()[1]), 0 }; + unsigned int pos3[3] = { element3, (unsigned int)std::round(depth_in_meters3 * 1000.f / outputImage->GetGeometry()->GetSpacing()[1]), 0 }; + + double average = 0; + + for (unsigned int i = 0; i < RECONSTRUCTED_LINES*RECONSTRUCTED_SAMPLES; ++i) + { + average += outputData[i] / (RECONSTRUCTED_LINES*RECONSTRUCTED_SAMPLES); + } + + CPPUNIT_ASSERT_MESSAGE(std::string("Iteration " + std::to_string(iteration) + ": first point source incorrectly reconstructed; should be > average*100, is " + + std::to_string(abs(outputData[pos1[0] + pos1[1] * RECONSTRUCTED_LINES]))) + " < " + std::to_string(average) + "*100" + , abs(outputData[pos1[0] + pos1[1]*RECONSTRUCTED_LINES] / average) > 100); + CPPUNIT_ASSERT_MESSAGE(std::string("Iteration " + std::to_string(iteration) + ": second point source incorrectly reconstructed; should be > average*100, is " + + std::to_string(abs(outputData[pos2[0] + pos2[1] * RECONSTRUCTED_LINES]))) + " < " + std::to_string(average) + "*100" + , abs(outputData[pos2[0] + pos2[1] * RECONSTRUCTED_LINES] / average) > 100); + CPPUNIT_ASSERT_MESSAGE(std::string("Iteration " + std::to_string(iteration) + ": third point source incorrectly reconstructed; should be > average*100, is " + + std::to_string(abs(outputData[pos3[0] + pos3[1] * RECONSTRUCTED_LINES]))) + " < " + std::to_string(average) + "*100" + , abs(outputData[pos3[0] + pos3[1] * RECONSTRUCTED_LINES] / average) > 100); + } + } + + mitk::BeamformingSettings::Pointer createConfig(bool UseGPU, unsigned int* inputDim, mitk::BeamformingSettings::BeamformingAlgorithm alg) + { + return mitk::BeamformingSettings::New(SPACING_X / 1000, + SPEED_OF_SOUND, + SPACING_Y / 1000000, + 27.f, + true, + RECONSTRUCTED_SAMPLES, + RECONSTRUCTED_LINES, + inputDim, + SPEED_OF_SOUND * (SPACING_Y / 1000000) * SAMPLES, + UseGPU, + GPU_BATCH_SIZE, + mitk::BeamformingSettings::DelayCalc::Spherical, + mitk::BeamformingSettings::Apodization::Box, + ELEMENTS * 2, + alg); + } + + void testBeamformingCPU_DAS() + { + MITK_INFO << "Started DAS test on CPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(false, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::DAS)); + + test(); + delete[] inputDim; + } + + void testBeamformingGPU_DAS() + { + MITK_INFO << "Started DAS test on GPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(true, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::DAS)); + + test(); + delete[] inputDim; + } + + void testBeamformingCPU_sDMAS() + { + MITK_INFO << "Started sDMAS test on CPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(false, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS)); + + test(); + delete[] inputDim; + } + + void testBeamformingGPU_sDMAS() + { + MITK_INFO << "Started sDMAS test on GPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(true, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS)); + + test(); + delete[] inputDim; + } + + void testBeamformingCPU_DMAS() + { + MITK_INFO << "Started DMAS test on CPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(false, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::DMAS)); + + test(); + delete[] inputDim; + } + + void testBeamformingGPU_DMAS() + { + MITK_INFO << "Started DMAS test on GPU"; + unsigned int* inputDim = new unsigned int[3]; + inputDim[0] = ELEMENTS; + inputDim[1] = SAMPLES; + inputDim[2] = 1; + m_BeamformingFilter = mitk::BeamformingFilter::New(createConfig(true, inputDim, mitk::BeamformingSettings::BeamformingAlgorithm::DMAS)); + + test(); + delete[] inputDim; + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkBeamformingFilter) diff --git a/Modules/PhotoacousticsAlgorithms/test/mitkCastToFloatImageFilterTest.cpp b/Modules/PhotoacousticsAlgorithms/test/mitkCastToFloatImageFilterTest.cpp new file mode 100644 index 0000000000..ab43018f02 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/mitkCastToFloatImageFilterTest.cpp @@ -0,0 +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 + +class mitkCastToFloatImageFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkCastToFloatImageFilterTestSuite); + MITK_TEST(testShortConversion); + MITK_TEST(testIntConversion); + MITK_TEST(testLongConversion); + MITK_TEST(testFloatConversion); + MITK_TEST(testDoubleConversion); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::CastToFloatImageFilter::Pointer m_CastToFloatImageFilter; + const unsigned int NUM_ITERATIONS = 15; + const unsigned int DATA_DIM = 10; + +public: + + void setUp() override + { + m_CastToFloatImageFilter = mitk::CastToFloatImageFilter::New(); + } + + template + void test() + { + TPixelType* data = new TPixelType[DATA_DIM*DATA_DIM*DATA_DIM]; + + for (unsigned int i = 0; i < DATA_DIM*DATA_DIM*DATA_DIM; ++i) + { + data[i] = (TPixelType)i; + } + + mitk::Image::Pointer inputImage = mitk::Image::New(); + unsigned int dimension[3]{ DATA_DIM, DATA_DIM, DATA_DIM }; + inputImage->Initialize(mitk::MakeScalarPixelType(), 3, dimension); + inputImage->SetImportVolume(data); + + for (unsigned int iteration = 0; iteration < NUM_ITERATIONS; ++iteration) + { + m_CastToFloatImageFilter->SetInput(inputImage); + m_CastToFloatImageFilter->Update(); + mitk::Image::Pointer outputImage = m_CastToFloatImageFilter->GetOutput(); + mitk::ImageReadAccessor readAccess(outputImage); + const float* outputData = (const float*)readAccess.GetData(); + for (unsigned int i = 0; i < DATA_DIM*DATA_DIM*DATA_DIM; ++i) + { + CPPUNIT_ASSERT_MESSAGE(std::string("expected " + std::to_string(data[i]) + " but was " + std::to_string(outputData[i])), abs(outputData[i] - data[i]) < mitk::eps); + } + } + } + + void testFloatConversion() + { + test(); + } + + void testShortConversion() + { + test(); + test(); + } + + void testIntConversion() + { + test(); + test(); + } + + void testDoubleConversion() + { + test(); + } + + void testLongConversion() + { + test(); + } + + void tearDown() override + { + m_CastToFloatImageFilter = nullptr; + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkCastToFloatImageFilter) diff --git a/Modules/PhotoacousticsAlgorithms/test/mitkCropImageFilterTest.cpp b/Modules/PhotoacousticsAlgorithms/test/mitkCropImageFilterTest.cpp new file mode 100644 index 0000000000..808382eb97 --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/mitkCropImageFilterTest.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 +#include +#include +#include +#include +#include + +class mitkCropImageFilterTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkCropImageFilterTestSuite); + MITK_TEST(testCropImage); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::CropImageFilter::Pointer m_CropImageFilter; + const unsigned int NUM_ITERATIONS = 5; + const unsigned int DATA_DIM = 25; + +public: + + void setUp() override + { + m_CropImageFilter = mitk::CropImageFilter::New(); + } + + void test() + { + std::random_device r; + std::default_random_engine randGen(r()); + std::uniform_int_distribution randDistr(0, (DATA_DIM / 2) - 1); + + float* data = new float[DATA_DIM*DATA_DIM*DATA_DIM]; + + for (unsigned int i = 0; i < DATA_DIM*DATA_DIM*DATA_DIM; ++i) + { + data[i] = (float)i; + } + + mitk::Image::Pointer inputImage = mitk::Image::New(); + unsigned int dimension[3]{ DATA_DIM, DATA_DIM, DATA_DIM }; + inputImage->Initialize(mitk::MakeScalarPixelType(), 3, dimension); + inputImage->SetImportVolume(data, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + + for (unsigned int iteration = 0; iteration < NUM_ITERATIONS; ++iteration) + { + unsigned int XPixelsCropStart = randDistr(randGen); + unsigned int YPixelsCropStart = randDistr(randGen); + unsigned int ZPixelsCropStart = randDistr(randGen); + unsigned int XPixelsCropEnd = randDistr(randGen); + unsigned int YPixelsCropEnd = randDistr(randGen); + unsigned int ZPixelsCropEnd = randDistr(randGen); + + unsigned int newXDim = DATA_DIM - XPixelsCropStart - XPixelsCropEnd; + unsigned int newYDim = DATA_DIM - YPixelsCropStart - YPixelsCropEnd; + unsigned int newZDim = DATA_DIM - ZPixelsCropStart - ZPixelsCropEnd; + + m_CropImageFilter->SetInput(inputImage); + + m_CropImageFilter->SetXPixelsCropStart(XPixelsCropStart); + m_CropImageFilter->SetYPixelsCropStart(YPixelsCropStart); + m_CropImageFilter->SetZPixelsCropStart(ZPixelsCropStart); + m_CropImageFilter->SetXPixelsCropEnd(XPixelsCropEnd); + m_CropImageFilter->SetYPixelsCropEnd(YPixelsCropEnd); + m_CropImageFilter->SetZPixelsCropEnd(ZPixelsCropEnd); + + m_CropImageFilter->Update(); + mitk::Image::Pointer outputImage = m_CropImageFilter->GetOutput(); + + mitk::ImageReadAccessor readAccess(outputImage); + const float* outputData = (const float*)readAccess.GetData(); + + CPPUNIT_ASSERT_MESSAGE(std::string("expected x size to be " + std::to_string(newXDim) + " but was " + std::to_string(outputImage->GetDimension(0))), newXDim == outputImage->GetDimension(0)); + CPPUNIT_ASSERT_MESSAGE(std::string("expected y size to be " + std::to_string(newYDim) + " but was " + std::to_string(outputImage->GetDimension(1))), newYDim == outputImage->GetDimension(1)); + CPPUNIT_ASSERT_MESSAGE(std::string("expected z size to be " + std::to_string(newZDim) + " but was " + std::to_string(outputImage->GetDimension(2))), newZDim == outputImage->GetDimension(2)); + + for (unsigned int z = 0; z < newZDim; ++z) + { + for (unsigned int y = 0; y < newYDim; ++y) + { + for (unsigned int x = 0; x < newXDim; ++x) + { + unsigned int origPos = (x + XPixelsCropStart) + (y + YPixelsCropStart) * DATA_DIM + (z + ZPixelsCropStart) * DATA_DIM * DATA_DIM; + unsigned int outPos = x + y * newXDim + z * newXDim * newYDim; + CPPUNIT_ASSERT_MESSAGE(std::string("expected " + std::to_string(data[origPos]) + + " but was " + std::to_string(outputData[outPos])), + abs((float)outputData[outPos] - (float)data[origPos]) < mitk::eps); + } + } + } + } + + delete[] data; + } + + void testCropImage() + { + for (int repetition = 0; repetition < 20; ++repetition) + { + MITK_INFO << "[" << (repetition + 1) << "/20]"; + test(); + } + } + + void tearDown() override + { + m_CropImageFilter = nullptr; + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkCropImageFilter) diff --git a/Modules/PhotoacousticsAlgorithms/test/mitkPAFilterServiceTest.cpp b/Modules/PhotoacousticsAlgorithms/test/mitkPAFilterServiceTest.cpp new file mode 100644 index 0000000000..70d0dd7f1b --- /dev/null +++ b/Modules/PhotoacousticsAlgorithms/test/mitkPAFilterServiceTest.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 +#include + +#include +#include +#include +#include + +// us +#include +#include +#include +#include +#include + +#include +#include + +class mitkPAFilterServiceTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPAFilterServiceTestSuite); + MITK_TEST(testRunning); + CPPUNIT_TEST_SUITE_END(); + +private: + + mitk::PhotoacousticFilterService::Pointer m_PhotoacousticFilterService; + mitk::BeamformingSettings::Pointer m_BeamformingSettings; + unsigned int* inputDimensions; + const int xDim = 16; + const int yDim = 128; + const int length = yDim * xDim; + +public: + + void setUp() override + { + m_PhotoacousticFilterService = mitk::PhotoacousticFilterService::New(); + m_BeamformingSettings = CreateBeamformingSettings(); + } + + mitk::BeamformingSettings::Pointer CreateBeamformingSettings() + { + inputDimensions = new unsigned int[length]; + inputDimensions[0] = yDim; + inputDimensions[1] = xDim; + mitk::BeamformingSettings::Pointer outputSettings = mitk::BeamformingSettings::New( + (float)(0.3 / 1000), + (float)(1500), + (float)(0.0125 / 1000000), + 27, + true, + 3000, + 128, + inputDimensions, + yDim * (0.0125 / 1000000) * (1500), + false, + 16, + mitk::BeamformingSettings::DelayCalc::Spherical, + mitk::BeamformingSettings::Apodization::Box, + 128, + mitk::BeamformingSettings::BeamformingAlgorithm::DAS); + + return outputSettings; + } + + void testRunning() + { + float* testArray = new float[length]; + for (int i = 0; i < length; ++i) + { + testArray[i] = 0; + } + + mitk::PixelType pixelType = mitk::MakeScalarPixelType(); + mitk::Image::Pointer testImage = mitk::Image::New(); + testImage->Initialize(pixelType, 2, inputDimensions); + testImage->SetImportSlice(testArray, 0, 0, 0, mitk::Image::ImportMemoryManagementType::CopyMemory); + delete[] testArray; + + mitk::ImageReadAccessor readAccessInput(testImage); + const float* inputArray = (const float*)readAccessInput.GetData(); + + for (int i = 0; i < length; ++i) + { + CPPUNIT_ASSERT_MESSAGE(std::string("Input array already not correct: " + std::to_string(inputArray[i])), abs(inputArray[i]) < 1e-5f); + } + + auto output = m_PhotoacousticFilterService->ApplyBeamforming(testImage, m_BeamformingSettings); + + mitk::ImageReadAccessor readAccess(output); + const float* outputArray = (const float*)readAccess.GetData(); + + for (int i = 0; i < length; ++i) + { + CPPUNIT_ASSERT_MESSAGE(std::string("Output array not correct: " + std::to_string(abs(outputArray[i]))), abs(outputArray[i]) < 1e-5f); + } + } + + void tearDown() override + { + m_PhotoacousticFilterService = nullptr; + delete[] inputDimensions; + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPAFilterService) diff --git a/Modules/PhotoacousticsLib/CMakeLists.txt b/Modules/PhotoacousticsLib/CMakeLists.txt index 8c89b2658e..0ae41f8f5c 100644 --- a/Modules/PhotoacousticsLib/CMakeLists.txt +++ b/Modules/PhotoacousticsLib/CMakeLists.txt @@ -1,12 +1,15 @@ MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC include INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} DEPENDS PUBLIC MitkAlgorithmsExt tinyxml PACKAGE_DEPENDS tinyxml PUBLIC ITK ) add_subdirectory(MitkMCxyz) +add_subdirectory(MitkTissueBatchGenerator) +add_subdirectory(MitkPAPhantomGenerator) + add_subdirectory(test) diff --git a/Modules/PhotoacousticsLib/MitkMCxyz/MitkMCxyz.cpp b/Modules/PhotoacousticsLib/MitkMCxyz/MitkMCxyz.cpp index a557042cb0..6a375706a9 100644 --- a/Modules/PhotoacousticsLib/MitkMCxyz/MitkMCxyz.cpp +++ b/Modules/PhotoacousticsLib/MitkMCxyz/MitkMCxyz.cpp @@ -1,1472 +1,1474 @@ /*=================================================================== 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. ===================================================================*/ // Please retain the following copyright notice /****************************************************************** * based on mcxyz.c Oct2014 * * mcxyz.c, in ANSI Standard C programing language * * created 2010, 2012 by * Steven L. JACQUES * Ting LI * Oregon Health & Science University * *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include "mitkImageCast.h" #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #include #endif #define ls 1.0E-7 /* Moving photon a little bit off the voxel face */ #define PI 3.1415926 #define ALIVE 1 /* if photon not yet terminated */ #define DEAD 0 /* if photon is to be terminated */ #define THRESHOLD 0.01 /* used in roulette */ #define CHANCE 0.1 /* used in roulette */ #define SQR(x) (x*x) #define SIGN(x) ((x)>=0 ? 1:-1) #define ONE_MINUS_COSZERO 1.0E-12 /* If 1-cos(theta) <= ONE_MINUS_COSZERO, fabs(theta) <= 1e-6 rad. */ /* If 1+cos(theta) <= ONE_MINUS_COSZERO, fabs(PI-theta) <= 1e-6 rad. */ /* Struct for storing x,y and z coordinates */ struct Location { int x, y, z; double absorb; }; struct Location initLocation(int x, int y, int z, double absorb) { struct Location loc; loc.x = x; loc.y = y; loc.z = z; loc.absorb = absorb; return loc; } class DetectorVoxel { public: Location location; std::vector* recordedPhotonRoute = new std::vector(); double* fluenceContribution; double m_PhotonNormalizationValue; long m_NumberPhotonsCurrent; DetectorVoxel(Location location, long totalNumberOfVoxels, double photonNormalizationValue) { this->location = location; this->fluenceContribution = (double *)malloc(totalNumberOfVoxels * sizeof(double)); for (int j = 0; j < totalNumberOfVoxels; j++) fluenceContribution[j] = 0; // ensure fluenceContribution[] starts empty. m_NumberPhotonsCurrent = 0; m_PhotonNormalizationValue = photonNormalizationValue; } }; bool verbose(false); class InputValues { private: std::string inputFilename; int tissueIterator; long long ix, iy, iz; public: int mcflag, launchflag, boundaryflag; double xfocus, yfocus, zfocus; double ux0, uy0, uz0; double radius; double waist; double xs, ys, zs; /* launch position */ int Nx, Ny, Nz, numberOfTissueTypes; /* # of bins */ char* tissueType; double* muaVector; double* musVector; double* gVector; double* normalizationVector; double xSpacing, ySpacing, zSpacing; double simulationTimeFromFile; long long Nphotons; long totalNumberOfVoxels; double* totalFluence; std::string myname; DetectorVoxel* detectorVoxel; mitk::Image::Pointer m_inputImage; mitk::Image::Pointer m_normalizationImage; InputValues() { tissueType = nullptr; muaVector = nullptr; musVector = nullptr; gVector = nullptr; detectorVoxel = nullptr; normalizationVector = nullptr; mcflag = 0; launchflag = 0; boundaryflag = 0; } double GetNormalizationValue(int x, int y, int z) { if (normalizationVector) return normalizationVector[z*Ny*Nx + x*Ny + y]; else return 1; } void LoadValues(std::string localInputFilename, float yOffset, std::string normalizationFilename, bool simulatePVFC) { inputFilename = localInputFilename; try { + if (verbose) std::cout << "Loading input image..." << std::endl; m_inputImage = mitk::IOUtil::Load(inputFilename); + if (verbose) std::cout << "Loading input image... [Done]" << std::endl; } catch (...) { if (verbose) std::cout << "No .nrrd file found ... switching to legacy mode." << std::endl; } try { if (simulatePVFC && !normalizationFilename.empty()) m_normalizationImage = mitk::IOUtil::Load(normalizationFilename); } catch (...) { if (verbose) std::cout << "No normalization .nrrd file found ... will not normalize PVFC" << std::endl; } if (m_normalizationImage.IsNotNull()) { mitk::ImageReadAccessor readAccess3(m_normalizationImage, m_normalizationImage->GetVolumeData(0)); normalizationVector = (double *)readAccess3.GetData(); } if (m_inputImage.IsNotNull()) // load stuff from nrrd file { simulationTimeFromFile = 0; Nx = m_inputImage->GetDimensions()[1]; Ny = m_inputImage->GetDimensions()[0]; Nz = m_inputImage->GetDimensions()[2]; xSpacing = m_inputImage->GetGeometry(0)->GetSpacing()[0]; ySpacing = m_inputImage->GetGeometry(0)->GetSpacing()[1]; zSpacing = m_inputImage->GetGeometry(0)->GetSpacing()[2]; mcflag = std::stoi(m_inputImage->GetProperty("mcflag")->GetValueAsString().c_str()); // mcflag, 0 = uniform, 1 = Gaussian, 2 = iso-pt, 4 = monospectral fraunhofer setup launchflag = std::stoi(m_inputImage->GetProperty("launchflag")->GetValueAsString().c_str());// 0 = let mcxyz calculate trajectory, 1 = manually set launch vector boundaryflag = std::stoi(m_inputImage->GetProperty("boundaryflag")->GetValueAsString().c_str());// 0 = no boundaries, 1 = escape at boundaries, 2 = escape at surface only xs = std::stod(m_inputImage->GetProperty("launchPointX")->GetValueAsString().c_str()); ys = std::stod(m_inputImage->GetProperty("launchPointY")->GetValueAsString().c_str()) + yOffset; zs = std::stod(m_inputImage->GetProperty("launchPointZ")->GetValueAsString().c_str()); xfocus = std::stod(m_inputImage->GetProperty("focusPointX")->GetValueAsString().c_str()); yfocus = std::stod(m_inputImage->GetProperty("focusPointY")->GetValueAsString().c_str()); zfocus = std::stod(m_inputImage->GetProperty("focusPointZ")->GetValueAsString().c_str()); ux0 = std::stod(m_inputImage->GetProperty("trajectoryVectorX")->GetValueAsString().c_str()); uy0 = std::stod(m_inputImage->GetProperty("trajectoryVectorY")->GetValueAsString().c_str()); uz0 = std::stod(m_inputImage->GetProperty("trajectoryVectorZ")->GetValueAsString().c_str()); radius = std::stod(m_inputImage->GetProperty("radius")->GetValueAsString().c_str()); waist = std::stod(m_inputImage->GetProperty("waist")->GetValueAsString().c_str()); totalNumberOfVoxels = Nx*Ny*Nz; if (verbose) std::cout << totalNumberOfVoxels << " = sizeof totalNumberOfVoxels" << std::endl; muaVector = (double *)malloc(totalNumberOfVoxels * sizeof(double)); /* tissue structure */ musVector = (double *)malloc(totalNumberOfVoxels * sizeof(double)); /* tissue structure */ gVector = (double *)malloc(totalNumberOfVoxels * sizeof(double)); /* tissue structure */ mitk::ImageReadAccessor readAccess0(m_inputImage, m_inputImage->GetVolumeData(0)); muaVector = (double *)readAccess0.GetData(); mitk::ImageReadAccessor readAccess1(m_inputImage, m_inputImage->GetVolumeData(1)); musVector = (double *)readAccess1.GetData(); mitk::ImageReadAccessor readAccess2(m_inputImage, m_inputImage->GetVolumeData(2)); gVector = (double *)readAccess2.GetData(); } else { mitkThrow() << "No longer support loading of binary tissue files."; } } }; class ReturnValues { private: long i1 = 0, i2 = 31; // used Random Generator long ma[56]; // used Random Generator /* ma[0] is not used. */ long mj, mk; short i, ii; public: long long Nphotons; double* totalFluence; std::string myname; DetectorVoxel* detectorVoxel; ReturnValues() { detectorVoxel = nullptr; Nphotons = 0; totalFluence = nullptr; } /* SUBROUTINES */ /************************************************************************** * RandomGen * A random number generator that generates uniformly * distributed random numbers between 0 and 1 inclusive. * The algorithm is based on: * W.H. Press, S.A. Teukolsky, W.T. Vetterling, and B.P. * Flannery, "Numerical Recipes in C," Cambridge University * Press, 2nd edition, (1992). * and * D.E. Knuth, "Seminumerical Algorithms," 2nd edition, vol. 2 * of "The Art of Computer Programming", Addison-Wesley, (1981). * * When Type is 0, sets Seed as the seed. Make sure 0 b) m = a; else m = b; return m; } /*********************************************************** * min2 ****/ double min2(double a, double b) { double m; if (a >= b) m = b; else m = a; return m; } /*********************************************************** * min3 ****/ double min3(double a, double b, double c) { double m; if (a <= min2(b, c)) m = a; else if (b <= min2(a, c)) m = b; else m = c; return m; } /******************** * my version of FindVoxelFace for no scattering. * s = ls + FindVoxelFace2(x,y,z, tempx, tempy, tempz, dx, dy, dz, ux, uy, uz); ****/ double FindVoxelFace2(double x1, double y1, double z1, double /*x2*/, double /*y2*/, double /*z2*/, double dx, double dy, double dz, double ux, double uy, double uz) { int ix1 = floor(x1 / dx); int iy1 = floor(y1 / dy); int iz1 = floor(z1 / dz); int ix2, iy2, iz2; if (ux >= 0) ix2 = ix1 + 1; else ix2 = ix1; if (uy >= 0) iy2 = iy1 + 1; else iy2 = iy1; if (uz >= 0) iz2 = iz1 + 1; else iz2 = iz1; double xs = fabs((ix2*dx - x1) / ux); double ys = fabs((iy2*dy - y1) / uy); double zs = fabs((iz2*dz - z1) / uz); double s = min3(xs, ys, zs); return s; } /*********************************************************** * FRESNEL REFLECTANCE * Computes reflectance as photon passes from medium 1 to * medium 2 with refractive indices n1,n2. Incident * angle a1 is specified by cosine value ca1 = cos(a1). * Program returns value of transmitted angle a1 as * value in *ca2_Ptr = cos(a2). ****/ double RFresnel(double n1, /* incident refractive index.*/ double n2, /* transmit refractive index.*/ double ca1, /* cosine of the incident */ /* angle a1, 00. */ { double r; if (n1 == n2) { /** matched boundary. **/ *ca2_Ptr = ca1; r = 0.0; } else if (ca1 > (1.0 - 1.0e-12)) { /** normal incidence. **/ *ca2_Ptr = ca1; r = (n2 - n1) / (n2 + n1); r *= r; } else if (ca1 < 1.0e-6) { /** very slanted. **/ *ca2_Ptr = 0.0; r = 1.0; } else { /** general. **/ double sa1, sa2; /* sine of incident and transmission angles. */ double ca2; /* cosine of transmission angle. */ sa1 = sqrt(1 - ca1*ca1); sa2 = n1*sa1 / n2; if (sa2 >= 1.0) { /* double check for total internal reflection. */ *ca2_Ptr = 0.0; r = 1.0; } else { double cap, cam; /* cosines of sum ap or diff am of the two */ /* angles: ap = a1 + a2, am = a1 - a2. */ double sap, sam; /* sines. */ *ca2_Ptr = ca2 = sqrt(1 - sa2*sa2); cap = ca1*ca2 - sa1*sa2; /* c+ = cc - ss. */ cam = ca1*ca2 + sa1*sa2; /* c- = cc + ss. */ sap = sa1*ca2 + ca1*sa2; /* s+ = sc + cs. */ sam = sa1*ca2 - ca1*sa2; /* s- = sc - cs. */ r = 0.5*sam*sam*(cam*cam + cap*cap) / (sap*sap*cam*cam); /* rearranged for speed. */ } } return(r); } /******** END SUBROUTINE **********/ /*********************************************************** * the boundary is the face of some voxel * find the the photon's hitting position on the nearest face of the voxel and update the step size. ****/ double FindVoxelFace(double x1, double y1, double z1, double x2, double y2, double z2, double dx, double dy, double dz, double ux, double uy, double uz) { double x_1 = x1 / dx; double y_1 = y1 / dy; double z_1 = z1 / dz; double x_2 = x2 / dx; double y_2 = y2 / dy; double z_2 = z2 / dz; double fx_1 = floor(x_1); double fy_1 = floor(y_1); double fz_1 = floor(z_1); double fx_2 = floor(x_2); double fy_2 = floor(y_2); double fz_2 = floor(z_2); double x = 0, y = 0, z = 0, x0 = 0, y0 = 0, z0 = 0, s = 0; if ((fx_1 != fx_2) && (fy_1 != fy_2) && (fz_1 != fz_2)) { //#10 fx_2 = fx_1 + SIGN(fx_2 - fx_1);//added fy_2 = fy_1 + SIGN(fy_2 - fy_1);//added fz_2 = fz_1 + SIGN(fz_2 - fz_1);//added x = (max2(fx_1, fx_2) - x_1) / ux; y = (max2(fy_1, fy_2) - y_1) / uy; z = (max2(fz_1, fz_2) - z_1) / uz; if (x == min3(x, y, z)) { x0 = max2(fx_1, fx_2); y0 = (x0 - x_1) / ux*uy + y_1; z0 = (x0 - x_1) / ux*uz + z_1; } else if (y == min3(x, y, z)) { y0 = max2(fy_1, fy_2); x0 = (y0 - y_1) / uy*ux + x_1; z0 = (y0 - y_1) / uy*uz + z_1; } else { z0 = max2(fz_1, fz_2); y0 = (z0 - z_1) / uz*uy + y_1; x0 = (z0 - z_1) / uz*ux + x_1; } } else if ((fx_1 != fx_2) && (fy_1 != fy_2)) { //#2 fx_2 = fx_1 + SIGN(fx_2 - fx_1);//added fy_2 = fy_1 + SIGN(fy_2 - fy_1);//added x = (max2(fx_1, fx_2) - x_1) / ux; y = (max2(fy_1, fy_2) - y_1) / uy; if (x == min2(x, y)) { x0 = max2(fx_1, fx_2); y0 = (x0 - x_1) / ux*uy + y_1; z0 = (x0 - x_1) / ux*uz + z_1; } else { y0 = max2(fy_1, fy_2); x0 = (y0 - y_1) / uy*ux + x_1; z0 = (y0 - y_1) / uy*uz + z_1; } } else if ((fy_1 != fy_2) && (fz_1 != fz_2)) { //#3 fy_2 = fy_1 + SIGN(fy_2 - fy_1);//added fz_2 = fz_1 + SIGN(fz_2 - fz_1);//added y = (max2(fy_1, fy_2) - y_1) / uy; z = (max2(fz_1, fz_2) - z_1) / uz; if (y == min2(y, z)) { y0 = max2(fy_1, fy_2); x0 = (y0 - y_1) / uy*ux + x_1; z0 = (y0 - y_1) / uy*uz + z_1; } else { z0 = max2(fz_1, fz_2); x0 = (z0 - z_1) / uz*ux + x_1; y0 = (z0 - z_1) / uz*uy + y_1; } } else if ((fx_1 != fx_2) && (fz_1 != fz_2)) { //#4 fx_2 = fx_1 + SIGN(fx_2 - fx_1);//added fz_2 = fz_1 + SIGN(fz_2 - fz_1);//added x = (max2(fx_1, fx_2) - x_1) / ux; z = (max2(fz_1, fz_2) - z_1) / uz; if (x == min2(x, z)) { x0 = max2(fx_1, fx_2); y0 = (x0 - x_1) / ux*uy + y_1; z0 = (x0 - x_1) / ux*uz + z_1; } else { z0 = max2(fz_1, fz_2); x0 = (z0 - z_1) / uz*ux + x_1; y0 = (z0 - z_1) / uz*uy + y_1; } } else if (fx_1 != fx_2) { //#5 fx_2 = fx_1 + SIGN(fx_2 - fx_1);//added x0 = max2(fx_1, fx_2); y0 = (x0 - x_1) / ux*uy + y_1; z0 = (x0 - x_1) / ux*uz + z_1; } else if (fy_1 != fy_2) { //#6 fy_2 = fy_1 + SIGN(fy_2 - fy_1);//added y0 = max2(fy_1, fy_2); x0 = (y0 - y_1) / uy*ux + x_1; z0 = (y0 - y_1) / uy*uz + z_1; } else { //#7 z0 = max2(fz_1, fz_2); fz_2 = fz_1 + SIGN(fz_2 - fz_1);//added x0 = (z0 - z_1) / uz*ux + x_1; y0 = (z0 - z_1) / uz*uy + y_1; } //s = ( (x0-fx_1)*dx + (y0-fy_1)*dy + (z0-fz_1)*dz )/3; //s = sqrt( SQR((x0-x_1)*dx) + SQR((y0-y_1)*dy) + SQR((z0-z_1)*dz) ); //s = sqrt(SQR(x0-x_1)*SQR(dx) + SQR(y0-y_1)*SQR(dy) + SQR(z0-z_1)*SQR(dz)); s = sqrt(SQR((x0 - x_1)*dx) + SQR((y0 - y_1)*dy) + SQR((z0 - z_1)*dz)); return (s); } }; /* DECLARE FUNCTIONS */ void runMonteCarlo(InputValues* inputValues, ReturnValues* returnValue, int thread, mitk::pa::MonteCarloThreadHandler::Pointer threadHandler); int detector_x = -1; int detector_z = -1; bool interpretAsTime = true; bool simulatePVFC = false; int requestedNumberOfPhotons = 100000; float requestedSimulationTime = 0; // in minutes int concurentThreadsSupported = -1; float yOffset = 0; // in mm bool saveLegacy = false; std::string normalizationFilename; std::string inputFilename; std::string outputFilename; mitk::pa::Probe::Pointer m_PhotoacousticProbe; int main(int argc, char * argv[]) { mitkCommandLineParser parser; // set general information parser.setCategory("MITK-Photoacoustics"); parser.setTitle("Mitk MCxyz"); parser.setDescription("Runs Monte Carlo simulations on inputed tissues."); parser.setContributor("CAI, DKFZ based on code by Jacques and Li"); // how should arguments be prefixed parser.setArgumentPrefix("--", "-"); // add each argument, unless specified otherwise each argument is optional // see mitkCommandLineParser::addArgument for more information parser.beginGroup("Required I/O parameters"); parser.addArgument( "input", "i", mitkCommandLineParser::InputFile, "Input tissue file", "input tissue file (*.nrrd)", us::Any(), false); parser.addArgument( "output", "o", mitkCommandLineParser::OutputFile, "Output fluence file", "where to save the simulated fluence (*.nrrd)", us::Any(), false); parser.endGroup(); parser.beginGroup("Optional parameters"); parser.addArgument( "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose, or rather debug output"); parser.addArgument( "detector-x", "dx", mitkCommandLineParser::Int, "Detector voxel x position", "Determines the x position of the detector voxel (default: -1 = dont use detector voxel)", -1); parser.addArgument( "detector-z", "dz", mitkCommandLineParser::Int, "Detector voxel z position", "Determines the z position of the detector voxel (default: -1 = dont use detector voxel)", -1); parser.addArgument( "number-of-photons", "n", mitkCommandLineParser::Int, "Number of photons", "Specifies the number of photons (default: 100000). Simulation stops after that number. Use -t --timer to define a timer instead"); parser.addArgument( "timer", "t", mitkCommandLineParser::Float, "Simulation time in min", "Specifies the amount of time for simutation (default: 0). Simulation stops after that number of minutes. -n --number-of-photons is the override and default behavior and defines the maximum number of photons instead. If no simulation time or number of photons is specified the file time is taken."); parser.addArgument( "y-offset", "yo", mitkCommandLineParser::Float, "Probe Y-Offset in mm", "Specifies an offset of the photoacoustic probe in the y direction depending on the initial probe position (default: 0) in mm."); parser.addArgument( "jobs", "j", mitkCommandLineParser::Int, "Number of jobs", "Specifies the number of jobs for simutation (default: -1 which starts as many jobs as supported)."); parser.addArgument( "probe-xml", "p", mitkCommandLineParser::InputFile, "Xml definition of the probe", "Specifies the absolute path of the location of the xml definition file of the probe design."); parser.addArgument("normalization-file", "nf", mitkCommandLineParser::InputFile, "Input normalization file", "The input normalization file is used for normalization of the number of photons in the PVFC calculations."); parser.endGroup(); // parse arguments, this method returns a mapping of long argument names and their values std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size() == 0) return EXIT_FAILURE; // parse, cast and set required arguments inputFilename = us::any_cast(parsedArgs["input"]); // strip ending inputFilename = inputFilename.substr(0, inputFilename.find("_H.mci")); inputFilename = inputFilename.substr(0, inputFilename.find("_T.bin")); outputFilename = us::any_cast(parsedArgs["output"]); // add .nrrd if not there std::string suffix = ".nrrd"; if (outputFilename.compare(outputFilename.size() - suffix.size(), suffix.size(), suffix) != 0) outputFilename = outputFilename + suffix; // default values for optional arguments // parse, cast and set optional arguments if given if (parsedArgs.count("verbose")) { verbose = us::any_cast(parsedArgs["verbose"]); } if (parsedArgs.count("detector-x")) { detector_x = us::any_cast(parsedArgs["detector-x"]); } if (parsedArgs.count("detector-z")) { detector_z = us::any_cast(parsedArgs["detector-z"]); } if (parsedArgs.count("timer")) { requestedSimulationTime = us::any_cast(parsedArgs["timer"]); if (requestedSimulationTime > 0) interpretAsTime = true; } if (parsedArgs.count("y-offset")) { yOffset = us::any_cast(parsedArgs["y-offset"]); } if (parsedArgs.count("number-of-photons")) { requestedNumberOfPhotons = us::any_cast(parsedArgs["number-of-photons"]); if (requestedNumberOfPhotons > 0) interpretAsTime = false; } if (parsedArgs.count("jobs")) { concurentThreadsSupported = us::any_cast(parsedArgs["jobs"]); } if (parsedArgs.count("probe-xml")) { std::string inputXmlProbeDesign = us::any_cast(parsedArgs["probe-xml"]); m_PhotoacousticProbe = mitk::pa::Probe::New(inputXmlProbeDesign, verbose); if (!m_PhotoacousticProbe->IsValid()) { std::cerr << "Xml File was not valid. Simulation failed." << std::endl; return EXIT_FAILURE; } } if (parsedArgs.count("normalization-file")) { normalizationFilename = us::any_cast(parsedArgs["normalization-file"]); } if (concurentThreadsSupported == 0 || concurentThreadsSupported == -1) { concurentThreadsSupported = std::thread::hardware_concurrency(); if (concurentThreadsSupported == 0) { std::cout << "Could not determine number of available threads. Launching only one." << std::endl; concurentThreadsSupported = 1; } } if (detector_x != -1 && detector_z != -1) { if (verbose) std::cout << "Performing PVFC calculation for x=" << detector_x << " and z=" << detector_z << std::endl; simulatePVFC = true; } else { if (verbose) std::cout << "Will not perform PVFC calculation due to x=" << detector_x << " and/or z=" << detector_z << std::endl; } InputValues allInput = InputValues(); allInput.LoadValues(inputFilename, yOffset, normalizationFilename, simulatePVFC); std::vector allValues(concurentThreadsSupported); auto* threads = new std::thread[concurentThreadsSupported]; for (long i = 0; i < concurentThreadsSupported; i++) { auto* tmp = new ReturnValues(); allValues.push_back(*tmp); } if (verbose) std::cout << "Initializing MonteCarloThreadHandler" << std::endl; long timeMetric; if (interpretAsTime) { if (requestedSimulationTime < mitk::eps) requestedSimulationTime = allInput.simulationTimeFromFile; timeMetric = requestedSimulationTime * 60 * 1000; } else { timeMetric = requestedNumberOfPhotons; } mitk::pa::MonteCarloThreadHandler::Pointer threadHandler = mitk::pa::MonteCarloThreadHandler::New(timeMetric, interpretAsTime); if (simulatePVFC) threadHandler->SetPackageSize(1000); if (verbose) std::cout << "\nStarting simulation ...\n" << std::endl; auto simulationStartTime = std::chrono::system_clock::now(); for (int i = 0; i < concurentThreadsSupported; i++) { threads[i] = std::thread(runMonteCarlo, &allInput, &allValues[i], (i + 1), threadHandler); } for (int i = 0; i < concurentThreadsSupported; i++) { threads[i].join(); } auto simulationFinishTime = std::chrono::system_clock::now(); auto simulationTimeElapsed = simulationFinishTime - simulationStartTime; if (verbose) std::cout << "\n\nFinished simulation\n\n" << std::endl; std::cout << "total time for simulation: " << (int)std::chrono::duration_cast(simulationTimeElapsed).count() << "sec " << std::endl; /**** SAVE Convert data to relative fluence rate [cm^-2] and save. *****/ if (!simulatePVFC) { if (verbose) std::cout << "Allocating memory for normal simulation result ... "; auto* finalTotalFluence = (double *)malloc(allInput.totalNumberOfVoxels * sizeof(double)); if (verbose) std::cout << "[OK]" << std::endl; if (verbose) std::cout << "Cleaning memory for normal simulation result ..."; for (int i = 0; i < allInput.totalNumberOfVoxels; i++) { finalTotalFluence[i] = 0; } if (verbose) std::cout << "[OK]" << std::endl; if (verbose) std::cout << "Calculating resulting fluence ... "; double tdx = 0, tdy = 0, tdz = 0; long long tNphotons = 0; for (int t = 0; t < concurentThreadsSupported; t++) { tdx = allInput.xSpacing; tdy = allInput.ySpacing; tdz = allInput.zSpacing; tNphotons += allValues[t].Nphotons; for (int voxelNumber = 0; voxelNumber < allInput.totalNumberOfVoxels; voxelNumber++) { finalTotalFluence[voxelNumber] += allValues[t].totalFluence[voxelNumber]; } } if (verbose) std::cout << "[OK]" << std::endl; std::cout << "total number of photons simulated: " << tNphotons << std::endl; // Normalize deposition (A) to yield fluence rate (F). double temp = tdx*tdy*tdz*tNphotons; for (int i = 0; i < allInput.totalNumberOfVoxels; i++) { finalTotalFluence[i] /= temp*allInput.muaVector[i]; } if (verbose) std::cout << "Saving normal simulated fluence result to " << outputFilename << " ... "; mitk::Image::Pointer resultImage = mitk::Image::New(); mitk::PixelType TPixel = mitk::MakeScalarPixelType(); auto* dimensionsOfImage = new unsigned int[3]; // Copy dimensions dimensionsOfImage[0] = allInput.Ny; dimensionsOfImage[1] = allInput.Nx; dimensionsOfImage[2] = allInput.Nz; resultImage->Initialize(TPixel, 3, dimensionsOfImage); mitk::Vector3D spacing; spacing[0] = allInput.ySpacing; spacing[1] = allInput.xSpacing; spacing[2] = allInput.zSpacing; resultImage->SetSpacing(spacing); resultImage->SetImportVolume(finalTotalFluence, 0, 0, mitk::Image::CopyMemory); resultImage->GetPropertyList()->SetFloatProperty("y-offset", yOffset); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("y-offset")); mitk::IOUtil::Save(resultImage, outputFilename); if (verbose) std::cout << "[OK]" << std::endl; if (verbose) { std::cout << "x spacing = " << tdx << std::endl; std::cout << "y spacing = " << tdy << std::endl; std::cout << "z spacing = " << tdz << std::endl; std::cout << "total number of voxels = " << allInput.totalNumberOfVoxels << std::endl; std::cout << "number of photons = " << (int)tNphotons << std::endl; } } else // if simulate PVFC { if (verbose) std::cout << "Allocating memory for PVFC simulation result ... "; double* detectorFluence = ((double*)malloc(allInput.totalNumberOfVoxels * sizeof(double))); if (verbose) std::cout << "[OK]" << std::endl; if (verbose) std::cout << "Cleaning memory for PVFC simulation result ..."; for (int i = 0; i < allInput.totalNumberOfVoxels; i++) { detectorFluence[i] = 0; } if (verbose) std::cout << "[OK]" << std::endl; if (verbose) std::cout << "Calculating resulting PVFC fluence ... "; double tdx = 0, tdy = 0, tdz = 0; long long tNphotons = 0; long pvfcPhotons = 0; for (int t = 0; t < concurentThreadsSupported; t++) { tdx = allInput.xSpacing; tdy = allInput.ySpacing; tdz = allInput.zSpacing; tNphotons += allValues[t].Nphotons; pvfcPhotons += allValues[t].detectorVoxel->m_NumberPhotonsCurrent; for (int voxelNumber = 0; voxelNumber < allInput.totalNumberOfVoxels; voxelNumber++) { detectorFluence[voxelNumber] += allValues[t].detectorVoxel->fluenceContribution[voxelNumber]; } } if (verbose) std::cout << "[OK]" << std::endl; std::cout << "total number of photons simulated: " << tNphotons << std::endl; // Normalize deposition (A) to yield fluence rate (F). double temp = tdx*tdy*tdz*tNphotons; for (int i = 0; i < allInput.totalNumberOfVoxels; i++) { detectorFluence[i] /= temp*allInput.muaVector[i]; } if (verbose) std::cout << "Saving PVFC ..."; std::stringstream detectorname(""); double detectorX = allValues[0].detectorVoxel->location.x; double detectorY = allValues[0].detectorVoxel->location.y; double detectorZ = allValues[0].detectorVoxel->location.z; detectorname << detectorX << "," << detectorY << "," << detectorZ << "FluenceContribution.nrrd"; // Save the binary file std::string outputFileBase = outputFilename.substr(0, outputFilename.find(".nrrd")); outputFilename = outputFileBase + "_p" + detectorname.str().c_str(); mitk::Image::Pointer pvfcImage = mitk::Image::New(); auto* dimensionsOfPvfcImage = new unsigned int[3]; // Copy dimensions dimensionsOfPvfcImage[0] = allInput.Ny; dimensionsOfPvfcImage[1] = allInput.Nx; dimensionsOfPvfcImage[2] = allInput.Nz; pvfcImage->Initialize(mitk::MakeScalarPixelType(), 3, dimensionsOfPvfcImage); mitk::Vector3D pvfcSpacing; pvfcSpacing[0] = allInput.ySpacing; pvfcSpacing[1] = allInput.xSpacing; pvfcSpacing[2] = allInput.zSpacing; pvfcImage->SetSpacing(pvfcSpacing); pvfcImage->SetImportVolume(detectorFluence, 0, 0, mitk::Image::CopyMemory); pvfcImage->GetPropertyList()->SetFloatProperty("detector-x", detectorX); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("detector-x")); pvfcImage->GetPropertyList()->SetFloatProperty("detector-y", detectorY); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("detector-y")); pvfcImage->GetPropertyList()->SetFloatProperty("detector-z", detectorZ); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("detector-z")); pvfcImage->GetPropertyList()->SetFloatProperty("normalization-factor", allValues[0].detectorVoxel->m_PhotonNormalizationValue); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("normalization-factor")); pvfcImage->GetPropertyList()->SetFloatProperty("simulated-photons", pvfcPhotons); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("simulated-photons")); mitk::IOUtil::Save(pvfcImage, outputFilename); if (verbose) std::cout << "[OK]" << std::endl; if (verbose) { std::cout << "x spacing = " << tdx << std::endl; std::cout << "y spacing = " << tdy << std::endl; std::cout << "z spacing = " << tdz << std::endl; std::cout << "total number of voxels = " << allInput.totalNumberOfVoxels << std::endl; std::cout << "number of photons = " << (int)tNphotons << std::endl; } } exit(EXIT_SUCCESS); } /* end of main */ /* CORE FUNCTION */ void runMonteCarlo(InputValues* inputValues, ReturnValues* returnValue, int thread, mitk::pa::MonteCarloThreadHandler::Pointer threadHandler) { if (verbose) std::cout << "Thread " << thread << ": Locking Mutex ..." << std::endl; if (verbose) std::cout << "[OK]" << std::endl; if (verbose) std::cout << "Initializing ... "; /* Propagation parameters */ double x, y, z; /* photon position */ double ux, uy, uz; /* photon trajectory as cosines */ double uxx, uyy, uzz; /* temporary values used during SPIN */ double s; /* step sizes. s = -log(RND)/mus [cm] */ double sleft; /* dimensionless */ double costheta; /* cos(theta) */ double sintheta; /* sin(theta) */ double cospsi; /* cos(psi) */ double sinpsi; /* sin(psi) */ double psi; /* azimuthal angle */ long photonIterator = 0; /* current photon */ double W; /* photon weight */ double absorb; /* weighted deposited in a step due to absorption */ short photon_status; /* flag = ALIVE=1 or DEAD=0 */ bool sv; /* Are they in the same voxel? */ /* dummy variables */ double rnd; /* assigned random value 0-1 */ double r, phi; /* dummy values */ long i, j; /* dummy indices */ double tempx, tempy, tempz; /* temporary variables, used during photon step. */ int ix, iy, iz; /* Added. Used to track photons */ double temp; /* dummy variable */ int bflag; /* boundary flag: 0 = photon inside volume. 1 = outside volume */ int CNT = 0; returnValue->totalFluence = (double *)malloc(inputValues->totalNumberOfVoxels * sizeof(double)); /* relative fluence rate [W/cm^2/W.delivered] */ if (detector_x != -1 && detector_z != -1) { if (detector_x<0 || detector_x>inputValues->Nx) { std::cout << "Requested detector x position not valid. Needs to be >= 0 and <= " << inputValues->Nx << std::endl; exit(EXIT_FAILURE); } if (detector_z<1 || detector_z>inputValues->Nz) { std::cout << "Requested detector z position not valid. Needs to be > 0 and <= " << inputValues->Nz << std::endl; exit(EXIT_FAILURE); } double photonNormalizationValue = 1 / inputValues->GetNormalizationValue(detector_x, inputValues->Ny / 2, detector_z); returnValue->detectorVoxel = new DetectorVoxel(initLocation(detector_x, inputValues->Ny / 2, detector_z, 0), inputValues->totalNumberOfVoxels, photonNormalizationValue); } /**** ======================== MAJOR CYCLE ============================ *****/ auto duration = std::chrono::system_clock::now().time_since_epoch(); returnValue->RandomGen(0, (std::chrono::duration_cast(duration).count() + thread) % 32000, nullptr); /* initiate with seed = 1, or any long integer. */ for (j = 0; j < inputValues->totalNumberOfVoxels; j++) returnValue->totalFluence[j] = 0; // ensure F[] starts empty. /**** RUN Launch N photons, initializing each one before progation. *****/ long photonsToSimulate = 0; do { photonsToSimulate = threadHandler->GetNextWorkPackage(); if (returnValue->detectorVoxel != nullptr) { photonsToSimulate = photonsToSimulate * returnValue->detectorVoxel->m_PhotonNormalizationValue; } if (verbose) MITK_INFO << "Photons to simulate: " << photonsToSimulate; photonIterator = 0L; do { /**** LAUNCH Initialize photon position and trajectory. *****/ photonIterator += 1; /* increment photon count */ W = 1.0; /* set photon weight to one */ photon_status = ALIVE; /* Launch an ALIVE photon */ CNT = 0; /**** SET SOURCE* Launch collimated beam at x,y center.****/ /****************************/ /* Initial position. */ if (m_PhotoacousticProbe.IsNotNull()) { double rnd1 = -1; double rnd2 = -1; double rnd3 = -1; double rnd4 = -1; double rnd5 = -1; double rnd6 = -1; double rnd7 = -1; double rnd8 = -1; while ((rnd1 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd2 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd3 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd4 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd5 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd6 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd7 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); while ((rnd8 = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); mitk::pa::LightSource::PhotonInformation info = m_PhotoacousticProbe->GetNextPhoton(rnd1, rnd2, rnd3, rnd4, rnd5, rnd6, rnd7, rnd8); x = info.xPosition; y = yOffset + info.yPosition; z = info.zPosition; ux = info.xAngle; uy = info.yAngle; uz = info.zAngle; if (verbose) std::cout << "Created photon at position (" << x << "|" << y << "|" << z << ") with angles (" << ux << "|" << uy << "|" << uz << ")." << std::endl; } else { /* trajectory */ if (inputValues->launchflag == 1) // manually set launch { x = inputValues->xs; y = inputValues->ys; z = inputValues->zs; ux = inputValues->ux0; uy = inputValues->uy0; uz = inputValues->uz0; } else // use mcflag { if (inputValues->mcflag == 0) // uniform beam { // set launch point and width of beam while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // avoids rnd = 0 r = inputValues->radius*sqrt(rnd); // radius of beam at launch point while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // avoids rnd = 0 phi = rnd*2.0*PI; x = inputValues->xs + r*cos(phi); y = inputValues->ys + r*sin(phi); z = inputValues->zs; // set trajectory toward focus while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // avoids rnd = 0 r = inputValues->waist*sqrt(rnd); // radius of beam at focus while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // avoids rnd = 0 phi = rnd*2.0*PI; // !!!!!!!!!!!!!!!!!!!!!!! setting input values will braek inputValues->xfocus = r*cos(phi); inputValues->yfocus = r*sin(phi); temp = sqrt((x - inputValues->xfocus)*(x - inputValues->xfocus) + (y - inputValues->yfocus)*(y - inputValues->yfocus) + inputValues->zfocus*inputValues->zfocus); ux = -(x - inputValues->xfocus) / temp; uy = -(y - inputValues->yfocus) / temp; uz = sqrt(1 - ux*ux + uy*uy); } else if (inputValues->mcflag == 5) // Multispectral DKFZ prototype { // set launch point and width of beam while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); //offset in x direction in cm (random) x = (rnd*2.5) - 1.25; while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); double b = ((rnd)-0.5); y = (b > 0 ? yOffset + 1.5 : yOffset - 1.5); z = 0.1; ux = 0; while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); //Angle of beam in y direction uy = sin((rnd*0.42) - 0.21 + (b < 0 ? 1.0 : -1.0) * 0.436); while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // angle of beam in x direction ux = sin((rnd*0.42) - 0.21); uz = sqrt(1 - ux*ux - uy*uy); } else if (inputValues->mcflag == 4) // Monospectral prototype DKFZ { // set launch point and width of beam while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); //offset in x direction in cm (random) x = (rnd*2.5) - 1.25; while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); double b = ((rnd)-0.5); y = (b > 0 ? yOffset + 0.83 : yOffset - 0.83); z = 0.1; ux = 0; while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); //Angle of beam in y direction uy = sin((rnd*0.42) - 0.21 + (b < 0 ? 1.0 : -1.0) * 0.375); while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); // angle of beam in x direction ux = sin((rnd*0.42) - 0.21); uz = sqrt(1 - ux*ux - uy*uy); } else { // isotropic pt source costheta = 1.0 - 2.0 * returnValue->RandomGen(1, 0, nullptr); sintheta = sqrt(1.0 - costheta*costheta); psi = 2.0 * PI * returnValue->RandomGen(1, 0, nullptr); cospsi = cos(psi); if (psi < PI) sinpsi = sqrt(1.0 - cospsi*cospsi); else sinpsi = -sqrt(1.0 - cospsi*cospsi); x = inputValues->xs; y = inputValues->ys; z = inputValues->zs; ux = sintheta*cospsi; uy = sintheta*sinpsi; uz = costheta; } } // end use mcflag } /****************************/ /* Get tissue voxel properties of launchpoint. * If photon beyond outer edge of defined voxels, * the tissue equals properties of outermost voxels. * Therefore, set outermost voxels to infinite background value. */ ix = (int)(inputValues->Nx / 2 + x / inputValues->xSpacing); iy = (int)(inputValues->Ny / 2 + y / inputValues->ySpacing); iz = (int)(z / inputValues->zSpacing); if (ix >= inputValues->Nx) ix = inputValues->Nx - 1; if (iy >= inputValues->Ny) iy = inputValues->Ny - 1; if (iz >= inputValues->Nz) iz = inputValues->Nz - 1; if (ix < 0) ix = 0; if (iy < 0) iy = 0; if (iz < 0) iz = 0; /* Get the tissue type of located voxel */ i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy); bflag = 1; // initialize as 1 = inside volume, but later check as photon propagates. if (returnValue->detectorVoxel != nullptr) returnValue->detectorVoxel->recordedPhotonRoute->clear(); /* HOP_DROP_SPIN_CHECK Propagate one photon until it dies as determined by ROULETTE. *******/ do { /**** HOP Take step to new position s = dimensionless stepsize x, uy, uz are cosines of current photon trajectory *****/ while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); /* yields 0 < rnd <= 1 */ sleft = -log(rnd); /* dimensionless step */ CNT += 1; do { // while sleft>0 s = sleft / inputValues->musVector[i]; /* Step size [cm].*/ tempx = x + s*ux; /* Update positions. [cm] */ tempy = y + s*uy; tempz = z + s*uz; sv = returnValue->SameVoxel(x, y, z, tempx, tempy, tempz, inputValues->xSpacing, inputValues->ySpacing, inputValues->zSpacing); if (sv) /* photon in same voxel */ { x = tempx; /* Update positions. */ y = tempy; z = tempz; /**** DROP Drop photon weight (W) into local bin. *****/ absorb = W*(1 - exp(-inputValues->muaVector[i] * s)); /* photon weight absorbed at this step */ W -= absorb; /* decrement WEIGHT by amount absorbed */ // If photon within volume of heterogeneity, deposit energy in F[]. // Normalize F[] later, when save output. if (bflag) { i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy); returnValue->totalFluence[i] += absorb; // only save data if blag==1, i.e., photon inside simulation cube //For each detectorvoxel if (returnValue->detectorVoxel != nullptr) { //Add photon position to the recorded photon route returnValue->detectorVoxel->recordedPhotonRoute->push_back(initLocation(ix, iy, iz, absorb)); //If the photon is currently at the detector position if ((returnValue->detectorVoxel->location.x == ix) && ((returnValue->detectorVoxel->location.y == iy) || (returnValue->detectorVoxel->location.y - 1 == iy)) && (returnValue->detectorVoxel->location.z == iz)) { //For each voxel in the recorded photon route for (unsigned int routeIndex = 0; routeIndex < returnValue->detectorVoxel->recordedPhotonRoute->size(); routeIndex++) { //increment the fluence contribution at that particular position i = (long)(returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).z*inputValues->Ny*inputValues->Nx + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).x*inputValues->Ny + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).y); returnValue->detectorVoxel->fluenceContribution[i] += returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).absorb; } //Clear the recorded photon route returnValue->detectorVoxel->m_NumberPhotonsCurrent++; returnValue->detectorVoxel->recordedPhotonRoute->clear(); } } } /* Update sleft */ sleft = 0; /* dimensionless step remaining */ } else /* photon has crossed voxel boundary */ { /* step to voxel face + "littlest step" so just inside new voxel. */ s = ls + returnValue->FindVoxelFace2(x, y, z, tempx, tempy, tempz, inputValues->xSpacing, inputValues->ySpacing, inputValues->zSpacing, ux, uy, uz); /**** DROP Drop photon weight (W) into local bin. *****/ absorb = W*(1 - exp(-inputValues->muaVector[i] * s)); /* photon weight absorbed at this step */ W -= absorb; /* decrement WEIGHT by amount absorbed */ // If photon within volume of heterogeneity, deposit energy in F[]. // Normalize F[] later, when save output. if (bflag) { // only save data if bflag==1, i.e., photon inside simulation cube //For each detectorvoxel if (returnValue->detectorVoxel != nullptr) { //Add photon position to the recorded photon route returnValue->detectorVoxel->recordedPhotonRoute->push_back(initLocation(ix, iy, iz, absorb)); //If the photon is currently at the detector position if ((returnValue->detectorVoxel->location.x == ix) && ((returnValue->detectorVoxel->location.y == iy) || (returnValue->detectorVoxel->location.y - 1 == iy)) && (returnValue->detectorVoxel->location.z == iz)) { //For each voxel in the recorded photon route for (unsigned int routeIndex = 0; routeIndex < returnValue->detectorVoxel->recordedPhotonRoute->size(); routeIndex++) { //increment the fluence contribution at that particular position i = (long)(returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).z*inputValues->Ny*inputValues->Nx + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).x*inputValues->Ny + returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).y); returnValue->detectorVoxel->fluenceContribution[i] += returnValue->detectorVoxel->recordedPhotonRoute->at(routeIndex).absorb; } //Clear the recorded photon route returnValue->detectorVoxel->m_NumberPhotonsCurrent++; returnValue->detectorVoxel->recordedPhotonRoute->clear(); } } i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy); returnValue->totalFluence[i] += absorb; } /* Update sleft */ sleft -= s*inputValues->musVector[i]; /* dimensionless step remaining */ if (sleft <= ls) sleft = 0; /* Update positions. */ x += s*ux; y += s*uy; z += s*uz; // pointers to voxel containing optical properties ix = (int)(inputValues->Nx / 2 + x / inputValues->xSpacing); iy = (int)(inputValues->Ny / 2 + y / inputValues->ySpacing); iz = (int)(z / inputValues->zSpacing); bflag = 1; // Boundary flag. Initialize as 1 = inside volume, then check. if (inputValues->boundaryflag == 0) { // Infinite medium. // Check if photon has wandered outside volume. // If so, set tissue type to boundary value, but let photon wander. // Set blag to zero, so DROP does not deposit energy. if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; bflag = 0; } if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; bflag = 0; } if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; bflag = 0; } if (iz < 0) { iz = 0; bflag = 0; } if (ix < 0) { ix = 0; bflag = 0; } if (iy < 0) { iy = 0; bflag = 0; } } else if (inputValues->boundaryflag == 1) { // Escape at boundaries if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; photon_status = DEAD; sleft = 0; } if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; photon_status = DEAD; sleft = 0; } if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; photon_status = DEAD; sleft = 0; } if (iz < 0) { iz = 0; photon_status = DEAD; sleft = 0; } if (ix < 0) { ix = 0; photon_status = DEAD; sleft = 0; } if (iy < 0) { iy = 0; photon_status = DEAD; sleft = 0; } } else if (inputValues->boundaryflag == 2) { // Escape at top surface, no x,y bottom z boundaries if (iz >= inputValues->Nz) { iz = inputValues->Nz - 1; bflag = 0; } if (ix >= inputValues->Nx) { ix = inputValues->Nx - 1; bflag = 0; } if (iy >= inputValues->Ny) { iy = inputValues->Ny - 1; bflag = 0; } if (iz < 0) { iz = 0; photon_status = DEAD; sleft = 0; } if (ix < 0) { ix = 0; bflag = 0; } if (iy < 0) { iy = 0; bflag = 0; } } // update pointer to tissue type i = (long)(iz*inputValues->Ny*inputValues->Nx + ix*inputValues->Ny + iy); } //(sv) /* same voxel */ } while (sleft > 0); //do...while /**** SPIN Scatter photon into new trajectory defined by theta and psi. Theta is specified by cos(theta), which is determined based on the Henyey-Greenstein scattering function. Convert theta and psi into cosines ux, uy, uz. *****/ /* Sample for costheta */ while ((rnd = returnValue->RandomGen(1, 0, nullptr)) <= 0.0); if (inputValues->gVector[i] == 0.0) { costheta = 2.0 * rnd - 1.0; } else { double temp = (1.0 - inputValues->gVector[i] * inputValues->gVector[i]) / (1.0 - inputValues->gVector[i] + 2 * inputValues->gVector[i] * rnd); costheta = (1.0 + inputValues->gVector[i] * inputValues->gVector[i] - temp*temp) / (2.0*inputValues->gVector[i]); } sintheta = sqrt(1.0 - costheta*costheta); /* sqrt() is faster than sin(). */ /* Sample psi. */ psi = 2.0*PI*returnValue->RandomGen(1, 0, nullptr); cospsi = cos(psi); if (psi < PI) sinpsi = sqrt(1.0 - cospsi*cospsi); /* sqrt() is faster than sin(). */ else sinpsi = -sqrt(1.0 - cospsi*cospsi); /* New trajectory. */ if (1 - fabs(uz) <= ONE_MINUS_COSZERO) { /* close to perpendicular. */ uxx = sintheta * cospsi; uyy = sintheta * sinpsi; uzz = costheta * SIGN(uz); /* SIGN() is faster than division. */ } else { /* usually use this option */ temp = sqrt(1.0 - uz * uz); uxx = sintheta * (ux * uz * cospsi - uy * sinpsi) / temp + ux * costheta; uyy = sintheta * (uy * uz * cospsi + ux * sinpsi) / temp + uy * costheta; uzz = -sintheta * cospsi * temp + uz * costheta; } /* Update trajectory */ ux = uxx; uy = uyy; uz = uzz; /**** CHECK ROULETTE If photon weight below THRESHOLD, then terminate photon using Roulette technique. Photon has CHANCE probability of having its weight increased by factor of 1/CHANCE, and 1-CHANCE probability of terminating. *****/ if (W < THRESHOLD) { if (returnValue->RandomGen(1, 0, nullptr) <= CHANCE) W /= CHANCE; else photon_status = DEAD; } } while (photon_status == ALIVE); /* end STEP_CHECK_HOP_SPIN */ /* if ALIVE, continue propagating */ /* If photon DEAD, then launch new photon. */ } while (photonIterator < photonsToSimulate); /* end RUN */ returnValue->Nphotons += photonsToSimulate; } while (photonsToSimulate > 0); if (verbose) std::cout << "------------------------------------------------------" << std::endl; if (verbose) std::cout << "Thread " << thread << " is finished." << std::endl; } diff --git a/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/CMakeLists.txt b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/CMakeLists.txt new file mode 100644 index 0000000000..8c8dcb7fba --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/CMakeLists.txt @@ -0,0 +1,11 @@ +OPTION(BUILD_PhotoacousticPhantomGenerator "Build MiniApp for generating a PA phantom in silico" ON) + +IF(BUILD_PhotoacousticPhantomGenerator) + PROJECT( MitkPAPhantomGenerator ) + mitk_create_executable(PAPhantomGenerator + DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsLib + PACKAGE_DEPENDS + CPP_FILES PAPhantomGenerator.cpp) + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + ENDIF() diff --git a/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/PAPhantomGenerator.cpp b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/PAPhantomGenerator.cpp new file mode 100644 index 0000000000..cb83119f46 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/PAPhantomGenerator.cpp @@ -0,0 +1,230 @@ +/*=================================================================== + +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 + +using namespace mitk::pa; + +TissueGeneratorParameters::Pointer CreatePhantom_04_04_18_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(12); + returnParameters->SetMinBackgroundAbsorption(0.1); + returnParameters->SetMaxBackgroundAbsorption(0.1); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateNewPositionInStraightLine); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(8); + returnParameters->SetMinVesselAbsorption(1); + returnParameters->SetMaxVesselAbsorption(10); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0.1); + returnParameters->SetMaxVesselBending(0.3); + returnParameters->SetMinVesselRadiusInMillimeters(0.25); + returnParameters->SetMaxVesselRadiusInMillimeters(4); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(1.6); + returnParameters->SetMaxVesselZOrigin(4); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.03); + returnParameters->SetXDim(140); + returnParameters->SetYDim(100); + returnParameters->SetZDim(180); + //returnParameters->SetVoxelSpacingInCentimeters(0.015); + //returnParameters->SetXDim(280); + //returnParameters->SetYDim(200); + //returnParameters->SetZDim(360); + returnParameters->SetForceVesselsMoveAlongYDirection(true); + //returnParameters->SetVoxelSpacingInCentimeters(0.0075); + //returnParameters->SetXDim(560); + //returnParameters->SetYDim(400); + //returnParameters->SetZDim(720); + return returnParameters; +} + +struct InputParameters +{ + std::string saveFolderPath; + std::string identifyer; + std::string exePath; + std::string probePath; + bool empty; + bool verbose; +}; + +InputParameters parseInput(int argc, char* argv[]) +{ + MITK_INFO << "Parsing arguments..."; + mitkCommandLineParser parser; + + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Tissue Batch Generator"); + parser.setDescription("Creates in silico tissue in batch processing and automatically calculates fluence values for the central slice of the volume."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + parser.setArgumentPrefix("--", "-"); + + parser.beginGroup("Required parameters"); + parser.addArgument( + "savePath", "s", mitkCommandLineParser::InputDirectory, + "Input save folder (directory)", "input save folder", + us::Any(), false); + parser.addArgument( + "mitkMcxyz", "m", mitkCommandLineParser::OutputFile, + "MitkMcxyz binary (file)", "path to the MitkMcxyz binary", + us::Any(), false); + parser.endGroup(); + + parser.beginGroup("Optional parameters"); + parser.addArgument( + "probe", "p", mitkCommandLineParser::OutputFile, + "xml probe file (file)", "file to the definition of the used probe (*.xml)", + us::Any()); + parser.addArgument( + "verbose", "v", mitkCommandLineParser::Bool, + "Verbose Output", "Whether to produce verbose, or rather debug output"); + parser.addArgument( + "identifyer", "i", mitkCommandLineParser::String, + "Generator identifyer (string)", "A unique identifyer for the calculation instance"); + parser.addArgument( + "empty-volume", "e", mitkCommandLineParser::Bool, + "omit vessel structures (boolean flag)", "Whether to create an empty volume with no structures inside."); + parser.endGroup(); + + InputParameters input; + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size() == 0) + exit(-1); + + if (parsedArgs.count("empty-volume")) + { + input.empty = us::any_cast(parsedArgs["empty-volume"]); + } + else + { + input.empty = false; + } + + if (parsedArgs.count("verbose")) + { + input.verbose = us::any_cast(parsedArgs["verbose"]); + } + else + { + input.verbose = false; + } + + if (parsedArgs.count("savePath")) + { + input.saveFolderPath = us::any_cast(parsedArgs["savePath"]); + } + + if (parsedArgs.count("mitkMcxyz")) + { + input.exePath = us::any_cast(parsedArgs["mitkMcxyz"]); + } + + if (parsedArgs.count("probe")) + { + input.probePath = us::any_cast(parsedArgs["probe"]); + } + + if (parsedArgs.count("identifyer")) + { + input.identifyer = us::any_cast(parsedArgs["identifyer"]); + } + else + { + auto uid = mitk::UIDGenerator("", 8); + input.identifyer = uid.GetUID(); + } + MITK_INFO << "Parsing arguments...[Done]"; + return input; +} + +int main(int argc, char * argv[]) +{ + auto input = parseInput(argc, argv); + auto parameters = CreatePhantom_04_04_18_Parameters(); + if (input.empty) + { + parameters->SetMaxNumberOfVessels(0); + parameters->SetMinNumberOfVessels(0); + } + MITK_INFO(input.verbose) << "Generating tissue.."; + auto resultTissue = InSilicoTissueGenerator::GenerateInSilicoData(parameters); + MITK_INFO(input.verbose) << "Generating tissue..[Done]"; + + auto inputfolder = std::string(input.saveFolderPath + "input/"); + auto outputfolder = std::string(input.saveFolderPath + "output/"); + if (!itksys::SystemTools::FileIsDirectory(inputfolder)) + { + itksys::SystemTools::MakeDirectory(inputfolder); + } + if (!itksys::SystemTools::FileIsDirectory(outputfolder)) + { + itksys::SystemTools::MakeDirectory(outputfolder); + } + + std::string savePath = input.saveFolderPath + "input/Phantom_" + input.identifyer + + ".nrrd"; + mitk::IOUtil::Save(resultTissue->ConvertToMitkImage(), savePath); + std::string outputPath = input.saveFolderPath + "output/Phantom_" + input.identifyer + + "/"; + + resultTissue = nullptr; + + if (!itksys::SystemTools::FileIsDirectory(outputPath)) + { + itksys::SystemTools::MakeDirectory(outputPath); + } + + outputPath = outputPath + "Fluence_Phantom_" + input.identifyer; + + MITK_INFO(input.verbose) << "Simulating fluence.."; + + int result = -4; + + std::string cmdString = std::string(input.exePath + " -i " + savePath + " -o " + + (outputPath + ".nrrd") + + " -yo " + "0" + " -p " + input.probePath + + " -n 10000000"); + + MITK_INFO << "Executing: " << cmdString; + + result = std::system(cmdString.c_str()); + + MITK_INFO << result; + MITK_INFO(input.verbose) << "Simulating fluence..[Done]"; +} diff --git a/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/files.cmake b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/files.cmake new file mode 100644 index 0000000000..07f708562d --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkPAPhantomGenerator/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + PAPhantomGenerator.cpp +) diff --git a/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/CMakeLists.txt b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/CMakeLists.txt new file mode 100644 index 0000000000..73a948b462 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/CMakeLists.txt @@ -0,0 +1,11 @@ +OPTION(BUILD_PhotoacousticTissueBatchGenerator "Build MiniApp for batch generating of photoacoustic tissue" ON) + +IF(BUILD_PhotoacousticTissueBatchGenerator) + PROJECT( MitkTissueBatchGenerator ) + mitk_create_executable(TissueBatchGenerator + DEPENDS MitkCommandLine MitkCore MitkPhotoacousticsLib + PACKAGE_DEPENDS + CPP_FILES TissueBatchGenerator.cpp) + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + ENDIF() diff --git a/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/TissueBatchGenerator.cpp b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/TissueBatchGenerator.cpp new file mode 100644 index 0000000000..61d6b94ab9 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/TissueBatchGenerator.cpp @@ -0,0 +1,394 @@ +/*=================================================================== + +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 + +using namespace mitk::pa; + +TissueGeneratorParameters::Pointer CreateMultiHB_13_02_18_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(1.8); + returnParameters->SetMinBackgroundAbsorption(0.001); + returnParameters->SetMaxBackgroundAbsorption(0.2); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(7); + returnParameters->SetMinVesselAbsorption(1); + returnParameters->SetMaxVesselAbsorption(12); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0); + returnParameters->SetMaxVesselBending(0.2); + returnParameters->SetMinVesselRadiusInMillimeters(0.5); + returnParameters->SetMaxVesselRadiusInMillimeters(6); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(1); + returnParameters->SetMaxVesselZOrigin(3); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.06); + returnParameters->SetXDim(70); + returnParameters->SetYDim(100); + returnParameters->SetZDim(100); + returnParameters->SetMCflag(4); + return returnParameters; +} + +TissueGeneratorParameters::Pointer CreateBaselineHB_13_02_18_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(1.8); + returnParameters->SetMinBackgroundAbsorption(0.001); + returnParameters->SetMaxBackgroundAbsorption(0.2); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(1); + returnParameters->SetMinVesselAbsorption(4.73); + returnParameters->SetMaxVesselAbsorption(4.73); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0); + returnParameters->SetMaxVesselBending(0.2); + returnParameters->SetMinVesselRadiusInMillimeters(3); + returnParameters->SetMaxVesselRadiusInMillimeters(3); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(1); + returnParameters->SetMaxVesselZOrigin(3); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.06); + returnParameters->SetXDim(70); + returnParameters->SetYDim(100); + returnParameters->SetZDim(100); + returnParameters->SetMCflag(4); + return returnParameters; +} + +TissueGeneratorParameters::Pointer CreateSingleVesselHeterogeneousBackground_08_02_18_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(1.8); + returnParameters->SetMinBackgroundAbsorption(0.001); + returnParameters->SetMaxBackgroundAbsorption(0.2); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(1); + returnParameters->SetMinVesselAbsorption(1); + returnParameters->SetMaxVesselAbsorption(12); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0); + returnParameters->SetMaxVesselBending(0.2); + returnParameters->SetMinVesselRadiusInMillimeters(0.5); + returnParameters->SetMaxVesselRadiusInMillimeters(6); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(1); + returnParameters->SetMaxVesselZOrigin(3); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.06); + returnParameters->SetXDim(70); + returnParameters->SetYDim(100); + returnParameters->SetZDim(100); + returnParameters->SetMCflag(4); + return returnParameters; +} + +TissueGeneratorParameters::Pointer CreateMultivessel_19_12_17_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(12); + returnParameters->SetMinBackgroundAbsorption(0.1); + returnParameters->SetMaxBackgroundAbsorption(0.1); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(7); + returnParameters->SetMinVesselAbsorption(2); + returnParameters->SetMaxVesselAbsorption(8); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0.1); + returnParameters->SetMaxVesselBending(0.3); + returnParameters->SetMinVesselRadiusInMillimeters(0.5); + returnParameters->SetMaxVesselRadiusInMillimeters(4); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(2.2); + returnParameters->SetMaxVesselZOrigin(4); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.06); + returnParameters->SetXDim(70); + returnParameters->SetYDim(100); + returnParameters->SetZDim(100); + return returnParameters; +} + +TissueGeneratorParameters::Pointer CreateMultivessel_19_10_17_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(12); + returnParameters->SetMinBackgroundAbsorption(0.1); + returnParameters->SetMaxBackgroundAbsorption(0.1); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(7); + returnParameters->SetMinVesselAbsorption(2); + returnParameters->SetMaxVesselAbsorption(8); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0.1); + returnParameters->SetMaxVesselBending(0.3); + returnParameters->SetMinVesselRadiusInMillimeters(0.5); + returnParameters->SetMaxVesselRadiusInMillimeters(4); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(2.2); + returnParameters->SetMaxVesselZOrigin(4); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.03); + returnParameters->SetXDim(140); + returnParameters->SetYDim(200); + returnParameters->SetZDim(180); + return returnParameters; +} + +TissueGeneratorParameters::Pointer CreateSinglevessel_19_10_17_Parameters() +{ + auto returnParameters = TissueGeneratorParameters::New(); + returnParameters->SetAirThicknessInMillimeters(12); + returnParameters->SetMinBackgroundAbsorption(0.1); + returnParameters->SetMaxBackgroundAbsorption(0.1); + returnParameters->SetBackgroundAnisotropy(0.9); + returnParameters->SetBackgroundScattering(15); + returnParameters->SetCalculateNewVesselPositionCallback(&VesselMeanderStrategy::CalculateRandomlyDivergingPosition); + returnParameters->SetDoPartialVolume(true); + returnParameters->SetMinNumberOfVessels(1); + returnParameters->SetMaxNumberOfVessels(1); + returnParameters->SetMinVesselAbsorption(2); + returnParameters->SetMaxVesselAbsorption(8); + returnParameters->SetMinVesselAnisotropy(0.9); + returnParameters->SetMaxVesselAnisotropy(0.9); + returnParameters->SetMinVesselBending(0.1); + returnParameters->SetMaxVesselBending(0.3); + returnParameters->SetMinVesselRadiusInMillimeters(0.5); + returnParameters->SetMaxVesselRadiusInMillimeters(4); + returnParameters->SetMinVesselScattering(15); + returnParameters->SetMaxVesselScattering(15); + returnParameters->SetMinVesselZOrigin(2.2); + returnParameters->SetMaxVesselZOrigin(4); + returnParameters->SetVesselBifurcationFrequency(5000); + returnParameters->SetRandomizePhysicalProperties(false); + returnParameters->SetSkinThicknessInMillimeters(0); + returnParameters->SetUseRngSeed(false); + returnParameters->SetVoxelSpacingInCentimeters(0.03); + returnParameters->SetXDim(140); + returnParameters->SetYDim(200); + returnParameters->SetZDim(180); + return returnParameters; +} + +struct InputParameters +{ + std::string saveFolderPath; + std::string identifyer; + std::string exePath; + std::string probePath; + bool verbose; +}; + +InputParameters parseInput(int argc, char* argv[]) +{ + MITK_INFO << "Paring arguments..."; + mitkCommandLineParser parser; + // set general information + parser.setCategory("MITK-Photoacoustics"); + parser.setTitle("Mitk Tissue Batch Generator"); + parser.setDescription("Creates in silico tissue in batch processing and automatically calculates fluence values for the central slice of the volume."); + parser.setContributor("Computer Assisted Medical Interventions, DKFZ"); + + // how should arguments be prefixed + parser.setArgumentPrefix("--", "-"); + // add each argument, unless specified otherwise each argument is optional + // see mitkCommandLineParser::addArgument for more information + parser.beginGroup("Required parameters"); + parser.addArgument( + "savePath", "s", mitkCommandLineParser::InputDirectory, + "Input save folder (directory)", "input save folder", + us::Any(), false); + parser.addArgument( + "mitkMcxyz", "m", mitkCommandLineParser::OutputFile, + "MitkMcxyz binary (file)", "path to the MitkMcxyz binary", + us::Any(), false); + parser.endGroup(); + parser.beginGroup("Optional parameters"); + parser.addArgument( + "probe", "p", mitkCommandLineParser::OutputFile, + "xml probe file (file)", "file to the definition of the used probe (*.xml)", + us::Any()); + parser.addArgument( + "verbose", "v", mitkCommandLineParser::Bool, + "Verbose Output", "Whether to produce verbose, or rather debug output"); + parser.addArgument( + "identifyer", "i", mitkCommandLineParser::String, + "Generator identifyer (string)", "A unique identifyer for the calculation instance"); + + InputParameters input; + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size() == 0) + exit(-1); + + if (parsedArgs.count("verbose")) + { + MITK_INFO << "verbose"; + input.verbose = us::any_cast(parsedArgs["verbose"]); + } + else + { + input.verbose = false; + } + + if (parsedArgs.count("savePath")) + { + MITK_INFO << "savePath"; + input.saveFolderPath = us::any_cast(parsedArgs["savePath"]); + } + + if (parsedArgs.count("mitkMcxyz")) + { + MITK_INFO << "mitkMcxyz"; + input.exePath = us::any_cast(parsedArgs["mitkMcxyz"]); + } + + if (parsedArgs.count("probe")) + { + MITK_INFO << "probe"; + input.probePath = us::any_cast(parsedArgs["probe"]); + } + + if (parsedArgs.count("identifyer")) + { + MITK_INFO << "identifyer"; + input.identifyer = us::any_cast(parsedArgs["identifyer"]); + } + else + { + MITK_INFO << "generating identifyer"; + auto uid = mitk::UIDGenerator("", 8); + input.identifyer = uid.GetUID(); + } + MITK_INFO << "Paring arguments...[Done]"; + return input; +} + +int main(int argc, char * argv[]) +{ + auto input = parseInput(argc, argv); + unsigned int iterationNumber = 0; + + while (true) + { + auto parameters = CreateBaselineHB_13_02_18_Parameters(); + MITK_INFO(input.verbose) << "Generating tissue.."; + auto resultTissue = InSilicoTissueGenerator::GenerateInSilicoData(parameters); + MITK_INFO(input.verbose) << "Generating tissue..[Done]"; + + auto inputfolder = std::string(input.saveFolderPath + "input/"); + auto outputfolder = std::string(input.saveFolderPath + "output/"); + if (!itksys::SystemTools::FileIsDirectory(inputfolder)) + { + itksys::SystemTools::MakeDirectory(inputfolder); + } + if (!itksys::SystemTools::FileIsDirectory(outputfolder)) + { + itksys::SystemTools::MakeDirectory(outputfolder); + } + + std::string savePath = input.saveFolderPath + "input/BaselineHB_" + input.identifyer + + "_" + std::to_string(iterationNumber) + ".nrrd"; + mitk::IOUtil::Save(resultTissue->ConvertToMitkImage(), savePath); + std::string outputPath = input.saveFolderPath + "output/BaselineHB_" + input.identifyer + + "_" + std::to_string(iterationNumber) + "/"; + + if (!itksys::SystemTools::FileIsDirectory(outputPath)) + { + itksys::SystemTools::MakeDirectory(outputPath); + } + + outputPath = outputPath + "Fluence_BaselineHB_" + input.identifyer + "_" + std::to_string(iterationNumber); + + MITK_INFO(input.verbose) << "Simulating fluence.."; + for(double yo = -1.8; yo <= 1.81; yo=yo+0.12) + { + std::string yo_string = std::to_string(round(yo*100)/100.0); + int result = -4; + if(!input.probePath.empty()) + result = std::system(std::string(input.exePath + " -i " + savePath + " -o " + + (outputPath + "_yo" + yo_string + ".nrrd") + + " -yo " + yo_string + " -p " + input.probePath + + " -n 100000000").c_str()); + else + result = std::system(std::string(input.exePath + " -i " + savePath + " -o " + + (outputPath + "_yo" + yo_string + ".nrrd") + + " -yo " + yo_string + " -n 100000000").c_str()); + MITK_INFO << "yo: " << yo_string << ": " << result; + } + + MITK_INFO(input.verbose) << "Simulating fluence..[Done]"; + + iterationNumber++; + } +} diff --git a/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/files.cmake b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/files.cmake new file mode 100644 index 0000000000..d4e42c83d5 --- /dev/null +++ b/Modules/PhotoacousticsLib/MitkTissueBatchGenerator/files.cmake @@ -0,0 +1,3 @@ +set(CPP_FILES + TissueBatchGenerator.cpp +) diff --git a/Modules/PhotoacousticsLib/files.cmake b/Modules/PhotoacousticsLib/files.cmake index 8b14417421..3f62323168 100644 --- a/Modules/PhotoacousticsLib/files.cmake +++ b/Modules/PhotoacousticsLib/files.cmake @@ -1,52 +1,56 @@ SET(H_FILES include/mitkPAPropertyCalculator.h include/mitkPAVector.h include/mitkPATissueGeneratorParameters.h include/mitkPAInSilicoTissueVolume.h + include/mitkPAPhantomTissueGenerator.h include/mitkPATissueGenerator.h include/mitkPAVesselTree.h include/mitkPAVessel.h + include/mitkPAVesselDrawer.h include/mitkPAVesselMeanderStrategy.h include/mitkPANoiseGenerator.h include/mitkPAVolume.h include/mitkPAComposedVolume.h include/mitkPASlicedVolumeGenerator.h include/mitkPAProbe.h include/mitkPALightSource.h include/mitkPAIOUtil.h include/mitkPAMonteCarloThreadHandler.h include/mitkPASimulationBatchGenerator.h include/mitkPAFluenceYOffsetPair.h include/mitkPAVolumeManipulator.h include/mitkPAVesselProperties.h include/mitkPASimulationBatchGeneratorParameters.h include/mitkPAExceptions.h ) set(CPP_FILES Domain/Vessel/mitkPAVesselTree.cpp Domain/Vessel/mitkPAVessel.cpp Domain/Vessel/mitkPAVesselMeanderStrategy.cpp Domain/Vessel/mitkPAVesselProperties.cpp Domain/Volume/mitkPAInSilicoTissueVolume.cpp Domain/Volume/mitkPAVolume.cpp Domain/Volume/mitkPAComposedVolume.cpp Domain/Volume/mitkPAFluenceYOffsetPair.cpp Generator/mitkPATissueGenerator.cpp + Generator/mitkPAPhantomTissueGenerator.cpp Generator/mitkPANoiseGenerator.cpp Generator/mitkPASlicedVolumeGenerator.cpp Generator/mitkPASimulationBatchGenerator.cpp Generator/mitkPASimulationBatchGeneratorParameters.cpp IO/mitkPAIOUtil.cpp Utils/mitkPAPropertyCalculator.cpp Utils/mitkPAVector.cpp Utils/mitkPATissueGeneratorParameters.cpp Utils/mitkPAVolumeManipulator.cpp Utils/ProbeDesign/mitkPAProbe.cpp Utils/ProbeDesign/mitkPALightSource.cpp Utils/Thread/mitkPAMonteCarloThreadHandler.cpp + Utils/mitkPAVesselDrawer.cpp ) set(RESOURCE_FILES spectralLIB.dat ) diff --git a/Modules/PhotoacousticsLib/include/mitkPAInSilicoTissueVolume.h b/Modules/PhotoacousticsLib/include/mitkPAInSilicoTissueVolume.h index db6ed6a7a2..732bb1040e 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAInSilicoTissueVolume.h +++ b/Modules/PhotoacousticsLib/include/mitkPAInSilicoTissueVolume.h @@ -1,140 +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. ===================================================================*/ #ifndef MITKPHOTOACOUSTICVOLUME_H #define MITKPHOTOACOUSTICVOLUME_H #include #include #include #include #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT InSilicoTissueVolume : public itk::LightObject { public: mitkClassMacroItkParent(InSilicoTissueVolume, itk::LightObject) - mitkNewMacro1Param(Self, TissueGeneratorParameters::Pointer) + mitkNewMacro2Param(Self, TissueGeneratorParameters::Pointer, std::mt19937*) - enum SegmentationType + enum SegmentationType { AIR = -1, BACKGROUND = 0, VESSEL = 1, FAT = 2, SKIN = 3 }; /** * @brief ConvertToMitkImage * @return a pointer to an mitk image containing this volume. */ mitk::Image::Pointer ConvertToMitkImage(); /** * @brief SetVolumeValues sets the values for aborption, scattering and anisotropy at the specified voxel location. * * @param x * @param y * @param z * @param absorption * @param scattering * @param anisotropy * @param segmentType */ - void SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy, SegmentationType segmentType = SegmentationType::BACKGROUND); + void SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy, SegmentationType segmentType); + + /** + * @brief SetVolumeValues sets the values for aborption, scattering and anisotropy at the specified voxel location. + * + * @param x + * @param y + * @param z + * @param absorption + * @param scattering + * @param anisotropy + */ + void SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy); /** * @brief IsInsideVolume * * @param x * @param y * @param z * @return true if the voxel location is inside the volume */ bool IsInsideVolume(int x, int y, int z); /** * @brief AddDoubleProperty adds a persistent property to the volume, which will be exported to the mitk image. * * @param label * @param value */ void AddDoubleProperty(std::string label, double value); /** * @brief AddIntProperty adds a persistent property to the volume, which will be exported to the mitk image. * * @param label * @param value */ void AddIntProperty(std::string label, int value); Volume::Pointer GetAbsorptionVolume(); Volume::Pointer GetScatteringVolume(); Volume::Pointer GetAnisotropyVolume(); Volume::Pointer GetSegmentationVolume(); + void SetAbsorptionVolume(Volume::Pointer volume); + void SetScatteringVolume(Volume::Pointer volume); + void SetAnisotropyVolume(Volume::Pointer volume); + void SetSegmentationVolume(Volume::Pointer volume); + + double GetSpacing(); + void SetSpacing(double spacing); + void FinalizeVolume(); itkGetMacro(TissueParameters, TissueGeneratorParameters::Pointer); itkGetMacro(TDim, unsigned int); static InSilicoTissueVolume::Pointer New(mitk::pa::Volume::Pointer absorptionVolume, Volume::Pointer scatteringVolume, Volume::Pointer anisotropyVolume, Volume::Pointer segmentationVolume, TissueGeneratorParameters::Pointer tissueParameters, mitk::PropertyList::Pointer propertyList); protected: - InSilicoTissueVolume(TissueGeneratorParameters::Pointer parameters); + InSilicoTissueVolume(TissueGeneratorParameters::Pointer parameters, std::mt19937* rng); InSilicoTissueVolume(Volume::Pointer absorptionVolume, Volume::Pointer scatteringVolume, Volume::Pointer anisotropyVolume, Volume::Pointer segmentationVolume, TissueGeneratorParameters::Pointer tissueParameters, mitk::PropertyList::Pointer propertyList); ~InSilicoTissueVolume() override; mitk::pa::Volume::Pointer m_AbsorptionVolume; mitk::pa::Volume::Pointer m_ScatteringVolume; mitk::pa::Volume::Pointer m_AnisotropyVolume; mitk::pa::Volume::Pointer m_SegmentationVolume; TissueGeneratorParameters::Pointer m_TissueParameters; unsigned int m_TDim; + double m_InitialBackgroundAbsorption; + + std::mt19937* m_Rng; + void RandomizeTissueCoefficients(long rngSeed, bool useRngSeed, double percentage); mitk::PropertyList::Pointer m_PropertyList; private: void FillZLayer(int x, int y, double startIdx, double endIdx, double absorption, double scattering, double anisotropy, SegmentationType segmentationType); void AddSkinAndAirLayers(); void UpdatePropertyList(); }; } } #endif // MITKPHOTOACOUSTICVOLUME_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAPhantomTissueGenerator.h b/Modules/PhotoacousticsLib/include/mitkPAPhantomTissueGenerator.h new file mode 100644 index 0000000000..f60c62de7c --- /dev/null +++ b/Modules/PhotoacousticsLib/include/mitkPAPhantomTissueGenerator.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPhotoacousticPhantomTissueGenerator_h +#define mitkPhotoacousticPhantomTissueGenerator_h + +#include +#include +#include +#include + +#include +#include + +#include "mitkPAVesselTree.h" +#include "mitkPAInSilicoTissueVolume.h" + +#include "mitkCommon.h" + +namespace mitk { + namespace pa { + class MITKPHOTOACOUSTICSLIB_EXPORT PhantomTissueGenerator final + { + public: + + /** + * @brief GenerateInSilicoData This method will return a InSilicoTissueVolume created in terms of the given parameters. + * @param parameters + * @return + */ + static InSilicoTissueVolume::Pointer GeneratePhantomData(TissueGeneratorParameters::Pointer parameters); + + private: + PhantomTissueGenerator(); + virtual ~PhantomTissueGenerator(); + }; + } +} +#endif diff --git a/Modules/PhotoacousticsLib/include/mitkPATissueGeneratorParameters.h b/Modules/PhotoacousticsLib/include/mitkPATissueGeneratorParameters.h index 9d8e833f29..2ab5fcf444 100644 --- a/Modules/PhotoacousticsLib/include/mitkPATissueGeneratorParameters.h +++ b/Modules/PhotoacousticsLib/include/mitkPATissueGeneratorParameters.h @@ -1,214 +1,217 @@ /*=================================================================== 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 MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H #define MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H #include #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT TissueGeneratorParameters : public itk::Object { public: mitkClassMacroItkParent(TissueGeneratorParameters, itk::Object) itkFactorylessNewMacro(Self) /** * Callback function definition of a VesselMeanderStrategy */ typedef void (VesselMeanderStrategy::*CalculateNewVesselPositionCallback) (Vector::Pointer, Vector::Pointer, double, std::mt19937*); itkGetMacro(XDim, int) itkGetMacro(YDim, int) itkGetMacro(ZDim, int) itkGetMacro(VoxelSpacingInCentimeters, double) - itkGetMacro(VolumeSmoothingSigma, double) - itkGetMacro(DoVolumeSmoothing, bool) + itkGetMacro(DoPartialVolume, bool) itkGetMacro(UseRngSeed, bool) itkGetMacro(RngSeed, long) itkGetMacro(RandomizePhysicalProperties, bool) itkGetMacro(RandomizePhysicalPropertiesPercentage, double) + itkGetMacro(ForceVesselsMoveAlongYDirection, bool) - itkGetMacro(BackgroundAbsorption, double) + itkGetMacro(MinBackgroundAbsorption, double) + itkGetMacro(MaxBackgroundAbsorption, double) itkGetMacro(BackgroundScattering, double) itkGetMacro(BackgroundAnisotropy, double) itkGetMacro(AirAbsorption, double) itkGetMacro(AirScattering, double) itkGetMacro(AirAnisotropy, double) itkGetMacro(AirThicknessInMillimeters, double) itkGetMacro(SkinAbsorption, double) itkGetMacro(SkinScattering, double) itkGetMacro(SkinAnisotropy, double) itkGetMacro(SkinThicknessInMillimeters, double) itkGetMacro(CalculateNewVesselPositionCallback, CalculateNewVesselPositionCallback) itkGetMacro(MinNumberOfVessels, int) itkGetMacro(MaxNumberOfVessels, int) itkGetMacro(MinVesselBending, double) itkGetMacro(MaxVesselBending, double) itkGetMacro(MinVesselAbsorption, double) itkGetMacro(MaxVesselAbsorption, double) itkGetMacro(MinVesselRadiusInMillimeters, double) itkGetMacro(MaxVesselRadiusInMillimeters, double) itkGetMacro(VesselBifurcationFrequency, int) itkGetMacro(MinVesselScattering, double) itkGetMacro(MaxVesselScattering, double) itkGetMacro(MinVesselAnisotropy, double) itkGetMacro(MaxVesselAnisotropy, double) itkGetMacro(MinVesselZOrigin, double) itkGetMacro(MaxVesselZOrigin, double) itkGetMacro(MCflag, double) itkGetMacro(MCLaunchflag, double) itkGetMacro(MCBoundaryflag, double) itkGetMacro(MCLaunchPointX, double) itkGetMacro(MCLaunchPointY, double) itkGetMacro(MCLaunchPointZ, double) itkGetMacro(MCFocusPointX, double) itkGetMacro(MCFocusPointY, double) itkGetMacro(MCFocusPointZ, double) itkGetMacro(MCTrajectoryVectorX, double) itkGetMacro(MCTrajectoryVectorY, double) itkGetMacro(MCTrajectoryVectorZ, double) itkGetMacro(MCRadius, double) itkGetMacro(MCWaist, double) itkSetMacro(XDim, int) itkSetMacro(YDim, int) itkSetMacro(ZDim, int) itkSetMacro(VoxelSpacingInCentimeters, double) - itkSetMacro(VolumeSmoothingSigma, double) - itkSetMacro(DoVolumeSmoothing, bool) + itkSetMacro(DoPartialVolume, bool) itkSetMacro(UseRngSeed, bool) itkSetMacro(RngSeed, long) itkSetMacro(RandomizePhysicalProperties, bool) itkSetMacro(RandomizePhysicalPropertiesPercentage, double) + itkSetMacro(ForceVesselsMoveAlongYDirection, bool) - itkSetMacro(BackgroundAbsorption, double) + itkSetMacro(MinBackgroundAbsorption, double) + itkSetMacro(MaxBackgroundAbsorption, double) itkSetMacro(BackgroundScattering, double) itkSetMacro(BackgroundAnisotropy, double) itkSetMacro(AirAbsorption, double) itkSetMacro(AirScattering, double) itkSetMacro(AirAnisotropy, double) itkSetMacro(AirThicknessInMillimeters, double) itkSetMacro(SkinAbsorption, double) itkSetMacro(SkinScattering, double) itkSetMacro(SkinAnisotropy, double) itkSetMacro(SkinThicknessInMillimeters, double) itkSetMacro(CalculateNewVesselPositionCallback, CalculateNewVesselPositionCallback) itkSetMacro(MinNumberOfVessels, int) itkSetMacro(MaxNumberOfVessels, int) itkSetMacro(MinVesselBending, double) itkSetMacro(MaxVesselBending, double) itkSetMacro(MinVesselAbsorption, double) itkSetMacro(MaxVesselAbsorption, double) itkSetMacro(MinVesselRadiusInMillimeters, double) itkSetMacro(MaxVesselRadiusInMillimeters, double) itkSetMacro(VesselBifurcationFrequency, int) itkSetMacro(MinVesselScattering, double) itkSetMacro(MaxVesselScattering, double) itkSetMacro(MinVesselAnisotropy, double) itkSetMacro(MaxVesselAnisotropy, double) itkSetMacro(MinVesselZOrigin, double) itkSetMacro(MaxVesselZOrigin, double) itkSetMacro(MCflag, double) itkSetMacro(MCLaunchflag, double) itkSetMacro(MCBoundaryflag, double) itkSetMacro(MCLaunchPointX, double) itkSetMacro(MCLaunchPointY, double) itkSetMacro(MCLaunchPointZ, double) itkSetMacro(MCFocusPointX, double) itkSetMacro(MCFocusPointY, double) itkSetMacro(MCFocusPointZ, double) itkSetMacro(MCTrajectoryVectorX, double) itkSetMacro(MCTrajectoryVectorY, double) itkSetMacro(MCTrajectoryVectorZ, double) itkSetMacro(MCRadius, double) itkSetMacro(MCWaist, double) protected: TissueGeneratorParameters(); - ~TissueGeneratorParameters() override; + ~TissueGeneratorParameters(); private: int m_XDim; int m_YDim; int m_ZDim; double m_VoxelSpacingInCentimeters; - double m_VolumeSmoothingSigma; - bool m_DoVolumeSmoothing; + bool m_DoPartialVolume; bool m_UseRngSeed; long m_RngSeed; bool m_RandomizePhysicalProperties; double m_RandomizePhysicalPropertiesPercentage; + bool m_ForceVesselsMoveAlongYDirection; - double m_BackgroundAbsorption; + double m_MinBackgroundAbsorption; + double m_MaxBackgroundAbsorption; double m_BackgroundScattering; double m_BackgroundAnisotropy; double m_AirAbsorption; double m_AirScattering; double m_AirAnisotropy; double m_AirThicknessInMillimeters; double m_SkinAbsorption; double m_SkinScattering; double m_SkinAnisotropy; double m_SkinThicknessInMillimeters; CalculateNewVesselPositionCallback m_CalculateNewVesselPositionCallback; int m_MinNumberOfVessels; int m_MaxNumberOfVessels; double m_MinVesselBending; double m_MaxVesselBending; double m_MinVesselAbsorption; double m_MaxVesselAbsorption; double m_MinVesselRadiusInMillimeters; double m_MaxVesselRadiusInMillimeters; int m_VesselBifurcationFrequency; double m_MinVesselScattering; double m_MaxVesselScattering; double m_MinVesselAnisotropy; double m_MaxVesselAnisotropy; double m_MinVesselZOrigin; double m_MaxVesselZOrigin; double m_MCflag; double m_MCLaunchflag; double m_MCBoundaryflag; double m_MCLaunchPointX; double m_MCLaunchPointY; double m_MCLaunchPointZ; double m_MCFocusPointX; double m_MCFocusPointY; double m_MCFocusPointZ; double m_MCTrajectoryVectorX; double m_MCTrajectoryVectorY; double m_MCTrajectoryVectorZ; double m_MCRadius; double m_MCWaist; }; } } #endif // MITKPHOTOACOUSTICTISSUEGENERATORPARAMETERS_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVector.h b/Modules/PhotoacousticsLib/include/mitkPAVector.h index 8e20ce895a..b4901b7248 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAVector.h +++ b/Modules/PhotoacousticsLib/include/mitkPAVector.h @@ -1,132 +1,136 @@ /*=================================================================== 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 MITKSMARTVECTOR_H #define MITKSMARTVECTOR_H #include #include #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT Vector : public itk::LightObject { public: mitkClassMacroItkParent(Vector, itk::LightObject) itkFactorylessNewMacro(Self) /** * @brief GetNorm calculates the length of this vector. * @return the euclidean norm */ double GetNorm(); double GetElement(unsigned short index); void SetElement(unsigned short index, double value); /** * @brief Normalize normalizes this vector. After calling this GetNorm() will return 1. */ void Normalize(); void SetValue(Vector::Pointer value); /** * @brief RandomizeByPercentage alters this vector randomly by [-percentage, percentage] of the bendingFactor. * * @param percentage * @param bendingFactor */ void RandomizeByPercentage(double percentage, double bendingFactor, std::mt19937* rng); /** * @brief Randomize randomizes this vector to be [lowerLimit, upperLimit] in each element * * @param xLowerLimit * @param xUpperLimit * @param yLowerLimit * @param yUpperLimit * @param zLowerLimit * @param zUpperLimit */ void Randomize(double xLowerLimit, double xUpperLimit, double yLowerLimit, double yUpperLimit, double zLowerLimit, double zUpperLimit, std::mt19937* rng); /** * @brief Randomize randomizes this vector to be [0, limit] in each element * * @param xLimit * @param yLimit * @param zLimit */ void Randomize(double xLimit, double yLimit, double zLimit, std::mt19937* rng); /** * @brief Randomize randomizes this vector to be [-1, 1] in each element */ void Randomize(std::mt19937* rng); /** * @brief Rotate rotates this Vector around the x, y and z axis with the given angles in radians * * @param thetaChange rotation of the inclination angle in radians * @param phiChange rotation of the azimuthal angle in radians */ void Rotate(double xAngle, double yAngle); /** * @brief Scale scales this Vector with the given factor * * @param factor the scaling factor * * If a negative number is provided, the direction of the vector will be inverted. */ void Scale(double factor); /** * @brief Clone create a deep copy of this vector * * @return a new vector with the same values. */ Vector::Pointer Clone(); + void Subtract(Vector::Pointer other); + + void Add(Vector::Pointer other); + protected: Vector(); ~Vector() override; void PrintSelf(std::ostream& os, itk::Indent indent) const override; private: mitk::Vector3D m_Vector; }; /** * @brief Equal A function comparing two vectors for beeing equal * * @param rightHandSide A Vector to be compared * @param leftHandSide A Vector to be compared * @param eps tolarence for comparison. You can use mitk::eps in most cases. * @param verbose flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKPHOTOACOUSTICSLIB_EXPORT bool Equal(const Vector::Pointer leftHandSide, const Vector::Pointer rightHandSide, double eps, bool verbose); } } #endif // MITKSMARTVECTOR_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVessel.h b/Modules/PhotoacousticsLib/include/mitkPAVessel.h index f49289e5a6..f7e4b777a7 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAVessel.h +++ b/Modules/PhotoacousticsLib/include/mitkPAVessel.h @@ -1,116 +1,118 @@ /*=================================================================== 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 MITKVESSEL_H #define MITKVESSEL_H #include "mitkVector.h" #include "mitkPAVesselMeanderStrategy.h" #include "mitkPAInSilicoTissueVolume.h" #include "mitkPAVector.h" #include "mitkPAVesselProperties.h" +#include "mitkPAVesselDrawer.h" #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT Vessel : public itk::LightObject { public: mitkClassMacroItkParent(Vessel, itk::LightObject) mitkNewMacro1Param(Self, VesselProperties::Pointer) /** * Callback function definition of a VesselMeanderStrategy */ typedef void (VesselMeanderStrategy::*CalculateNewVesselPositionCallback) (Vector::Pointer, Vector::Pointer, double, std::mt19937*); /** * @brief ExpandVessel makes this Vessel expand one step in its current direction. * After expanding, the vessel will draw itself into the given InSilicoTissueVolume. * * @param volume volume for the vessel to draw itself in * @param calculateNewPosition a callback function of the VesselMeanderStrategy class. * It is used to calculate the final position after taking the step. * @param bendingFactor a metric of how much the Vessel should bend. If set to 0 the vessel will go in a straight line. */ void ExpandVessel(mitk::pa::InSilicoTissueVolume::Pointer volume, CalculateNewVesselPositionCallback calculateNewPosition, double bendingFactor, std::mt19937* rng); /** * @brief CanBifurcate * @return true if the Vessel is ready to Bifurcate() */ bool CanBifurcate(); /** * @brief Bifurcate bifurcates this vessel into two new ones. Makes sure that the volume of the vessels stays the same. * * @return a new vessel split up from the current one. */ Vessel::Pointer Bifurcate(std::mt19937* rng); /** * @brief IsFinished * @return true if the vessel cannot expand any further */ bool IsFinished(); itkGetConstMacro(VesselProperties, VesselProperties::Pointer); protected: Vessel(VesselProperties::Pointer parameters); ~Vessel() override; private: - const double MINIMUM_VESSEL_RADIUS = 1; + const double MINIMUM_VESSEL_RADIUS = 0.1; const double SCALING_FACTOR = 0.33; const double NEW_RADIUS_MINIMUM_RELATIVE_SIZE = 0.6; const double NEW_RADIUS_MAXIMUM_RELATIVE_SIZE = 0.8; - void DrawVesselInVolume(Vector::Pointer toPosition, mitk::pa::InSilicoTissueVolume::Pointer volume); - VesselProperties::Pointer m_VesselProperties; - VesselMeanderStrategy::Pointer m_VesselMeanderStrategy; bool m_Finished; double m_WalkedDistance; std::uniform_real_distribution<> m_RangeDistribution; std::uniform_real_distribution<> m_SignDistribution; std::uniform_real_distribution<> m_RadiusRangeDistribution; int GetSign(std::mt19937* rng); + + VesselProperties::Pointer m_VesselProperties; + + VesselDrawer::Pointer m_VesselDrawer; }; /** * @brief Equal A function comparing two vessels for beeing equal * * @param rightHandSide A vessel to be compared * @param leftHandSide A vessel to be compared * @param eps tolarence for comparison. You can use mitk::eps in most cases. * @param verbose flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKPHOTOACOUSTICSLIB_EXPORT bool Equal(const Vessel::Pointer leftHandSide, const Vessel::Pointer rightHandSide, double eps, bool verbose); } } #endif // MITKVESSEL_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVesselDrawer.h b/Modules/PhotoacousticsLib/include/mitkPAVesselDrawer.h new file mode 100644 index 0000000000..e201d468a5 --- /dev/null +++ b/Modules/PhotoacousticsLib/include/mitkPAVesselDrawer.h @@ -0,0 +1,53 @@ +/*=================================================================== + +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 MITKVESSELDRAWER_H +#define MITKVESSELDRAWER_H + +#include "mitkVector.h" +#include "mitkPAVesselMeanderStrategy.h" +#include "mitkPAInSilicoTissueVolume.h" +#include "mitkPAVector.h" +#include "mitkPAVesselProperties.h" + +#include + +//Includes for smart pointer usage +#include "mitkCommon.h" +#include "itkLightObject.h" + +namespace mitk { + namespace pa { + class MITKPHOTOACOUSTICSLIB_EXPORT VesselDrawer : public itk::LightObject + { + public: + mitkClassMacroItkParent(VesselDrawer, itk::LightObject); + itkFactorylessNewMacro(Self); + + void DrawVesselInVolume( + VesselProperties::Pointer properties, + InSilicoTissueVolume::Pointer volume); + + protected: + VesselDrawer(); + virtual ~VesselDrawer(); + + private: + }; + + } +} +#endif // MITKVESSELDRAWER_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVesselProperties.h b/Modules/PhotoacousticsLib/include/mitkPAVesselProperties.h index fa80d8386c..f19be3a4d2 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAVesselProperties.h +++ b/Modules/PhotoacousticsLib/include/mitkPAVesselProperties.h @@ -1,80 +1,83 @@ /*=================================================================== 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 MITKPhotoacousticVesselParameters_H #define MITKPhotoacousticVesselParameters_H #include #include //Includes for smart pointer usage #include "mitkCommon.h" #include "itkLightObject.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT VesselProperties : public itk::Object { public: - mitkClassMacroItkParent(VesselProperties, itk::Object) - itkFactorylessNewMacro(Self) - mitkNewMacro1Param(Self, Self::Pointer) + mitkClassMacroItkParent(VesselProperties, itk::Object); + itkFactorylessNewMacro(Self); + mitkNewMacro1Param(Self, Self::Pointer); - itkGetMacro(PositionVector, Vector::Pointer) - itkGetMacro(DirectionVector, Vector::Pointer) - itkGetMacro(RadiusInVoxel, double) - itkGetMacro(AbsorptionCoefficient, double) - itkGetMacro(ScatteringCoefficient, double) - itkGetMacro(AnisotopyCoefficient, double) - itkGetMacro(BifurcationFrequency, double) + itkGetMacro(PositionVector, Vector::Pointer); + itkGetMacro(DirectionVector, Vector::Pointer); + itkGetMacro(RadiusInVoxel, double); + itkGetMacro(AbsorptionCoefficient, double); + itkGetMacro(ScatteringCoefficient, double); + itkGetMacro(AnisotopyCoefficient, double); + itkGetMacro(BifurcationFrequency, double); + itkGetMacro(DoPartialVolume, bool); - itkSetMacro(PositionVector, Vector::Pointer) - itkSetMacro(DirectionVector, Vector::Pointer) - itkSetMacro(RadiusInVoxel, double) - itkSetMacro(AbsorptionCoefficient, double) - itkSetMacro(ScatteringCoefficient, double) - itkSetMacro(AnisotopyCoefficient, double) - itkSetMacro(BifurcationFrequency, double) + itkSetMacro(PositionVector, Vector::Pointer); + itkSetMacro(DirectionVector, Vector::Pointer); + itkSetMacro(RadiusInVoxel, double); + itkSetMacro(AbsorptionCoefficient, double); + itkSetMacro(ScatteringCoefficient, double); + itkSetMacro(AnisotopyCoefficient, double); + itkSetMacro(BifurcationFrequency, double); + itkSetMacro(DoPartialVolume, bool); protected: VesselProperties(); VesselProperties(Self::Pointer other); ~VesselProperties() override; private: Vector::Pointer m_PositionVector; Vector::Pointer m_DirectionVector; double m_RadiusInVoxel; double m_AbsorptionCoefficient; double m_ScatteringCoefficient; double m_AnisotopyCoefficient; double m_BifurcationFrequency; + bool m_DoPartialVolume; }; /** * @brief Equal A function comparing two VesselProperty instances for beeing equal * * @param rightHandSide A VesselProperty to be compared * @param leftHandSide A Vesselproperty to be compared * @param eps tolarence for comparison. You can use mitk::eps in most cases. * @param verbose flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKPHOTOACOUSTICSLIB_EXPORT bool Equal(const VesselProperties::Pointer leftHandSide, const VesselProperties::Pointer rightHandSide, double eps, bool verbose); } } #endif // MITKPhotoacousticVesselParameters_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVolume.h b/Modules/PhotoacousticsLib/include/mitkPAVolume.h index 01b62542ea..e6f60707a6 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAVolume.h +++ b/Modules/PhotoacousticsLib/include/mitkPAVolume.h @@ -1,142 +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 MITKPHOTOACOUSTIC3dVOLUME_H #define MITKPHOTOACOUSTIC3dVOLUME_H #include "MitkPhotoacousticsLibExports.h" //Includes for smart pointer usage #include #include namespace mitk { namespace pa { /** * @brief The Volume class is designed to encapsulate volumetric information and to provide convenience methods * for data access and image conversions. */ class MITKPHOTOACOUSTICSLIB_EXPORT Volume : public itk::LightObject { public: - mitkClassMacroItkParent(Volume, itk::LightObject) - - /** - *@brief returns smartpointer reference to a new instance of this objects. - * The given data array will be freed upon calling this constructor. - *@param data - *@param xDim - *@param yDim - *@param zDim - *@return smartpointer reference to a new instance of this object - */ - static Volume::Pointer New(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim); + mitkClassMacroItkParent(Volume, itk::LightObject); + + /** + *@brief returns smartpointer reference to a new instance of this objects. + * The given data array will be freed upon calling this constructor. + *@param data + *@param xDim + *@param yDim + *@param zDim + *@return smartpointer reference to a new instance of this object + */ + static Volume::Pointer New(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim, double spacing); + + static Volume::Pointer New(mitk::Image::Pointer image); /** * @brief GetData. Returns data at wanted position. For performance reasons, this method will not check, * if the specified position it within the array. Please use the GetXDim(), GetYDim() and GetZDim() methods * to check for yourself if necessary. * * @param x * @param y * @param z * @return the data contained within the data array held by this Volume at * positon x|y|z. */ double GetData(unsigned int x, unsigned int y, unsigned int z); /** * Returns a const reference to the data encapsuled by this class. */ double* GetData() const; /** * @brief SetData * @param data * @param x * @param y * @param z */ void SetData(double data, unsigned int x, unsigned int y, unsigned int z); /** * @brief GetXDim * @return size of x dimension of this Volume */ unsigned int GetXDim(); /** * @brief GetYDim * @return size of y dimension of this Volume */ unsigned int GetYDim(); /** * @brief GetZDim * @return size of z dimension of this Volume */ unsigned int GetZDim(); /** *@brief returns the Volume instance as an mitk image */ Image::Pointer AsMitkImage(); /** * @brief DeepCopy * @return a deep copy of this Volume. the old volume remains intact and memory is NOT shared * between the objects. */ Volume::Pointer DeepCopy(); /** *@brief convenience method to enable consistent access to the dat array *@return a 1d index from 3d pixel coordinates */ - int GetIndex(unsigned int x, unsigned int y, unsigned int z); + long long GetIndex(unsigned int x, unsigned int y, unsigned int z); + + double GetSpacing(); + + void SetSpacing(double spacing); protected: /** * @brief Initialize initializes this volume with the given pointer to the data array. * It is assumed, that the array is of dimension xDim|yDim|zDim. * The Photoacoustic3DVolume will handle memory management of the array and delete it on * constructor call. * * @param data a pointer to the data array * @param xDim x dimension of the data * @param yDim y dimension of the data * @param zDim z dimension of the data */ - Volume(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim); - ~Volume() override; + Volume(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim, double spacing); + Volume(mitk::Image::Pointer image); + virtual ~Volume(); const int NUMBER_OF_SPATIAL_DIMENSIONS = 3; Image::Pointer m_InternalMitkImage; // this data is kept to enable fast access unsigned int m_XDim; unsigned int m_YDim; unsigned int m_ZDim; double* m_FastAccessDataPointer; }; } } #endif // MITKPHOTOACOUSTIC3dVOLUME_H diff --git a/Modules/PhotoacousticsLib/include/mitkPAVolumeManipulator.h b/Modules/PhotoacousticsLib/include/mitkPAVolumeManipulator.h index 0aa1999d61..3a02d50974 100644 --- a/Modules/PhotoacousticsLib/include/mitkPAVolumeManipulator.h +++ b/Modules/PhotoacousticsLib/include/mitkPAVolumeManipulator.h @@ -1,53 +1,58 @@ /*=================================================================== 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 MITKPHOTOACOUSTIC3DVOLUMEMANIPULATOR_H #define MITKPHOTOACOUSTIC3DVOLUMEMANIPULATOR_H #include #include #include "mitkPAVolume.h" +#include "mitkPAInSilicoTissueVolume.h" namespace mitk { namespace pa { class MITKPHOTOACOUSTICSLIB_EXPORT VolumeManipulator final { public: /** * @brief ThresholdImage applies a binary threshold filter to this image. * @param threshold */ - static void ThresholdImage(mitk::pa::Volume::Pointer image, double threshold); + static void ThresholdImage(Volume::Pointer image, double threshold); /** * @brief Multiplies the image with a given factor * @param factor */ - static void MultiplyImage(mitk::pa::Volume::Pointer image, double factor); + static void MultiplyImage(Volume::Pointer image, double factor); - static void GaussianBlur3D(mitk::pa::Volume::Pointer paVolume, double sigma); + static void GaussianBlur3D(Volume::Pointer paVolume, double sigma); - static void Log10Image(mitk::pa::Volume::Pointer image); + static void Log10Image(Volume::Pointer image); + + static void RescaleImage(InSilicoTissueVolume::Pointer image, double ratio); + + static Volume::Pointer RescaleImage(Volume::Pointer image, double ratio, double sigma); private: VolumeManipulator(); virtual ~VolumeManipulator(); }; } } #endif // MITKPHOTOACOUSTIC3DVOLUMEMANIPULATOR_H diff --git a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVessel.cpp b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVessel.cpp index 236cf7c25e..c3c98426de 100644 --- a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVessel.cpp +++ b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVessel.cpp @@ -1,167 +1,115 @@ /*=================================================================== 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 "mitkPAVessel.h" #include #include mitk::pa::Vessel::Vessel(VesselProperties::Pointer initialProperties) : m_RangeDistribution(itk::Math::pi / 16, itk::Math::pi / 8), m_SignDistribution(-1, 1) { m_Finished = false; //Copy this so it may be reused for other vessels. m_VesselProperties = VesselProperties::New(initialProperties); m_RadiusRangeDistribution = std::uniform_real_distribution<>(NEW_RADIUS_MINIMUM_RELATIVE_SIZE, NEW_RADIUS_MAXIMUM_RELATIVE_SIZE); m_VesselMeanderStrategy = VesselMeanderStrategy::New(); m_WalkedDistance = 0; + m_VesselDrawer = VesselDrawer::New(); } mitk::pa::Vessel::~Vessel() { m_VesselProperties = nullptr; m_VesselMeanderStrategy = nullptr; } void mitk::pa::Vessel::ExpandVessel(InSilicoTissueVolume::Pointer volume, CalculateNewVesselPositionCallback calculateNewPosition, double bendingFactor, std::mt19937* rng) { - Vector::Pointer oldPosition = m_VesselProperties->GetPositionVector()->Clone(); + m_VesselDrawer->DrawVesselInVolume(m_VesselProperties, volume); (m_VesselMeanderStrategy->*calculateNewPosition)(m_VesselProperties->GetPositionVector(), m_VesselProperties->GetDirectionVector(), bendingFactor, rng); - DrawVesselInVolume(oldPosition, volume); + m_WalkedDistance += (m_VesselProperties->GetDirectionVector()->GetNorm() / volume->GetSpacing()); } bool mitk::pa::Vessel::CanBifurcate() { return m_VesselProperties->GetBifurcationFrequency() < m_WalkedDistance; } int mitk::pa::Vessel::GetSign(std::mt19937 *rng) { if (m_SignDistribution(*rng) < 0) return -1; return 1; } mitk::pa::Vessel::Pointer mitk::pa::Vessel::Bifurcate(std::mt19937* rng) { VesselProperties::Pointer vesselParams = VesselProperties::New(m_VesselProperties); double thetaChange = m_RangeDistribution(*rng) * GetSign(rng); double phiChange = m_RangeDistribution(*rng) * GetSign(rng); vesselParams->GetDirectionVector()->Rotate(thetaChange, phiChange); m_VesselProperties->GetDirectionVector()->Rotate(-thetaChange, -phiChange); double newRadius = m_RadiusRangeDistribution(*rng)*m_VesselProperties->GetRadiusInVoxel(); vesselParams->SetRadiusInVoxel(newRadius); m_VesselProperties->SetRadiusInVoxel( sqrt(m_VesselProperties->GetRadiusInVoxel()*m_VesselProperties->GetRadiusInVoxel() - newRadius*newRadius)); m_WalkedDistance = 0; return Vessel::New(vesselParams); } -void mitk::pa::Vessel::DrawVesselInVolume(Vector::Pointer fromPosition, - InSilicoTissueVolume::Pointer volume) -{ - Vector::Pointer diffVector = Vector::New(); - Vector::Pointer toPosition = m_VesselProperties->GetPositionVector(); - diffVector->SetElement(0, fromPosition->GetElement(0) - toPosition->GetElement(0)); - diffVector->SetElement(1, fromPosition->GetElement(1) - toPosition->GetElement(1)); - diffVector->SetElement(2, fromPosition->GetElement(2) - toPosition->GetElement(2)); - - //1/SCALING_FACTOR steps along the direction vector are taken and drawn into the image. - Vector::Pointer stepSize = Vector::New(); - stepSize->SetValue(m_VesselProperties->GetDirectionVector()); - stepSize->Scale(SCALING_FACTOR); - - while (diffVector->GetNorm() >= SCALING_FACTOR) - { - m_WalkedDistance += stepSize->GetNorm(); - - fromPosition->SetElement(0, fromPosition->GetElement(0) + stepSize->GetElement(0)); - fromPosition->SetElement(1, fromPosition->GetElement(1) + stepSize->GetElement(1)); - fromPosition->SetElement(2, fromPosition->GetElement(2) + stepSize->GetElement(2)); - - int xPos = fromPosition->GetElement(0); - int yPos = fromPosition->GetElement(1); - int zPos = fromPosition->GetElement(2); - - if (!volume->IsInsideVolume(xPos, yPos, zPos)) - { - m_VesselProperties->SetRadiusInVoxel(0); - break; - } - - double radius = m_VesselProperties->GetRadiusInVoxel(); - - for (int x = xPos - radius; x <= xPos + radius; x++) - for (int y = yPos - radius; y <= yPos + radius; y++) - for (int z = zPos - radius; z <= zPos + radius; z++) - { - if (radius*radius >= (x - xPos)*(x - xPos) + (y - yPos)*(y - yPos) + (z - zPos)*(z - zPos)) - { - volume->SetVolumeValues(x, y, z, m_VesselProperties->GetAbsorptionCoefficient(), - m_VesselProperties->GetScatteringCoefficient(), - m_VesselProperties->GetAnisotopyCoefficient(), - mitk::pa::InSilicoTissueVolume::SegmentationType::VESSEL); - } - } - - diffVector->SetElement(0, fromPosition->GetElement(0) - toPosition->GetElement(0)); - diffVector->SetElement(1, fromPosition->GetElement(1) - toPosition->GetElement(1)); - diffVector->SetElement(2, fromPosition->GetElement(2) - toPosition->GetElement(2)); - } -} - bool mitk::pa::Vessel::IsFinished() { return m_VesselProperties->GetRadiusInVoxel() < MINIMUM_VESSEL_RADIUS; } bool mitk::pa::Equal(const Vessel::Pointer leftHandSide, const Vessel::Pointer rightHandSide, double eps, bool verbose) { MITK_INFO(verbose) << "=== mitk::pa::Vessel Equal ==="; if (rightHandSide.IsNull() || leftHandSide.IsNull()) { MITK_INFO(verbose) << "Cannot compare nullpointers"; return false; } if (leftHandSide->IsFinished() != rightHandSide->IsFinished()) { MITK_INFO(verbose) << "Not same finished state."; return false; } if (leftHandSide->CanBifurcate() != rightHandSide->CanBifurcate()) { MITK_INFO(verbose) << "Not same bifurcation state."; return false; } if (!Equal(leftHandSide->GetVesselProperties(), rightHandSide->GetVesselProperties(), eps, verbose)) { MITK_INFO(verbose) << "Vesselproperties not equal"; return false; } return true; } diff --git a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselMeanderStrategy.cpp b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselMeanderStrategy.cpp index 699235bdac..14229f6577 100644 --- a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselMeanderStrategy.cpp +++ b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselMeanderStrategy.cpp @@ -1,53 +1,47 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPAVesselMeanderStrategy.h" mitk::pa::VesselMeanderStrategy::VesselMeanderStrategy() { } mitk::pa::VesselMeanderStrategy::~VesselMeanderStrategy() { } void mitk::pa::VesselMeanderStrategy::CalculateNewPositionInStraightLine( - Vector::Pointer position, Vector::Pointer direction, double /*bendingFactor*/, std::mt19937* rng) + Vector::Pointer /*position*/, Vector::Pointer direction, double /*bendingFactor*/, std::mt19937* rng) { if (direction->GetNorm() <= mitk::eps) { direction->Randomize(rng); } - - position->SetElement(0, position->GetElement(0) + direction->GetElement(0)); - position->SetElement(1, position->GetElement(1) + direction->GetElement(1)); - position->SetElement(2, position->GetElement(2) + direction->GetElement(2)); } void mitk::pa::VesselMeanderStrategy::CalculateRandomlyDivergingPosition( - Vector::Pointer position, Vector::Pointer direction, double bendingFactor, std::mt19937* rng) + Vector::Pointer /*position*/, Vector::Pointer direction, double bendingFactor, std::mt19937* rng) { if (direction->GetNorm() <= mitk::eps) { direction->Randomize(rng); } direction->RandomizeByPercentage(RANDOMIZATION_PERCENTAGE, bendingFactor, rng); - position->SetElement(0, position->GetElement(0) + direction->GetElement(0)); - position->SetElement(1, position->GetElement(1) + direction->GetElement(1)); - position->SetElement(2, position->GetElement(2) + direction->GetElement(2)); + direction->Normalize(); } diff --git a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselProperties.cpp b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselProperties.cpp index 63ebd6de6d..c3800ef171 100644 --- a/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselProperties.cpp +++ b/Modules/PhotoacousticsLib/src/Domain/Vessel/mitkPAVesselProperties.cpp @@ -1,101 +1,109 @@ /*=================================================================== 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 "mitkPAVesselProperties.h" mitk::pa::VesselProperties::VesselProperties() { m_PositionVector = Vector::New(); m_DirectionVector = Vector::New(); m_RadiusInVoxel = 0; m_AbsorptionCoefficient = 0; m_ScatteringCoefficient = 0; m_AnisotopyCoefficient = 0; m_BifurcationFrequency = 0; + m_DoPartialVolume = false; } mitk::pa::VesselProperties::VesselProperties(Self::Pointer other) { m_PositionVector = other->GetPositionVector()->Clone(); m_DirectionVector = other->GetDirectionVector()->Clone(); m_RadiusInVoxel = other->GetRadiusInVoxel(); m_AbsorptionCoefficient = other->GetAbsorptionCoefficient(); m_ScatteringCoefficient = other->GetScatteringCoefficient(); m_AnisotopyCoefficient = other->GetAnisotopyCoefficient(); m_BifurcationFrequency = other->GetBifurcationFrequency(); + m_DoPartialVolume = other->GetDoPartialVolume(); } mitk::pa::VesselProperties::~VesselProperties() { m_PositionVector = nullptr; m_DirectionVector = nullptr; } bool mitk::pa::Equal(const VesselProperties::Pointer leftHandSide, const VesselProperties::Pointer rightHandSide, double eps, bool verbose) { MITK_INFO(verbose) << "=== mitk::pa::VesselProperties Equal ==="; if (rightHandSide.IsNull() || leftHandSide.IsNull()) { MITK_INFO(verbose) << "Cannot compare nullpointers"; return false; } if (leftHandSide->GetAbsorptionCoefficient() - rightHandSide->GetAbsorptionCoefficient() > eps) { MITK_INFO(verbose) << "Not the same AbsorptionCoefficient."; return false; } if (leftHandSide->GetAnisotopyCoefficient() - rightHandSide->GetAnisotopyCoefficient() > eps) { MITK_INFO(verbose) << "Not the same AnisotropyCoefficient."; return false; } if (leftHandSide->GetBifurcationFrequency() - rightHandSide->GetBifurcationFrequency() > eps) { MITK_INFO(verbose) << "Not the same BifurcationFrequency."; return false; } if (leftHandSide->GetRadiusInVoxel() - rightHandSide->GetRadiusInVoxel() > eps) { MITK_INFO(verbose) << "Not the same RadiusInVoxel."; return false; } if (leftHandSide->GetScatteringCoefficient() - rightHandSide->GetScatteringCoefficient() > eps) { MITK_INFO(verbose) << "Not the same ScatteringCoefficient."; return false; } if (!Equal(leftHandSide->GetPositionVector(), rightHandSide->GetPositionVector(), eps, verbose)) { MITK_INFO(verbose) << "PositionVector not equal"; return false; } if (!Equal(leftHandSide->GetDirectionVector(), rightHandSide->GetDirectionVector(), eps, verbose)) { - MITK_INFO(verbose) << "PositionVector not equal"; + MITK_INFO(verbose) << "DirectionVector not equal"; + return false; + } + + if (!(leftHandSide->GetDoPartialVolume() == rightHandSide->GetDoPartialVolume())) + { + MITK_INFO(verbose) << "GetDoPartialVolume not equal"; return false; } return true; } diff --git a/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAInSilicoTissueVolume.cpp b/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAInSilicoTissueVolume.cpp index 3d7b5501c1..9c7f308207 100644 --- a/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAInSilicoTissueVolume.cpp +++ b/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAInSilicoTissueVolume.cpp @@ -1,325 +1,387 @@ /*=================================================================== 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 -mitk::pa::InSilicoTissueVolume::InSilicoTissueVolume(TissueGeneratorParameters::Pointer parameters) +mitk::pa::InSilicoTissueVolume::InSilicoTissueVolume(TissueGeneratorParameters::Pointer parameters, std::mt19937* rng) { { unsigned int xDim = parameters->GetXDim(); unsigned int yDim = parameters->GetYDim(); unsigned int zDim = parameters->GetZDim(); - m_TDim = 4; + m_TDim = 3; unsigned int size = xDim * yDim * zDim; auto* absorptionArray = new double[size]; auto* scatteringArray = new double[size]; auto* anisotropyArray = new double[size]; auto* segmentationArray = new double[size]; + m_InitialBackgroundAbsorption = (parameters->GetMinBackgroundAbsorption() + parameters->GetMaxBackgroundAbsorption()) / 2; + m_Rng = rng; + for (unsigned int index = 0; index < size; index++) { - absorptionArray[index] = parameters->GetBackgroundAbsorption(); + absorptionArray[index] = m_InitialBackgroundAbsorption; scatteringArray[index] = parameters->GetBackgroundScattering(); anisotropyArray[index] = parameters->GetBackgroundAnisotropy(); segmentationArray[index] = SegmentationType::BACKGROUND; } - m_AbsorptionVolume = Volume::New(absorptionArray, xDim, yDim, zDim); - m_ScatteringVolume = Volume::New(scatteringArray, xDim, yDim, zDim); - m_AnisotropyVolume = Volume::New(anisotropyArray, xDim, yDim, zDim); - m_SegmentationVolume = Volume::New(segmentationArray, xDim, yDim, zDim); + m_AbsorptionVolume = Volume::New(absorptionArray, xDim, yDim, zDim, parameters->GetVoxelSpacingInCentimeters()); + m_ScatteringVolume = Volume::New(scatteringArray, xDim, yDim, zDim, parameters->GetVoxelSpacingInCentimeters()); + m_AnisotropyVolume = Volume::New(anisotropyArray, xDim, yDim, zDim, parameters->GetVoxelSpacingInCentimeters()); + m_SegmentationVolume = Volume::New(segmentationArray, xDim, yDim, zDim, parameters->GetVoxelSpacingInCentimeters()); } m_TissueParameters = parameters; m_PropertyList = mitk::PropertyList::New(); UpdatePropertyList(); } void mitk::pa::InSilicoTissueVolume::UpdatePropertyList() { //Set properties AddIntProperty("mcflag", m_TissueParameters->GetMCflag()); AddIntProperty("launchflag", m_TissueParameters->GetMCLaunchflag()); AddIntProperty("boundaryflag", m_TissueParameters->GetMCBoundaryflag()); AddDoubleProperty("launchPointX", m_TissueParameters->GetMCLaunchPointX()); AddDoubleProperty("launchPointY", m_TissueParameters->GetMCLaunchPointY()); AddDoubleProperty("launchPointZ", m_TissueParameters->GetMCLaunchPointZ()); AddDoubleProperty("focusPointX", m_TissueParameters->GetMCFocusPointX()); AddDoubleProperty("focusPointY", m_TissueParameters->GetMCFocusPointY()); AddDoubleProperty("focusPointZ", m_TissueParameters->GetMCFocusPointZ()); AddDoubleProperty("trajectoryVectorX", m_TissueParameters->GetMCTrajectoryVectorX()); AddDoubleProperty("trajectoryVectorY", m_TissueParameters->GetMCTrajectoryVectorY()); AddDoubleProperty("trajectoryVectorZ", m_TissueParameters->GetMCTrajectoryVectorZ()); AddDoubleProperty("radius", m_TissueParameters->GetMCRadius()); AddDoubleProperty("waist", m_TissueParameters->GetMCWaist()); - if (m_TissueParameters->GetDoVolumeSmoothing()) - AddDoubleProperty("sigma", m_TissueParameters->GetVolumeSmoothingSigma()); - else - AddDoubleProperty("sigma", 0); - AddDoubleProperty("standardTissueAbsorption", m_TissueParameters->GetBackgroundAbsorption()); + AddDoubleProperty("partialVolume", m_TissueParameters->GetDoPartialVolume()); + AddDoubleProperty("standardTissueAbsorptionMin", m_TissueParameters->GetMinBackgroundAbsorption()); + AddDoubleProperty("standardTissueAbsorptionMax", m_TissueParameters->GetMaxBackgroundAbsorption()); AddDoubleProperty("standardTissueScattering", m_TissueParameters->GetBackgroundScattering()); AddDoubleProperty("standardTissueAnisotropy", m_TissueParameters->GetBackgroundAnisotropy()); AddDoubleProperty("airThickness", m_TissueParameters->GetAirThicknessInMillimeters()); AddDoubleProperty("skinThickness", m_TissueParameters->GetSkinThicknessInMillimeters()); } mitk::pa::InSilicoTissueVolume::InSilicoTissueVolume( Volume::Pointer absorptionVolume, Volume::Pointer scatteringVolume, Volume::Pointer anisotropyVolume, Volume::Pointer segmentationVolume, TissueGeneratorParameters::Pointer tissueParameters, mitk::PropertyList::Pointer propertyList) { m_AbsorptionVolume = absorptionVolume; m_ScatteringVolume = scatteringVolume; m_AnisotropyVolume = anisotropyVolume; m_SegmentationVolume = segmentationVolume; m_TissueParameters = tissueParameters; m_PropertyList = propertyList; if (m_SegmentationVolume.IsNotNull()) m_TDim = 4; else m_TDim = 3; } +double mitk::pa::InSilicoTissueVolume::GetSpacing() +{ + return m_AbsorptionVolume->GetSpacing(); +} + +void mitk::pa::InSilicoTissueVolume::SetSpacing(double spacing) +{ + m_AbsorptionVolume->SetSpacing(spacing); + m_ScatteringVolume->SetSpacing(spacing); + m_AnisotropyVolume->SetSpacing(spacing); + m_SegmentationVolume->SetSpacing(spacing); +} + void mitk::pa::InSilicoTissueVolume::AddDoubleProperty(std::string label, double value) { m_PropertyList->SetDoubleProperty(label.c_str(), value); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New(label)); } void mitk::pa::InSilicoTissueVolume::AddIntProperty(std::string label, int value) { m_PropertyList->SetIntProperty(label.c_str(), value); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New(label)); } mitk::Image::Pointer mitk::pa::InSilicoTissueVolume::ConvertToMitkImage() { mitk::Image::Pointer resultImage = mitk::Image::New(); mitk::PixelType TPixel = mitk::MakeScalarPixelType(); auto* dimensionsOfImage = new unsigned int[4]; // Copy dimensions dimensionsOfImage[0] = m_TissueParameters->GetYDim(); dimensionsOfImage[1] = m_TissueParameters->GetXDim(); dimensionsOfImage[2] = m_TissueParameters->GetZDim(); dimensionsOfImage[3] = m_TDim; - MITK_INFO << "Initializing image..."; resultImage->Initialize(TPixel, 4, dimensionsOfImage, 1); - MITK_INFO << "Initializing image...[Done]"; mitk::Vector3D spacing; spacing.Fill(m_TissueParameters->GetVoxelSpacingInCentimeters()); resultImage->SetSpacing(spacing); - MITK_INFO << "Set Import Volumes..."; - //Copy memory, deal with cleaning up memory yourself! resultImage->SetImportVolume(m_AbsorptionVolume->GetData(), 0, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_ScatteringVolume->GetData(), 1, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_AnisotropyVolume->GetData(), 2, 0, mitk::Image::CopyMemory); resultImage->SetImportVolume(m_SegmentationVolume->GetData(), 3, 0, mitk::Image::CopyMemory); - MITK_INFO << "Set Import Volumes...[Done]"; resultImage->SetPropertyList(m_PropertyList); return resultImage; } mitk::pa::InSilicoTissueVolume::Pointer mitk::pa::InSilicoTissueVolume::New( Volume::Pointer absorptionVolume, Volume::Pointer scatteringVolume, Volume::Pointer anisotropyVolume, Volume::Pointer segmentationVolume, TissueGeneratorParameters::Pointer tissueParameters, mitk::PropertyList::Pointer propertyList) { InSilicoTissueVolume::Pointer smartPtr = new InSilicoTissueVolume( absorptionVolume, scatteringVolume, anisotropyVolume, segmentationVolume, tissueParameters, propertyList); smartPtr->UnRegister(); return smartPtr; } mitk::pa::InSilicoTissueVolume::~InSilicoTissueVolume() { m_AbsorptionVolume = nullptr; m_ScatteringVolume = nullptr; m_AnisotropyVolume = nullptr; m_SegmentationVolume = nullptr; m_TissueParameters = nullptr; m_PropertyList = nullptr; } +void mitk::pa::InSilicoTissueVolume::SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy) +{ + if (IsInsideVolume(x, y, z)) + { + m_AbsorptionVolume->SetData(absorption, x, y, z); + m_ScatteringVolume->SetData(scattering, x, y, z); + m_AnisotropyVolume->SetData(anisotropy, x, y, z); + } +} + void mitk::pa::InSilicoTissueVolume::SetVolumeValues(int x, int y, int z, double absorption, double scattering, double anisotropy, SegmentationType segmentType) { if (IsInsideVolume(x, y, z)) { m_AbsorptionVolume->SetData(absorption, x, y, z); m_ScatteringVolume->SetData(scattering, x, y, z); m_AnisotropyVolume->SetData(anisotropy, x, y, z); m_SegmentationVolume->SetData(segmentType, x, y, z); } } bool mitk::pa::InSilicoTissueVolume::IsInsideVolume(int x, int y, int z) { return x >= 0 && x < m_TissueParameters->GetXDim() && y >= 0 && y < m_TissueParameters->GetYDim() && z >= 0 && z < m_TissueParameters->GetZDim(); } mitk::pa::Volume::Pointer mitk::pa::InSilicoTissueVolume::GetAbsorptionVolume() { return m_AbsorptionVolume; } mitk::pa::Volume::Pointer mitk::pa::InSilicoTissueVolume::GetSegmentationVolume() { return m_SegmentationVolume; } void mitk::pa::InSilicoTissueVolume::FinalizeVolume() { AddSkinAndAirLayers(); // If specified, randomize all tissue parameters if (m_TissueParameters->GetRandomizePhysicalProperties()) + { RandomizeTissueCoefficients(m_TissueParameters->GetUseRngSeed(), m_TissueParameters->GetRngSeed(), m_TissueParameters->GetRandomizePhysicalPropertiesPercentage()); + } + + unsigned int xDim = m_TissueParameters->GetXDim(); + unsigned int yDim = m_TissueParameters->GetYDim(); + unsigned int zDim = m_TissueParameters->GetZDim(); + + std::uniform_real_distribution randomBackgroundAbsorptionDistribution( + m_TissueParameters->GetMinBackgroundAbsorption(), m_TissueParameters->GetMaxBackgroundAbsorption()); + + for (unsigned int z = 0; z < zDim; z++) + { + for (unsigned int y = 0; y < yDim; y++) + { + for (unsigned int x = 0; x < xDim; x++) + { + if (fabs(m_AbsorptionVolume->GetData(x, y, z) - m_InitialBackgroundAbsorption) < mitk::eps) + { + m_AbsorptionVolume->SetData(randomBackgroundAbsorptionDistribution(*m_Rng), x, y, z); + } + } + } + } } void mitk::pa::InSilicoTissueVolume::AddSkinAndAirLayers() { //Calculate the index location according to thickness in cm double airvoxel = (m_TissueParameters->GetAirThicknessInMillimeters() / m_TissueParameters->GetVoxelSpacingInCentimeters()) / 10; double skinvoxel = airvoxel + (m_TissueParameters->GetSkinThicknessInMillimeters() / m_TissueParameters->GetVoxelSpacingInCentimeters()) / 10; for (int y = 0; y < m_TissueParameters->GetYDim(); y++) { for (int x = 0; x < m_TissueParameters->GetXDim(); x++) { // Add air from index 0 to airvoxel if (m_TissueParameters->GetAirThicknessInMillimeters() > mitk::eps) { FillZLayer(x, y, 0, airvoxel, m_TissueParameters->GetAirAbsorption(), m_TissueParameters->GetAirScattering(), m_TissueParameters->GetAirAnisotropy(), SegmentationType::AIR); } //Add skin from index airvoxel to skinvoxel if (m_TissueParameters->GetSkinThicknessInMillimeters() > mitk::eps) { FillZLayer(x, y, airvoxel, skinvoxel, m_TissueParameters->GetSkinAbsorption(), m_TissueParameters->GetSkinScattering(), m_TissueParameters->GetSkinAnisotropy(), SegmentationType::SKIN); } } } } void mitk::pa::InSilicoTissueVolume::FillZLayer(int x, int y, double startIdx, double endIdx, double absorption, double scattering, double anisotropy, SegmentationType segmentationType) { for (int z = startIdx; z < endIdx; z++) { if (IsInsideVolume(x, y, z)) { if (endIdx - z < 1) { //Simulate partial volume effects m_AbsorptionVolume->SetData((1 - (endIdx - z)) * m_AbsorptionVolume->GetData(x, y, z) + (endIdx - z) * absorption, x, y, z); m_ScatteringVolume->SetData((1 - (endIdx - z)) * m_ScatteringVolume->GetData(x, y, z) + (endIdx - z) * scattering, x, y, z); m_AnisotropyVolume->SetData((1 - (endIdx - z)) * m_AnisotropyVolume->GetData(x, y, z) + (endIdx - z) * anisotropy, x, y, z); if (endIdx - z > 0.5) { //Only put the segmentation label if more than half of the partial volume is the wanted tissue type m_SegmentationVolume->SetData(segmentationType, x, y, z); } } else { m_AbsorptionVolume->SetData(absorption, x, y, z); m_ScatteringVolume->SetData(scattering, x, y, z); m_AnisotropyVolume->SetData(anisotropy, x, y, z); m_SegmentationVolume->SetData(segmentationType, x, y, z); } } } } void mitk::pa::InSilicoTissueVolume::RandomizeTissueCoefficients(long rngSeed, bool useRngSeed, double percentage) { std::mt19937 rng; std::random_device randomDevice; if (useRngSeed) { rng.seed(rngSeed); } else { if (randomDevice.entropy() > 0.1) { rng.seed(randomDevice()); } else { rng.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); } } std::normal_distribution<> percentageDistribution(1, percentage / 100); for (int y = 0; y < m_TissueParameters->GetYDim(); y++) { for (int x = 0; x < m_TissueParameters->GetXDim(); x++) { for (int z = 0; z < m_TissueParameters->GetZDim(); z++) { m_AbsorptionVolume->SetData(m_AbsorptionVolume->GetData(x, y, z) * percentageDistribution(rng), x, y, z); m_ScatteringVolume->SetData(m_ScatteringVolume->GetData(x, y, z) * percentageDistribution(rng), x, y, z); } } } } mitk::pa::Volume::Pointer mitk::pa::InSilicoTissueVolume::GetScatteringVolume() { return m_ScatteringVolume; } mitk::pa::Volume::Pointer mitk::pa::InSilicoTissueVolume::GetAnisotropyVolume() { return m_AnisotropyVolume; } + +void mitk::pa::InSilicoTissueVolume::SetAbsorptionVolume(Volume::Pointer volume) +{ + m_AbsorptionVolume = volume; +} + +void mitk::pa::InSilicoTissueVolume::SetScatteringVolume(Volume::Pointer volume) +{ + m_ScatteringVolume = volume; +} + +void mitk::pa::InSilicoTissueVolume::SetAnisotropyVolume(Volume::Pointer volume) +{ + m_AnisotropyVolume = volume; +} + +void mitk::pa::InSilicoTissueVolume::SetSegmentationVolume(Volume::Pointer volume) +{ + m_SegmentationVolume = volume; +} diff --git a/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAVolume.cpp b/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAVolume.cpp index 5e4e013fcb..8ae9e32bb2 100644 --- a/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAVolume.cpp +++ b/Modules/PhotoacousticsLib/src/Domain/Volume/mitkPAVolume.cpp @@ -1,115 +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 "mitkPAVolume.h" #include #include #include mitk::pa::Volume::Volume(double* data, - unsigned int xDim, unsigned int yDim, unsigned int zDim) + unsigned int xDim, unsigned int yDim, unsigned int zDim, double spacing) { + MITK_INFO << "Initialized by data*"; if (data == nullptr) mitkThrow() << "You may not initialize a mitk::Volume with a nullptr"; m_InternalMitkImage = mitk::Image::New(); auto* dimensions = new unsigned int[NUMBER_OF_SPATIAL_DIMENSIONS]; dimensions[0] = yDim; dimensions[1] = xDim; dimensions[2] = zDim; m_XDim = xDim; m_YDim = yDim; m_ZDim = zDim; mitk::PixelType pixelType = mitk::MakeScalarPixelType(); m_InternalMitkImage->Initialize(pixelType, NUMBER_OF_SPATIAL_DIMENSIONS, dimensions); m_InternalMitkImage->SetImportVolume(data, Image::ImportMemoryManagementType::CopyMemory); + SetSpacing(spacing); + m_FastAccessDataPointer = GetData(); delete data; } +mitk::pa::Volume::Volume(mitk::Image::Pointer image) +{ + MITK_INFO << "Initialized by mitk::Image"; + + if (image.IsNull()) + mitkThrow() << "You may not initialize a mitk::Volume with a null reference to an mitk image"; + + unsigned int* dimensions = image->GetDimensions(); + m_YDim = dimensions[0]; + m_XDim = dimensions[1]; + m_ZDim = dimensions[2]; + + m_InternalMitkImage = image; + + m_FastAccessDataPointer = GetData(); +} + +double mitk::pa::Volume::GetSpacing() +{ + return m_InternalMitkImage->GetGeometry()->GetSpacing()[0]; +} + +void mitk::pa::Volume::SetSpacing(double spacing) +{ + const mitk::ScalarType spacingArray[]{ spacing, spacing, spacing }; + m_InternalMitkImage->SetSpacing(spacingArray); +} + mitk::pa::Volume::~Volume() { m_InternalMitkImage = nullptr; } -mitk::pa::Volume::Pointer mitk::pa::Volume::New(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim) +mitk::pa::Volume::Pointer mitk::pa::Volume::New(double* data, unsigned int xDim, unsigned int yDim, unsigned int zDim, double spacing) +{ + mitk::pa::Volume::Pointer smartPtr = new mitk::pa::Volume(data, xDim, yDim, zDim, spacing); + smartPtr->UnRegister(); + return smartPtr; +} + +mitk::pa::Volume::Pointer mitk::pa::Volume::New(mitk::Image::Pointer image) { - mitk::pa::Volume::Pointer smartPtr = new mitk::pa::Volume(data, xDim, yDim, zDim); + mitk::pa::Volume::Pointer smartPtr = new mitk::pa::Volume(image); smartPtr->UnRegister(); return smartPtr; } mitk::Image::Pointer mitk::pa::Volume::AsMitkImage() { return m_InternalMitkImage; } mitk::pa::Volume::Pointer mitk::pa::Volume::DeepCopy() { long length = GetXDim()*GetYDim()*GetZDim(); auto* data = new double[length]; memcpy(data, GetData(), length * sizeof(double)); - return mitk::pa::Volume::New(data, GetXDim(), GetYDim(), GetZDim()); + return mitk::pa::Volume::New(data, GetXDim(), GetYDim(), GetZDim(), GetSpacing()); } double mitk::pa::Volume::GetData(unsigned int x, unsigned int y, unsigned int z) { return m_FastAccessDataPointer[GetIndex(x, y, z)]; } void mitk::pa::Volume::SetData(double data, unsigned int x, unsigned int y, unsigned int z) { m_FastAccessDataPointer[GetIndex(x, y, z)] = data; } unsigned int mitk::pa::Volume::GetXDim() { return m_XDim; } unsigned int mitk::pa::Volume::GetYDim() { return m_YDim; } unsigned int mitk::pa::Volume::GetZDim() { return m_ZDim; } double* mitk::pa::Volume::GetData() const { mitk::ImageWriteAccessor imgRead(m_InternalMitkImage, m_InternalMitkImage->GetVolumeData()); return (double*)imgRead.GetData(); } -int mitk::pa::Volume::GetIndex(unsigned int x, unsigned int y, unsigned int z) +long long mitk::pa::Volume::GetIndex(unsigned int x, unsigned int y, unsigned int z) { #ifdef _DEBUG if (x < 0 || x >(GetXDim() - 1) || y < 0 || y >(GetYDim() - 1) || z < 0 || z >(GetZDim() - 1)) { MITK_ERROR << "Index out of bounds at " << x << "|" << y << "|" << z; mitkThrow() << "Index out of bounds exception!"; } #endif - return z * m_XDim * m_YDim + x * m_YDim + y; + return ((long long)z) * m_XDim * m_YDim + ((long long)x) * m_YDim + ((long long)y); } diff --git a/Modules/PhotoacousticsLib/src/Generator/mitkPAPhantomTissueGenerator.cpp b/Modules/PhotoacousticsLib/src/Generator/mitkPAPhantomTissueGenerator.cpp new file mode 100644 index 0000000000..167e30b0bb --- /dev/null +++ b/Modules/PhotoacousticsLib/src/Generator/mitkPAPhantomTissueGenerator.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "mitkPAPhantomTissueGenerator.h" +#include "mitkPAVector.h" +#include "mitkPAVolumeManipulator.h" + +mitk::pa::InSilicoTissueVolume::Pointer mitk::pa::PhantomTissueGenerator::GeneratePhantomData( + TissueGeneratorParameters::Pointer parameters) +{ + MITK_DEBUG << "Initializing Empty Volume"; + + const double RESAMPLING_FACTOR = 2; + + if (parameters->GetDoPartialVolume()) + { + parameters->SetXDim(parameters->GetXDim() * RESAMPLING_FACTOR); + parameters->SetYDim(parameters->GetYDim() * RESAMPLING_FACTOR); + parameters->SetZDim(parameters->GetZDim() * RESAMPLING_FACTOR); + parameters->SetVesselBifurcationFrequency(parameters->GetVesselBifurcationFrequency() * RESAMPLING_FACTOR); + parameters->SetVoxelSpacingInCentimeters(parameters->GetVoxelSpacingInCentimeters() / RESAMPLING_FACTOR); + } + + parameters->SetVesselBifurcationFrequency(10000); + + std::mt19937 randomNumberGenerator; + std::random_device randomDevice; + if (parameters->GetUseRngSeed()) + { + randomNumberGenerator.seed(parameters->GetRngSeed()); + } + else + { + if (randomDevice.entropy() > 0.1) + { + randomNumberGenerator.seed(randomDevice()); + } + else + { + randomNumberGenerator.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); + } + } + + auto generatedVolume = mitk::pa::InSilicoTissueVolume::New(parameters, &randomNumberGenerator); + + const unsigned int NUMER_OF_VESSELS = 5; + const double START_DEPTH_IN_CM = 2.10; + const double START_X_IN_CM = 0.76; + const double RADIUS_IN_MM = 0.5; + const double INCREMENT_XZ_IN_CM = 0.50; + double ABSORPTION_PER_CM = parameters->GetMinVesselAbsorption(); + + generatedVolume->AddIntProperty("numberOfVessels", NUMER_OF_VESSELS); + generatedVolume->AddIntProperty("bifurcationFrequency", parameters->GetVesselBifurcationFrequency()); + + for (unsigned int vesselNumber = 0; vesselNumber < NUMER_OF_VESSELS; vesselNumber++) + { + Vector::Pointer initialPosition = Vector::New(); + Vector::Pointer initialDirection = Vector::New(); + + double initialRadius = RADIUS_IN_MM / parameters->GetVoxelSpacingInCentimeters() / 10; + std::stringstream radiusString; + radiusString << "vessel_" << vesselNumber + 1 << "_radius"; + generatedVolume->AddDoubleProperty(radiusString.str(), initialRadius); + + double absorptionCoefficient = ABSORPTION_PER_CM; + std::stringstream absorptionString; + absorptionString << "vessel_" << vesselNumber + 1 << "_absorption"; + generatedVolume->AddDoubleProperty(absorptionString.str(), absorptionCoefficient); + + double bendingFactor = 0; + std::stringstream bendingString; + bendingString << "vessel_" << vesselNumber + 1 << "_bendingFactor"; + generatedVolume->AddDoubleProperty(bendingString.str(), bendingFactor); + + double vesselScattering = 15; + std::stringstream scatteringString; + scatteringString << "vessel_" << vesselNumber + 1 << "_scattering"; + generatedVolume->AddDoubleProperty(scatteringString.str(), vesselScattering); + + double vesselAnisotropy = 0.9; + std::stringstream anisotropyString; + anisotropyString << "vessel_" << vesselNumber + 1 << "_anisotropy"; + generatedVolume->AddDoubleProperty(anisotropyString.str(), vesselAnisotropy); + + /*The vessel tree shall start at one of the 4 sides of the volume. + * The vessels will always be completely contained in the volume + * when starting to meander. + * They will meander in a direction perpendicular to the + * plane they started from (within the limits of the + * DIRECTION_VECTOR_INITIAL_VARIANCE) + */ + + double zposition = (START_DEPTH_IN_CM + (vesselNumber*INCREMENT_XZ_IN_CM)) / parameters->GetVoxelSpacingInCentimeters(); + + double xposition = (START_X_IN_CM + (vesselNumber*INCREMENT_XZ_IN_CM)) / parameters->GetVoxelSpacingInCentimeters(); + + initialPosition->Randomize(xposition, xposition, 0, 0, zposition, zposition, &randomNumberGenerator); + initialDirection->Randomize(0, 0, 1, 1, 0, 0, &randomNumberGenerator); + + initialDirection->Normalize(); + MITK_INFO << initialPosition->GetElement(0) << " | " << initialPosition->GetElement(1) << " | " << initialPosition->GetElement(2); + MITK_INFO << initialDirection->GetElement(0) << " | " << initialDirection->GetElement(1) << " | " << initialDirection->GetElement(2); + + VesselProperties::Pointer vesselParams = VesselProperties::New(); + vesselParams->SetDirectionVector(initialDirection); + vesselParams->SetPositionVector(initialPosition); + vesselParams->SetRadiusInVoxel(initialRadius); + vesselParams->SetAbsorptionCoefficient(absorptionCoefficient); + vesselParams->SetScatteringCoefficient(vesselScattering); + vesselParams->SetAnisotopyCoefficient(vesselAnisotropy); + vesselParams->SetBifurcationFrequency(parameters->GetVesselBifurcationFrequency()); + vesselParams->SetDoPartialVolume(parameters->GetDoPartialVolume()); + + VesselTree::Pointer vesselTree = VesselTree::New(vesselParams); + + while (!vesselTree->IsFinished()) + { + vesselTree->Step(generatedVolume, parameters->GetCalculateNewVesselPositionCallback(), bendingFactor, &randomNumberGenerator); + } + } + + if (parameters->GetDoPartialVolume()) + { + VolumeManipulator::RescaleImage(generatedVolume, (1.0 / RESAMPLING_FACTOR)); + parameters->SetXDim(parameters->GetXDim() / RESAMPLING_FACTOR); + parameters->SetYDim(parameters->GetYDim() / RESAMPLING_FACTOR); + parameters->SetZDim(parameters->GetZDim() / RESAMPLING_FACTOR); + parameters->SetVesselBifurcationFrequency(parameters->GetVesselBifurcationFrequency() / RESAMPLING_FACTOR); + parameters->SetVoxelSpacingInCentimeters(parameters->GetVoxelSpacingInCentimeters() * RESAMPLING_FACTOR); + } + + generatedVolume->FinalizeVolume(); + + return generatedVolume; +} + +mitk::pa::PhantomTissueGenerator::PhantomTissueGenerator() +{ +} + +mitk::pa::PhantomTissueGenerator::~PhantomTissueGenerator() +{ +} diff --git a/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp b/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp index c310767c39..cd6cf1ea7a 100644 --- a/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp +++ b/Modules/PhotoacousticsLib/src/Generator/mitkPASlicedVolumeGenerator.cpp @@ -1,118 +1,118 @@ /*=================================================================== 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 "mitkPASlicedVolumeGenerator.h" #include mitk::pa::SlicedVolumeGenerator::SlicedVolumeGenerator(int centralYSlice, bool precorrect, Volume::Pointer precorrectionVolume, bool inverse) { m_CentralYSlice = centralYSlice; m_Precorrect = precorrect; m_Inverse = inverse; m_PrecorrectionVolume = nullptr; if (m_Precorrect) { m_PrecorrectionVolume = precorrectionVolume; } } mitk::pa::SlicedVolumeGenerator::~SlicedVolumeGenerator() { m_CentralYSlice = -1; m_Precorrect = false; m_PrecorrectionVolume = nullptr; } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedFluenceImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int index = z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx; imageArray[index] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_CentralYSlice, z); if (m_Precorrect) { imageArray[index] = imageArray[index] / m_PrecorrectionVolume->GetData(x, m_CentralYSlice, z); } if (m_Inverse) { if (std::abs(imageArray[index] - 0) >= mitk::eps) imageArray[index] = 1 / imageArray[index]; else imageArray[index] = INFINITY; } } - return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); + return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim, composedVolume->GetGroundTruthVolume()->GetSpacing()); } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedSignalImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int y = m_CentralYSlice + composedVolume->GetYOffsetForFluenceComponentInPixels(fluenceComponentIdx); imageArray[z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx] = composedVolume->GetFluenceValue(fluenceComponentIdx, x, m_CentralYSlice, z) * composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetData(x, y, z); } - return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); + return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim, composedVolume->GetGroundTruthVolume()->GetSpacing()); } mitk::pa::Volume::Pointer mitk::pa::SlicedVolumeGenerator::GetSlicedGroundTruthImageFromComposedVolume( ComposedVolume::Pointer composedVolume) { int fluenceComponents = composedVolume->GetNumberOfFluenceComponents(); int xDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetXDim(); int zDim = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetZDim(); auto* imageArray = new double[xDim*zDim*fluenceComponents]; for (int fluenceComponentIdx = 0; fluenceComponentIdx < fluenceComponents; fluenceComponentIdx++) for (int z = 0; z < zDim; z++) for (int x = 0; x < xDim; x++) { int y = m_CentralYSlice + composedVolume->GetYOffsetForFluenceComponentInPixels(fluenceComponentIdx); imageArray[z * xDim * fluenceComponents + x * fluenceComponents + fluenceComponentIdx] = composedVolume->GetGroundTruthVolume()->GetAbsorptionVolume()->GetData(x, y, z); } - return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim); + return mitk::pa::Volume::New(imageArray, xDim, fluenceComponents, zDim, composedVolume->GetGroundTruthVolume()->GetSpacing()); } diff --git a/Modules/PhotoacousticsLib/src/Generator/mitkPATissueGenerator.cpp b/Modules/PhotoacousticsLib/src/Generator/mitkPATissueGenerator.cpp index c2704dce5a..cbe23af73d 100644 --- a/Modules/PhotoacousticsLib/src/Generator/mitkPATissueGenerator.cpp +++ b/Modules/PhotoacousticsLib/src/Generator/mitkPATissueGenerator.cpp @@ -1,160 +1,199 @@ /*=================================================================== 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 "mitkPATissueGenerator.h" #include "mitkPAVector.h" #include "mitkPAVolumeManipulator.h" mitk::pa::InSilicoTissueVolume::Pointer mitk::pa::InSilicoTissueGenerator::GenerateInSilicoData( TissueGeneratorParameters::Pointer parameters) { MITK_DEBUG << "Initializing Empty Volume"; - auto generatedVolume = mitk::pa::InSilicoTissueVolume::New(parameters); + const double RESAMPLING_FACTOR = 2; - const double DIRECTION_VECTOR_INITIAL_VARIANCE = 0.2; + if (parameters->GetDoPartialVolume()) + { + parameters->SetXDim(parameters->GetXDim() * RESAMPLING_FACTOR); + parameters->SetYDim(parameters->GetYDim() * RESAMPLING_FACTOR); + parameters->SetZDim(parameters->GetZDim() * RESAMPLING_FACTOR); + parameters->SetVesselBifurcationFrequency(parameters->GetVesselBifurcationFrequency() * RESAMPLING_FACTOR); + parameters->SetVoxelSpacingInCentimeters(parameters->GetVoxelSpacingInCentimeters() / RESAMPLING_FACTOR); + } std::mt19937 randomNumberGenerator; std::random_device randomDevice; if (parameters->GetUseRngSeed()) { randomNumberGenerator.seed(parameters->GetRngSeed()); } else { if (randomDevice.entropy() > 0.1) { randomNumberGenerator.seed(randomDevice()); } else { randomNumberGenerator.seed(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); } } - std::uniform_int_distribution randomNumVesselDistribution(parameters->GetMinNumberOfVessels(), parameters->GetMaxNumberOfVessels()); - std::uniform_real_distribution randomBendingDistribution(parameters->GetMinVesselBending(), parameters->GetMaxVesselBending()); - std::uniform_real_distribution randomAbsorptionDistribution(parameters->GetMinVesselAbsorption(), parameters->GetMaxVesselAbsorption()); - std::uniform_real_distribution randomRadiusDistribution(parameters->GetMinVesselRadiusInMillimeters(), parameters->GetMaxVesselRadiusInMillimeters()); - std::uniform_real_distribution randomScatteringDistribution(parameters->GetMinVesselScattering(), parameters->GetMaxVesselScattering()); - std::uniform_real_distribution randomAnisotropyDistribution(parameters->GetMinVesselAnisotropy(), parameters->GetMaxVesselAnisotropy()); + auto generatedVolume = mitk::pa::InSilicoTissueVolume::New(parameters, &randomNumberGenerator); + + double DIRECTION_VECTOR_INITIAL_VARIANCE = 0.2; + + if(parameters->GetForceVesselsMoveAlongYDirection()) + DIRECTION_VECTOR_INITIAL_VARIANCE = 0; + + std::uniform_int_distribution randomNumVesselDistribution( + parameters->GetMinNumberOfVessels(), parameters->GetMaxNumberOfVessels()); + std::uniform_real_distribution randomBendingDistribution( + parameters->GetMinVesselBending(), parameters->GetMaxVesselBending()); + std::uniform_real_distribution randomAbsorptionDistribution( + parameters->GetMinVesselAbsorption(), parameters->GetMaxVesselAbsorption()); + std::uniform_real_distribution randomRadiusDistribution( + parameters->GetMinVesselRadiusInMillimeters(), parameters->GetMaxVesselRadiusInMillimeters()); + std::uniform_real_distribution randomScatteringDistribution( + parameters->GetMinVesselScattering(), parameters->GetMaxVesselScattering()); + std::uniform_real_distribution randomAnisotropyDistribution( + parameters->GetMinVesselAnisotropy(), parameters->GetMaxVesselAnisotropy()); std::uniform_int_distribution borderTypeDistribution(0, 3); int numberOfBloodVessels = randomNumVesselDistribution(randomNumberGenerator); generatedVolume->AddIntProperty("numberOfVessels", numberOfBloodVessels); generatedVolume->AddIntProperty("bifurcationFrequency", parameters->GetVesselBifurcationFrequency()); MITK_INFO << "Simulating " << numberOfBloodVessels << " vessel structures"; for (int vesselNumber = 0; vesselNumber < numberOfBloodVessels; vesselNumber++) { Vector::Pointer initialPosition = Vector::New(); Vector::Pointer initialDirection = Vector::New(); double initialRadius = randomRadiusDistribution(randomNumberGenerator) / parameters->GetVoxelSpacingInCentimeters() / 10; std::stringstream radiusString; radiusString << "vessel_" << vesselNumber + 1 << "_radius"; generatedVolume->AddDoubleProperty(radiusString.str(), initialRadius); double absorptionCoefficient = randomAbsorptionDistribution(randomNumberGenerator); std::stringstream absorptionString; absorptionString << "vessel_" << vesselNumber + 1 << "_absorption"; generatedVolume->AddDoubleProperty(absorptionString.str(), absorptionCoefficient); double bendingFactor = randomBendingDistribution(randomNumberGenerator); std::stringstream bendingString; bendingString << "vessel_" << vesselNumber + 1 << "_bendingFactor"; generatedVolume->AddDoubleProperty(bendingString.str(), bendingFactor); double vesselScattering = randomScatteringDistribution(randomNumberGenerator); std::stringstream scatteringString; scatteringString << "vessel_" << vesselNumber + 1 << "_scattering"; generatedVolume->AddDoubleProperty(scatteringString.str(), vesselScattering); double vesselAnisotropy = randomAnisotropyDistribution(randomNumberGenerator); std::stringstream anisotropyString; anisotropyString << "vessel_" << vesselNumber + 1 << "_anisotropy"; generatedVolume->AddDoubleProperty(anisotropyString.str(), vesselAnisotropy); /*The vessel tree shall start at one of the 4 sides of the volume. * The vessels will always be completely contained in the volume * when starting to meander. * They will meander in a direction perpendicular to the * plane they started from (within the limits of the * DIRECTION_VECTOR_INITIAL_VARIANCE) */ int borderType = borderTypeDistribution(randomNumberGenerator); + + if(parameters->GetForceVesselsMoveAlongYDirection()) + borderType = 2; + switch (borderType) { case 0: - initialPosition->Randomize(0, 0, initialRadius, parameters->GetYDim() - initialRadius, parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), + initialPosition->Randomize(0, 0, initialRadius, parameters->GetYDim() - initialRadius, + parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), parameters->GetMaxVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), &randomNumberGenerator); initialDirection->Randomize(1, 2, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; case 1: - initialPosition->Randomize(parameters->GetXDim(), parameters->GetXDim(), initialRadius, parameters->GetYDim() - initialRadius, parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), + initialPosition->Randomize(parameters->GetXDim() - 1, parameters->GetXDim() - 1, initialRadius, parameters->GetYDim() - initialRadius, + parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), parameters->GetMaxVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), &randomNumberGenerator); initialDirection->Randomize(-2, -1, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; case 2: - initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, 0, 0, parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), + initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, 0, 0, + parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), parameters->GetMaxVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), &randomNumberGenerator); initialDirection->Randomize(-DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, 1, 2, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; case 3: - initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, parameters->GetYDim(), parameters->GetYDim(), parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), + initialPosition->Randomize(initialRadius, parameters->GetXDim() - initialRadius, parameters->GetYDim() - 1, parameters->GetYDim() - 1, + parameters->GetMinVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), parameters->GetMaxVesselZOrigin() / parameters->GetVoxelSpacingInCentimeters(), &randomNumberGenerator); initialDirection->Randomize(-DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, -2, -1, -DIRECTION_VECTOR_INITIAL_VARIANCE, DIRECTION_VECTOR_INITIAL_VARIANCE, &randomNumberGenerator); break; } + initialDirection->Normalize(); + MITK_INFO << initialPosition->GetElement(0) << " | " << initialPosition->GetElement(1) << " | " << initialPosition->GetElement(2); + MITK_INFO << initialDirection->GetElement(0) << " | " << initialDirection->GetElement(1) << " | " << initialDirection->GetElement(2); + VesselProperties::Pointer vesselParams = VesselProperties::New(); vesselParams->SetDirectionVector(initialDirection); vesselParams->SetPositionVector(initialPosition); vesselParams->SetRadiusInVoxel(initialRadius); vesselParams->SetAbsorptionCoefficient(absorptionCoefficient); vesselParams->SetScatteringCoefficient(vesselScattering); vesselParams->SetAnisotopyCoefficient(vesselAnisotropy); vesselParams->SetBifurcationFrequency(parameters->GetVesselBifurcationFrequency()); + vesselParams->SetDoPartialVolume(parameters->GetDoPartialVolume()); VesselTree::Pointer vesselTree = VesselTree::New(vesselParams); while (!vesselTree->IsFinished()) { vesselTree->Step(generatedVolume, parameters->GetCalculateNewVesselPositionCallback(), bendingFactor, &randomNumberGenerator); } } - mitk::pa::VolumeManipulator::GaussianBlur3D(generatedVolume->GetAbsorptionVolume(), parameters->GetVolumeSmoothingSigma()); - mitk::pa::VolumeManipulator::GaussianBlur3D(generatedVolume->GetScatteringVolume(), parameters->GetVolumeSmoothingSigma()); - mitk::pa::VolumeManipulator::GaussianBlur3D(generatedVolume->GetAnisotropyVolume(), parameters->GetVolumeSmoothingSigma()); + if (parameters->GetDoPartialVolume()) + { + VolumeManipulator::RescaleImage(generatedVolume, (1.0 / RESAMPLING_FACTOR)); + parameters->SetXDim(parameters->GetXDim() / RESAMPLING_FACTOR); + parameters->SetYDim(parameters->GetYDim() / RESAMPLING_FACTOR); + parameters->SetZDim(parameters->GetZDim() / RESAMPLING_FACTOR); + parameters->SetVesselBifurcationFrequency(parameters->GetVesselBifurcationFrequency() / RESAMPLING_FACTOR); + parameters->SetVoxelSpacingInCentimeters(parameters->GetVoxelSpacingInCentimeters() * RESAMPLING_FACTOR); + } generatedVolume->FinalizeVolume(); return generatedVolume; } mitk::pa::InSilicoTissueGenerator::InSilicoTissueGenerator() { } mitk::pa::InSilicoTissueGenerator::~InSilicoTissueGenerator() { } diff --git a/Modules/PhotoacousticsLib/src/IO/mitkPAIOUtil.cpp b/Modules/PhotoacousticsLib/src/IO/mitkPAIOUtil.cpp index 3da84124e7..06f2f84d8b 100644 --- a/Modules/PhotoacousticsLib/src/IO/mitkPAIOUtil.cpp +++ b/Modules/PhotoacousticsLib/src/IO/mitkPAIOUtil.cpp @@ -1,258 +1,240 @@ #include "mitkPAIOUtil.h" #include "mitkIOUtil.h" #include "mitkImageReadAccessor.h" #include #include #include #include "mitkPAComposedVolume.h" #include "mitkPASlicedVolumeGenerator.h" #include "mitkPANoiseGenerator.h" #include "mitkPAVolumeManipulator.h" #include #include #include static std::vector splitString(const std::string &s, const char* delim) { std::vector elems; std::stringstream ss(s); std::string item; while (std::getline(ss, item, *delim)) { int numb; std::stringstream(item) >> numb; elems.push_back(numb); } return elems; } bool mitk::pa::IOUtil::DoesFileHaveEnding(std::string const &fullString, std::string const &ending) { if (fullString.length() == 0 || ending.length() == 0 || fullString.length() < ending.length()) return false; return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); } mitk::pa::IOUtil::IOUtil() {} mitk::pa::IOUtil::~IOUtil() {} mitk::pa::Volume::Pointer mitk::pa::IOUtil::LoadNrrd(std::string filename, double blur) { if (filename.empty() || filename == "") return nullptr; - auto inputImage = mitk::IOUtil::Load(filename); + mitk::Image::Pointer inputImage = mitk::IOUtil::Load(filename); if (inputImage.IsNull()) return nullptr; - int xDim = inputImage->GetDimensions()[1]; - int yDim = inputImage->GetDimensions()[0]; - int zDim = inputImage->GetDimensions()[2]; + auto returnImage = Volume::New(inputImage); - mitk::ImageReadAccessor readAccess(inputImage, inputImage->GetVolumeData(0)); - - auto* dataArray = new double[xDim*yDim*zDim]; - const auto* srcData = (const double*)readAccess.GetData(); - memcpy(dataArray, srcData, xDim*yDim*zDim * sizeof(double)); - - auto returnImage = mitk::pa::Volume::New(dataArray, xDim, yDim, zDim); - - mitk::pa::VolumeManipulator::GaussianBlur3D(returnImage, blur); + VolumeManipulator::GaussianBlur3D(returnImage, blur); return returnImage; } std::map mitk::pa::IOUtil::LoadFluenceContributionMaps(std::string foldername, double blur, int* progress, bool doLog10) { std::map resultMap; itk::Directory::Pointer directoryHandler = itk::Directory::New(); directoryHandler->Load(foldername.c_str()); for (unsigned int fileIndex = 0, numFiles = directoryHandler->GetNumberOfFiles(); fileIndex < numFiles; ++fileIndex) { std::string filename = std::string(directoryHandler->GetFile(fileIndex)); if (itksys::SystemTools::FileIsDirectory(filename)) continue; if (!DoesFileHaveEnding(filename, ".nrrd")) continue; size_t s = filename.find("_p"); size_t e = filename.find("Fluence", s); std::string sub = filename.substr(s + 2, e - s - 2); std::vector coords = splitString(sub, ","); if (coords.size() != 3) { MITK_ERROR << "Some of the data to read was corrupted or did not match the " << "naming pattern *_pN,N,NFluence*.nrrd"; mitkThrow() << "Some of the data to read was corrupted or did not match the" << " naming pattern *_pN,N,NFluence*.nrrd"; } else { MITK_DEBUG << "Extracted coords: " << coords[0] << "|" << coords[1] << "|" << coords[2] << " from string " << sub; Volume::Pointer nrrdFile = LoadNrrd(foldername + filename, blur); if (doLog10) VolumeManipulator::Log10Image(nrrdFile); resultMap[Position{ coords[0], coords[2] }] = nrrdFile; *progress = *progress + 1; } } return resultMap; } int mitk::pa::IOUtil::GetNumberOfNrrdFilesInDirectory(std::string directory) { return GetListOfAllNrrdFilesInDirectory(directory).size(); } std::vector mitk::pa::IOUtil::GetListOfAllNrrdFilesInDirectory(std::string directory, bool keepFileFormat) { std::vector filenames; itk::Directory::Pointer directoryHandler = itk::Directory::New(); directoryHandler->Load(directory.c_str()); for (unsigned int fileIndex = 0, numFiles = directoryHandler->GetNumberOfFiles(); fileIndex < numFiles; ++fileIndex) { std::string filename = std::string(directoryHandler->GetFile(fileIndex)); if (itksys::SystemTools::FileIsDirectory(filename)) continue; if (!DoesFileHaveEnding(filename, ".nrrd")) continue; if (keepFileFormat) { filenames.push_back(filename); } else { filenames.push_back(filename.substr(0, filename.size() - 5)); } } return filenames; } std::vector mitk::pa::IOUtil::GetAllChildfoldersFromFolder(std::string folderPath) { std::vector returnVector; itksys::Directory directoryHandler; directoryHandler.Load(folderPath.c_str()); for (unsigned int fileIndex = 0, numFiles = directoryHandler.GetNumberOfFiles(); fileIndex < numFiles; ++fileIndex) { std::string foldername = std::string(directoryHandler.GetFile(fileIndex)); std::string filename = folderPath + "/" + foldername; if (itksys::SystemTools::FileIsDirectory(filename)) { if (foldername != std::string(".") && foldername != std::string("..")) { MITK_INFO << filename; returnVector.push_back(filename); } continue; } //If there is a nrrd file in the directory we assume that a bottom level directory was chosen. if (DoesFileHaveEnding(filename, ".nrrd")) { returnVector.clear(); returnVector.push_back(folderPath); return returnVector; } } return returnVector; } mitk::pa::InSilicoTissueVolume::Pointer mitk::pa::IOUtil::LoadInSilicoTissueVolumeFromNrrdFile(std::string nrrdFile) { MITK_INFO << "Initializing ComposedVolume by nrrd..."; auto inputImage = mitk::IOUtil::Load(nrrdFile); auto tissueParameters = TissueGeneratorParameters::New(); unsigned int xDim = inputImage->GetDimensions()[1]; unsigned int yDim = inputImage->GetDimensions()[0]; unsigned int zDim = inputImage->GetDimensions()[2]; tissueParameters->SetXDim(xDim); tissueParameters->SetYDim(yDim); tissueParameters->SetZDim(zDim); double xSpacing = inputImage->GetGeometry(0)->GetSpacing()[1]; double ySpacing = inputImage->GetGeometry(0)->GetSpacing()[0]; double zSpacing = inputImage->GetGeometry(0)->GetSpacing()[2]; if ((xSpacing - ySpacing) > mitk::eps || (xSpacing - zSpacing) > mitk::eps || (ySpacing - zSpacing) > mitk::eps) { throw mitk::Exception("Cannot handle unequal spacing."); } tissueParameters->SetVoxelSpacingInCentimeters(xSpacing); mitk::PropertyList::Pointer propertyList = inputImage->GetPropertyList(); mitk::ImageReadAccessor readAccess0(inputImage, inputImage->GetVolumeData(0)); auto* m_AbsorptionArray = new double[xDim*yDim*zDim]; memcpy(m_AbsorptionArray, readAccess0.GetData(), xDim*yDim*zDim * sizeof(double)); - auto absorptionVolume = Volume::New(m_AbsorptionArray, xDim, yDim, zDim); + auto absorptionVolume = Volume::New(m_AbsorptionArray, xDim, yDim, zDim, xSpacing); mitk::ImageReadAccessor readAccess1(inputImage, inputImage->GetVolumeData(1)); auto* m_ScatteringArray = new double[xDim*yDim*zDim]; memcpy(m_ScatteringArray, readAccess1.GetData(), xDim*yDim*zDim * sizeof(double)); - auto scatteringVolume = Volume::New(m_ScatteringArray, xDim, yDim, zDim); + auto scatteringVolume = Volume::New(m_ScatteringArray, xDim, yDim, zDim, xSpacing); mitk::ImageReadAccessor readAccess2(inputImage, inputImage->GetVolumeData(2)); auto* m_AnisotropyArray = new double[xDim*yDim*zDim]; memcpy(m_AnisotropyArray, readAccess2.GetData(), xDim*yDim*zDim * sizeof(double)); - auto anisotropyVolume = Volume::New(m_AnisotropyArray, xDim, yDim, zDim); + auto anisotropyVolume = Volume::New(m_AnisotropyArray, xDim, yDim, zDim, xSpacing); Volume::Pointer segmentationVolume; if (inputImage->GetDimension() == 4) { mitk::ImageReadAccessor readAccess3(inputImage, inputImage->GetVolumeData(3)); auto* m_SegmentationArray = new double[xDim*yDim*zDim]; memcpy(m_SegmentationArray, readAccess3.GetData(), xDim*yDim*zDim * sizeof(double)); - segmentationVolume = Volume::New(m_SegmentationArray, xDim, yDim, zDim); + segmentationVolume = Volume::New(m_SegmentationArray, xDim, yDim, zDim, xSpacing); } return mitk::pa::InSilicoTissueVolume::New(absorptionVolume, scatteringVolume, anisotropyVolume, segmentationVolume, tissueParameters, propertyList); } mitk::pa::FluenceYOffsetPair::Pointer mitk::pa::IOUtil::LoadFluenceSimulation(std::string fluenceSimulation) { MITK_INFO << "Adding slice..."; - auto inputImage = mitk::IOUtil::Load(fluenceSimulation); - mitk::ImageReadAccessor readAccess0(inputImage, inputImage->GetVolumeData(0)); - - unsigned int xDim = inputImage->GetDimensions()[1]; - unsigned int yDim = inputImage->GetDimensions()[0]; - unsigned int zDim = inputImage->GetDimensions()[2]; - int size = xDim*yDim*zDim; - auto* fluenceArray = new double[size]; - memcpy(fluenceArray, readAccess0.GetData(), size * sizeof(double)); + mitk::Image::Pointer inputImage = mitk::IOUtil::Load(fluenceSimulation); auto yOffsetProperty = inputImage->GetProperty("y-offset"); if (yOffsetProperty.IsNull()) mitkThrow() << "No \"y-offset\" property found in fluence file!"; std::string yOff = yOffsetProperty->GetValueAsString(); MITK_INFO << "Reading y Offset: " << yOff; #ifdef __linux__ std::replace(yOff.begin(), yOff.end(), '.', ','); #endif // __linux__ double yOffset = std::stod(yOff); MITK_INFO << "Converted offset " << yOffset; - return mitk::pa::FluenceYOffsetPair::New(mitk::pa::Volume::New(fluenceArray, xDim, yDim, zDim), yOffset); + return FluenceYOffsetPair::New(Volume::New(inputImage), yOffset); } diff --git a/Modules/PhotoacousticsLib/src/Utils/mitkPATissueGeneratorParameters.cpp b/Modules/PhotoacousticsLib/src/Utils/mitkPATissueGeneratorParameters.cpp index d6e1637a34..bcbeed0f2f 100644 --- a/Modules/PhotoacousticsLib/src/Utils/mitkPATissueGeneratorParameters.cpp +++ b/Modules/PhotoacousticsLib/src/Utils/mitkPATissueGeneratorParameters.cpp @@ -1,79 +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 "mitkPATissueGeneratorParameters.h" mitk::pa::TissueGeneratorParameters::TissueGeneratorParameters() { m_XDim = 50; m_YDim = 50; m_ZDim = 50; m_VoxelSpacingInCentimeters = 1; - m_VolumeSmoothingSigma = 0; - m_DoVolumeSmoothing = false; + m_DoPartialVolume = false; m_UseRngSeed = false; m_RngSeed = 1337L; m_RandomizePhysicalProperties = false; m_RandomizePhysicalPropertiesPercentage = 0; + m_ForceVesselsMoveAlongYDirection = false; - m_BackgroundAbsorption = 0.1; + m_MinBackgroundAbsorption = 0.1; + m_MaxBackgroundAbsorption = 0.1; m_BackgroundScattering = 15; m_BackgroundAnisotropy = 0.9; m_AirAbsorption = 0.0001; m_AirScattering = 1; m_AirAnisotropy = 1; m_AirThicknessInMillimeters = 0; m_SkinAbsorption = 0.1; m_SkinScattering = 15; m_SkinAnisotropy = 0.9; m_SkinThicknessInMillimeters = 0; m_CalculateNewVesselPositionCallback = &VesselMeanderStrategy::CalculateRandomlyDivergingPosition; m_MinNumberOfVessels = 0; m_MaxNumberOfVessels = 0; m_MinVesselBending = 0; m_MaxVesselBending = 0.1; m_MinVesselAbsorption = 1; m_MaxVesselAbsorption = 8; m_MinVesselRadiusInMillimeters = 1; m_MaxVesselRadiusInMillimeters = 3; m_VesselBifurcationFrequency = 25; m_MinVesselScattering = 15; m_MaxVesselScattering = 15; m_MinVesselAnisotropy = 0.9; m_MaxVesselAnisotropy = 0.9; m_MinVesselZOrigin = 10; m_MaxVesselZOrigin = 40; m_MCflag = 1; m_MCLaunchflag = 0; m_MCBoundaryflag = 2; m_MCLaunchPointX = 25; m_MCLaunchPointY = 25; m_MCLaunchPointZ = 2; m_MCFocusPointX = 25; m_MCFocusPointY = 25; m_MCFocusPointZ = 25; m_MCTrajectoryVectorX = 0; m_MCTrajectoryVectorY = 0; m_MCTrajectoryVectorZ = 1; m_MCRadius = 2; m_MCWaist = 4; } mitk::pa::TissueGeneratorParameters::~TissueGeneratorParameters() { } diff --git a/Modules/PhotoacousticsLib/src/Utils/mitkPAVector.cpp b/Modules/PhotoacousticsLib/src/Utils/mitkPAVector.cpp index e621671c53..4c15f75064 100644 --- a/Modules/PhotoacousticsLib/src/Utils/mitkPAVector.cpp +++ b/Modules/PhotoacousticsLib/src/Utils/mitkPAVector.cpp @@ -1,168 +1,182 @@ /*=================================================================== 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 "mitkPAVector.h" #include "chrono" #include mitk::pa::Vector::Vector() { m_Vector.Fill(0); } mitk::pa::Vector::~Vector() { m_Vector.Fill(0); } double mitk::pa::Vector::GetNorm() { return m_Vector.GetNorm(); } double mitk::pa::Vector::GetElement(unsigned short index) { return m_Vector.GetElement(index); } void mitk::pa::Vector::SetElement(unsigned short index, double value) { m_Vector.SetElement(index, value); } void mitk::pa::Vector::Normalize() { double norm = m_Vector.GetNorm(); m_Vector.SetElement(0, m_Vector.GetElement(0) / norm); m_Vector.SetElement(1, m_Vector.GetElement(1) / norm); m_Vector.SetElement(2, m_Vector.GetElement(2) / norm); } void mitk::pa::Vector::SetValue(mitk::pa::Vector::Pointer value) { m_Vector.SetElement(0, value->GetElement(0)); m_Vector.SetElement(1, value->GetElement(1)); m_Vector.SetElement(2, value->GetElement(2)); } void mitk::pa::Vector::RandomizeByPercentage(double percentage, double bendingFactor, std::mt19937* rng) { std::uniform_real_distribution<> range(-percentage, percentage); m_Vector.SetElement(0, m_Vector.GetElement(0) + (bendingFactor * range(*rng))); m_Vector.SetElement(1, m_Vector.GetElement(1) + (bendingFactor * range(*rng))); m_Vector.SetElement(2, m_Vector.GetElement(2) + (bendingFactor * range(*rng))); } void mitk::pa::Vector::Randomize(double xLowerLimit, double xUpperLimit, double yLowerLimit, double yUpperLimit, double zLowerLimit, double zUpperLimit, std::mt19937* rng) { std::uniform_real_distribution<> rangeX(xLowerLimit, xUpperLimit); std::uniform_real_distribution<> rangeY(yLowerLimit, yUpperLimit); std::uniform_real_distribution<> rangeZ(zLowerLimit, zUpperLimit); m_Vector.SetElement(0, rangeX(*rng)); m_Vector.SetElement(1, rangeY(*rng)); m_Vector.SetElement(2, rangeZ(*rng)); } void mitk::pa::Vector::Randomize(double xLimit, double yLimit, double zLimit, std::mt19937* rng) { Randomize(0, xLimit, 0, yLimit, 0, zLimit, rng); } void mitk::pa::Vector::Randomize(std::mt19937* rng) { Randomize(-1, 1, -1, 1, -1, 1, rng); } void mitk::pa::Vector::PrintSelf(std::ostream& os, itk::Indent /*indent*/) const { os << "X: " << m_Vector.GetElement(0) << std::endl; os << "Y: " << m_Vector.GetElement(1) << std::endl; os << "Z: " << m_Vector.GetElement(2) << std::endl; os << "Length: " << m_Vector.GetNorm() << std::endl; } void mitk::pa::Vector::Rotate(double thetaChange, double phiChange) { MITK_DEBUG << "Vector before rotation: (" << GetElement(0) << "|" << GetElement(1) << "|" << GetElement(2) << ")"; if (thetaChange == 0 && phiChange == 0) return; double x = GetElement(0); double y = GetElement(1); double z = GetElement(2); double r = sqrt(x*x + y*y + z*z); if (r == 0) return; double theta = acos(z / r); double phi = atan2(y, x); theta += thetaChange; phi += phiChange; SetElement(0, r * sin(theta) * cos(phi)); SetElement(1, r * sin(theta) * sin(phi)); SetElement(2, r * cos(theta)); MITK_DEBUG << "Vector after rotation: (" << GetElement(0) << "|" << GetElement(1) << "|" << GetElement(2) << ")"; } void mitk::pa::Vector::Scale(double factor) { m_Vector.SetElement(0, m_Vector.GetElement(0)*factor); m_Vector.SetElement(1, m_Vector.GetElement(1)*factor); m_Vector.SetElement(2, m_Vector.GetElement(2)*factor); } mitk::pa::Vector::Pointer mitk::pa::Vector::Clone() { auto returnVector = Vector::New(); returnVector->SetElement(0, this->GetElement(0)); returnVector->SetElement(1, this->GetElement(1)); returnVector->SetElement(2, this->GetElement(2)); return returnVector; } +void mitk::pa::Vector::Subtract(Vector::Pointer other) +{ + m_Vector.SetElement(0, m_Vector.GetElement(0) - other->GetElement(0)); + m_Vector.SetElement(1, m_Vector.GetElement(1) - other->GetElement(1)); + m_Vector.SetElement(2, m_Vector.GetElement(2) - other->GetElement(2)); +} + +void mitk::pa::Vector::Add(Vector::Pointer other) +{ + m_Vector.SetElement(0, m_Vector.GetElement(0) + other->GetElement(0)); + m_Vector.SetElement(1, m_Vector.GetElement(1) + other->GetElement(1)); + m_Vector.SetElement(2, m_Vector.GetElement(2) + other->GetElement(2)); +} + bool mitk::pa::Equal(const Vector::Pointer leftHandSide, const Vector::Pointer rightHandSide, double eps, bool verbose) { MITK_INFO(verbose) << "=== mitk::pa::Vector Equal ==="; if (rightHandSide.IsNull() || leftHandSide.IsNull()) { MITK_INFO(verbose) << "Cannot compare nullpointers"; return false; } if (leftHandSide->GetElement(0) - rightHandSide->GetElement(0) > eps) { MITK_INFO(verbose) << "Element[0] not equal"; return false; } if (leftHandSide->GetElement(1) - rightHandSide->GetElement(1) > eps) { MITK_INFO(verbose) << "Element[1] not equal"; return false; } if (leftHandSide->GetElement(2) - rightHandSide->GetElement(2) > eps) { MITK_INFO(verbose) << "Element[2] not equal"; return false; } return true; } diff --git a/Modules/PhotoacousticsLib/src/Utils/mitkPAVesselDrawer.cpp b/Modules/PhotoacousticsLib/src/Utils/mitkPAVesselDrawer.cpp new file mode 100644 index 0000000000..2f9b266fa0 --- /dev/null +++ b/Modules/PhotoacousticsLib/src/Utils/mitkPAVesselDrawer.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +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 "mitkPAVesselDrawer.h" +#include "mitkPAVesselProperties.h" + +mitk::pa::VesselDrawer::VesselDrawer() +{ +} + +mitk::pa::VesselDrawer::~VesselDrawer() +{ +} + +void mitk::pa::VesselDrawer::DrawVesselInVolume( + VesselProperties::Pointer properties, + InSilicoTissueVolume::Pointer volume) +{ + Vector::Pointer stepDirection = properties->GetDirectionVector(); + Vector::Pointer fromPosition = properties->GetPositionVector()->Clone(); + + Vector::Pointer toPosition = properties->GetPositionVector()->Clone(); + Vector::Pointer totalWalkingDistance = stepDirection->Clone(); + totalWalkingDistance->Scale(1.0 / volume->GetSpacing()); + + while (totalWalkingDistance->GetNorm() >= 1) + { + double xPos = fromPosition->GetElement(0); + double yPos = fromPosition->GetElement(1); + double zPos = fromPosition->GetElement(2); + + if (!volume->IsInsideVolume(xPos, yPos, zPos)) + { + properties->SetRadiusInVoxel(0); + return; + } + + double radius = properties->GetRadiusInVoxel(); + double ceiledRadius = ceil(radius); + + for (int x = xPos - ceiledRadius; x <= xPos + ceiledRadius; x += 1) + for (int y = yPos - ceiledRadius; y <= yPos + ceiledRadius; y += 1) + for (int z = zPos - ceiledRadius; z <= zPos + ceiledRadius; z += 1) + { + if (!volume->IsInsideVolume(x, y, z)) + { + continue; + } + double xDiff = x - xPos; + double yDiff = y - yPos; + double zDiff = z - zPos; + double vectorLengthDiff = radius - sqrt(xDiff*xDiff + yDiff*yDiff + zDiff*zDiff); + + if (vectorLengthDiff > 0) + { + volume->SetVolumeValues(x, y, z, + properties->GetAbsorptionCoefficient(), + properties->GetScatteringCoefficient(), + properties->GetAnisotopyCoefficient(), + mitk::pa::InSilicoTissueVolume::SegmentationType::VESSEL); + } + } + + totalWalkingDistance->Subtract(stepDirection); + fromPosition->Add(stepDirection); + } + + properties->SetPositionVector(fromPosition); +} diff --git a/Modules/PhotoacousticsLib/src/Utils/mitkPAVolumeManipulator.cpp b/Modules/PhotoacousticsLib/src/Utils/mitkPAVolumeManipulator.cpp index aa99d1f5f3..c5f728505e 100644 --- a/Modules/PhotoacousticsLib/src/Utils/mitkPAVolumeManipulator.cpp +++ b/Modules/PhotoacousticsLib/src/Utils/mitkPAVolumeManipulator.cpp @@ -1,177 +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 "mitkPAVolumeManipulator.h" #include "mitkPAExceptions.h" +#include "mitkPAInSilicoTissueVolume.h" +#include "itkResampleImageFilter.h" +#include "itkGaussianInterpolateImageFunction.h" + +// Includes for image casting between ITK and MITK +#include +#include + +#include mitk::pa::VolumeManipulator::VolumeManipulator() {} mitk::pa::VolumeManipulator::~VolumeManipulator() {} -void mitk::pa::VolumeManipulator::ThresholdImage(mitk::pa::Volume::Pointer image, double threshold) +void mitk::pa::VolumeManipulator::ThresholdImage(Volume::Pointer image, double threshold) { for (unsigned int z = 0; z < image->GetZDim(); z++) for (unsigned int y = 0; y < image->GetYDim(); y++) for (unsigned int x = 0; x < image->GetXDim(); x++) if (image->GetData(x, y, z) > threshold) image->SetData(1, x, y, z); else image->SetData(0, x, y, z); } -void mitk::pa::VolumeManipulator::MultiplyImage(mitk::pa::Volume::Pointer image, double factor) +void mitk::pa::VolumeManipulator::MultiplyImage(Volume::Pointer image, double factor) { for (unsigned int z = 0; z < image->GetZDim(); z++) for (unsigned int y = 0; y < image->GetYDim(); y++) for (unsigned int x = 0; x < image->GetXDim(); x++) image->SetData(image->GetData(x, y, z)*factor, x, y, z); } -void mitk::pa::VolumeManipulator::Log10Image(mitk::pa::Volume::Pointer image) +void mitk::pa::VolumeManipulator::Log10Image(Volume::Pointer image) { for (unsigned int z = 0; z < image->GetZDim(); z++) for (unsigned int y = 0; y < image->GetYDim(); y++) for (unsigned int x = 0; x < image->GetXDim(); x++) { if (image->GetData(x, y, z) < 0) { MITK_ERROR << "Signal was smaller than 0. There is an error in the input image file."; - throw mitk::pa::InvalidValueException("Signal was smaller than 0. There is an error in the input image file."); + throw InvalidValueException("Signal was smaller than 0. There is an error in the input image file."); } image->SetData(log10(image->GetData(x, y, z)), x, y, z); } } +void mitk::pa::VolumeManipulator::RescaleImage(InSilicoTissueVolume::Pointer image, double ratio) +{ + MITK_INFO << "Rescaling images.."; + double sigma = image->GetSpacing() / (ratio * 2); + image->SetAbsorptionVolume(RescaleImage(image->GetAbsorptionVolume(), ratio, sigma)); + image->SetScatteringVolume(RescaleImage(image->GetScatteringVolume(), ratio, sigma)); + image->SetAnisotropyVolume(RescaleImage(image->GetAnisotropyVolume(), ratio, sigma)); + image->SetSegmentationVolume(RescaleImage(image->GetSegmentationVolume(), ratio, 0)); + MITK_INFO << "Rescaling images..[Done]"; +} + +mitk::pa::Volume::Pointer mitk::pa::VolumeManipulator::RescaleImage(Volume::Pointer image, double ratio, double sigma) +{ + MITK_INFO << "Rescaling image.."; + typedef itk::Image ImageType; + typedef itk::ResampleImageFilter FilterType; + typedef itk::GaussianInterpolateImageFunction InterpolatorType; + + auto input = image->AsMitkImage(); + ImageType::Pointer itkInput = ImageType::New(); + mitk::CastToItkImage(input, itkInput); + + ImageType::SizeType outputSize; + outputSize[0] = input->GetDimensions()[0] * ratio; + outputSize[1] = input->GetDimensions()[1] * ratio; + outputSize[2] = input->GetDimensions()[2] * ratio; + + FilterType::Pointer resampleImageFilter = FilterType::New(); + resampleImageFilter->SetInput(itkInput); + resampleImageFilter->SetSize(outputSize); + if (sigma > mitk::eps) + { + auto interpolator = InterpolatorType::New(); + interpolator->SetSigma(sigma); + resampleImageFilter->SetInterpolator(interpolator); + } + resampleImageFilter->SetOutputSpacing(input->GetGeometry()->GetSpacing()[0] / ratio); + + MITK_INFO << "Update.."; + resampleImageFilter->UpdateLargestPossibleRegion(); + MITK_INFO << "Update..[Done]"; + + ImageType::Pointer output = resampleImageFilter->GetOutput(); + mitk::Image::Pointer mitkOutput = mitk::Image::New(); + + GrabItkImageMemory(output, mitkOutput); + MITK_INFO << "Rescaling image..[Done]"; + return Volume::New(mitkOutput); +} + /** * @brief Fast 3D Gaussian convolution IIR approximation * @param paVolume * @param sigma * @author Pascal Getreuer * * Copyright (c) 2011, Pascal Getreuer * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the simplified BSD license. * * You should have received a copy of these licenses along with this program. * If not, see . */ void mitk::pa::VolumeManipulator::GaussianBlur3D(mitk::pa::Volume::Pointer paVolume, double sigma) { double* volume = paVolume->GetData(); long width = paVolume->GetYDim(); long height = paVolume->GetXDim(); long depth = paVolume->GetZDim(); const long plane = width*height; const long numel = plane*depth; double lambda, dnu; double nu, boundaryscale, postscale; double *ptr; long i, x, y, z; int step; if (sigma <= 0) return; lambda = (sigma*sigma) / (8.0); dnu = (1.0 + 2.0*lambda - sqrt(1.0 + 4.0*lambda)) / (2.0*lambda); nu = dnu; boundaryscale = 1.0 / (1.0 - dnu); postscale = pow(dnu / lambda, 12); /* Filter horizontally along each row */ for (z = 0; z < depth; z++) { for (y = 0; y < height; y++) { for (step = 0; step < 4; step++) { ptr = volume + width*(y + height*z); ptr[0] *= boundaryscale; /* Filter rightwards */ for (x = 1; x < width; x++) { ptr[x] += nu*ptr[x - 1]; } ptr[x = width - 1] *= boundaryscale; /* Filter leftwards */ for (; x > 0; x--) { ptr[x - 1] += nu*ptr[x]; } } } } /* Filter vertically along each column */ for (z = 0; z < depth; z++) { for (x = 0; x < width; x++) { for (step = 0; step < 4; step++) { ptr = volume + x + plane*z; ptr[0] *= boundaryscale; /* Filter downwards */ for (i = width; i < plane; i += width) { ptr[i] += nu*ptr[i - width]; } ptr[i = plane - width] *= boundaryscale; /* Filter upwards */ for (; i > 0; i -= width) { ptr[i - width] += nu*ptr[i]; } } } } /* Filter along z-dimension */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { for (step = 0; step < 4; step++) { ptr = volume + x + width*y; ptr[0] *= boundaryscale; for (i = plane; i < numel; i += plane) { ptr[i] += nu*ptr[i - plane]; } ptr[i = numel - plane] *= boundaryscale; for (; i > 0; i -= plane) { ptr[i - plane] += nu*ptr[i]; } } } } for (i = 0; i < numel; i++) { volume[i] *= postscale; } } diff --git a/Modules/PhotoacousticsLib/test/files.cmake b/Modules/PhotoacousticsLib/test/files.cmake index ae1e015083..0796a506a5 100644 --- a/Modules/PhotoacousticsLib/test/files.cmake +++ b/Modules/PhotoacousticsLib/test/files.cmake @@ -1,40 +1,41 @@ set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## ON THE FENCE TESTS ################################################# # none ################## DISABLED TESTS ##################################################### ################# RUNNING TESTS ####################################################### mitkSlicedVolumeGeneratorTest.cpp mitkPhotoacousticTissueGeneratorTest.cpp mitkPhotoacousticVectorTest.cpp mitkPhotoacoustic3dVolumeTest.cpp mitkPhotoacousticVolumeTest.cpp mitkPhotoacousticVesselTest.cpp mitkPhotoacousticVesselTreeTest.cpp mitkPhotoacousticVesselMeanderStrategyTest.cpp mitkMcxyzXmlTest.cpp mitkPhotoacousticComposedVolumeTest.cpp mitkPhotoacousticNoiseGeneratorTest.cpp mitkPhotoacousticIOTest.cpp mitkMCThreadHandlerTest.cpp mitkSimulationBatchGeneratorTest.cpp mitkPropertyCalculatorTest.cpp + mitkPhotoacousticImageSavingTest.cpp ) set(RESOURCE_FILES pointsource.xml circlesource.xml rectanglesource.xml twopointsources.xml allsources.xml ) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacoustic3dVolumeTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacoustic3dVolumeTest.cpp index 215a43d350..8ee9bf73c7 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacoustic3dVolumeTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacoustic3dVolumeTest.cpp @@ -1,224 +1,224 @@ /*=================================================================== 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 "mitkPAVolume.h" #include #include class mitkPhotoacoustic3dVolumeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacoustic3dVolumeTestSuite); MITK_TEST(TestCorrectGetDataAndSetDataBehavior); MITK_TEST(TestCallingConstructorWithNullParameter); MITK_TEST(TestCallingConstructorWithCorrectParameters); MITK_TEST(TestModifyImage); MITK_TEST(TestModifyComplexImage); MITK_TEST(TestConvertToMitkImage); MITK_TEST(TestDeepCopy); MITK_TEST(TestCatchException); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::Volume::Pointer m_Photoacoustic3dVolume; public: void setUp() override { } void TestCallingConstructorWithNullParameter() { bool exceptionEncountered = false; try { - m_Photoacoustic3dVolume = mitk::pa::Volume::New(nullptr, 3, 3, 3); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(nullptr, 3, 3, 3, 1); } catch (...) { exceptionEncountered = true; } CPPUNIT_ASSERT(exceptionEncountered); } void TestCallingConstructorWithCorrectParameters() { auto* data = new double[1]; data[0] = 3; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1, 1); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetXDim() == 1); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetYDim() == 1); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetZDim() == 1); } void TestModifyImage() { auto* data = new double[1]; data[0] = 3; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1, 1); CPPUNIT_ASSERT_MESSAGE(std::to_string(m_Photoacoustic3dVolume->GetData(0, 0, 0)), m_Photoacoustic3dVolume->GetData(0, 0, 0) == 3); m_Photoacoustic3dVolume->SetData(17, 0, 0, 0); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 17); } void TestModifyComplexImage() { unsigned int xDim = 4; unsigned int yDim = 7; unsigned int zDim = 12; unsigned int length = xDim * yDim * zDim; auto* data = new double[length]; for (unsigned int i = 0; i < length; i++) data[i] = 5; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, xDim, yDim, zDim); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, xDim, yDim, zDim, 1); for (unsigned int z = 0; z < zDim; z++) for (unsigned int y = 0; y < yDim; y++) for (unsigned int x = 0; x < xDim; x++) { CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(x, y, z) == 5); m_Photoacoustic3dVolume->SetData((x + y)*(z + 1), x, y, z); CPPUNIT_ASSERT(std::abs(m_Photoacoustic3dVolume->GetData(x, y, z) - (x + y)*(z + 1)) < mitk::eps); } } void TestCorrectGetDataAndSetDataBehavior() { unsigned int xDim = 40; unsigned int yDim = 7; unsigned int zDim = 12; unsigned int length = xDim * yDim * zDim; auto* data = new double[length]; for (unsigned int i = 0; i < length; i++) data[i] = 0; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, xDim, yDim, zDim); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, xDim, yDim, zDim, 1); for (unsigned int z = 0; z < zDim; z++) for (unsigned int y = 0; y < yDim; y++) for (unsigned int x = 0; x < xDim; x++) { int index = z*xDim*yDim + x*yDim + y; m_Photoacoustic3dVolume->SetData(index, x, y, z); CPPUNIT_ASSERT_MESSAGE(std::to_string(index), m_Photoacoustic3dVolume->GetData(x, y, z) == index); } } void TestConvertToMitkImage() { auto* data = new double[6]; data[0] = 3; data[1] = 3; data[2] = 3; data[3] = 3; data[4] = 3; data[5] = 3; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 2, 3); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 2, 3, 1); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 1) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 2) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 0) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 1) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 2) == 3); m_Photoacoustic3dVolume->SetData(17, 0, 0, 0); m_Photoacoustic3dVolume->SetData(17, 0, 1, 0); m_Photoacoustic3dVolume->SetData(17, 0, 1, 2); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 17); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 1) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 2) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 0) == 17); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 1) == 3); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 1, 2) == 17); mitk::Image::Pointer mitkImage = m_Photoacoustic3dVolume->AsMitkImage(); CPPUNIT_ASSERT(mitkImage->GetDimensions()[0] == 2); CPPUNIT_ASSERT(mitkImage->GetDimensions()[1] == 1); CPPUNIT_ASSERT(mitkImage->GetDimensions()[2] == 3); mitk::ImageReadAccessor readAccess(mitkImage, mitkImage->GetVolumeData()); auto* copyData = (double*)readAccess.GetData(); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[0]), copyData[0] == 17); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[1]), copyData[1] == 17); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[2]), copyData[2] == 3); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[3]), copyData[3] == 3); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[4]), copyData[4] == 3); CPPUNIT_ASSERT_MESSAGE(std::to_string(copyData[5]), copyData[5] == 17); } void TestDeepCopy() { auto* data = new double[1]; data[0] = 3; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1, 1); mitk::pa::Volume::Pointer copiedVolume = m_Photoacoustic3dVolume->DeepCopy(); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetXDim() == copiedVolume->GetXDim()); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetYDim() == copiedVolume->GetYDim()); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetZDim() == copiedVolume->GetZDim()); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 3); CPPUNIT_ASSERT(copiedVolume->GetData(0, 0, 0) == 3); m_Photoacoustic3dVolume->SetData(17, 0, 0, 0); CPPUNIT_ASSERT(m_Photoacoustic3dVolume->GetData(0, 0, 0) == 17); CPPUNIT_ASSERT(copiedVolume->GetData(0, 0, 0) == 3); } void AssertIndexException(unsigned int x, unsigned int y, unsigned int z) { bool exceptionCaught = false; try { double thisIsIrrelevant = m_Photoacoustic3dVolume->GetData(x, y, z); thisIsIrrelevant += 1; } catch (...) { exceptionCaught = true; if (exceptionCaught) exceptionCaught = true; } #ifdef _DEBUG CPPUNIT_ASSERT(exceptionCaught); #endif - } + } void TestCatchException() { auto* data = new double[1]; data[0] = 3; - m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1); + m_Photoacoustic3dVolume = mitk::pa::Volume::New(data, 1, 1, 1, 1); AssertIndexException(1, 0, 0); AssertIndexException(0, 1, 0); AssertIndexException(0, 0, 1); AssertIndexException(18, 1, 222); } void tearDown() override { m_Photoacoustic3dVolume = nullptr; } - }; +}; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacoustic3dVolume) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp index 65cc609884..b2aa4015eb 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticComposedVolumeTest.cpp @@ -1,148 +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 "mitkPAComposedVolume.h" #include "mitkIOUtil.h" #include "mitkImageReadAccessor.h" #include class mitkPhotoacousticComposedVolumeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticComposedVolumeTestSuite); MITK_TEST(TestCreateAndDestructComposedVolume); MITK_TEST(TestAccessInvalidFluenceComponent); MITK_TEST(TestAccessInvalidFluenceComponentIndex); MITK_TEST(TestAddMultiplePairs); MITK_TEST(TestSortFunctionality); MITK_TEST(TestAccessInvalidFluenceComponentForYOffset); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::ComposedVolume::Pointer m_ComposedVolume; mitk::pa::TissueGeneratorParameters::Pointer m_DefaultParameters; mitk::pa::InSilicoTissueVolume::Pointer m_InSilicoTissueVolume; public: void setUp() override { m_DefaultParameters = mitk::pa::TissueGeneratorParameters::New(); m_DefaultParameters->SetXDim(5); m_DefaultParameters->SetYDim(5); m_DefaultParameters->SetZDim(5); - m_InSilicoTissueVolume = mitk::pa::InSilicoTissueVolume::New(m_DefaultParameters); + auto rng = std::mt19937(); + m_InSilicoTissueVolume = mitk::pa::InSilicoTissueVolume::New(m_DefaultParameters, &rng); m_ComposedVolume = mitk::pa::ComposedVolume::New(m_InSilicoTissueVolume); } mitk::pa::FluenceYOffsetPair::Pointer createFluenceYOffsetPair(double value, double yOffset) { auto* data = new double[125]; for (int i = 0; i < 125; ++i) data[i] = value; - mitk::pa::Volume::Pointer volume = mitk::pa::Volume::New(data, 5, 5, 5); + mitk::pa::Volume::Pointer volume = mitk::pa::Volume::New(data, 5, 5, 5, 1); return mitk::pa::FluenceYOffsetPair::New(volume, yOffset); } void TestCreateAndDestructComposedVolume() { CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 0); } void TestAccessInvalidFluenceComponent() { bool caughtException = false; try { m_ComposedVolume->GetFluenceValue(0, 0, 0, 0); } catch (mitk::Exception e) { caughtException = true; } CPPUNIT_ASSERT(caughtException); } void TestAddMultiplePairs() { m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 1); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(1, 1)); CPPUNIT_ASSERT(m_ComposedVolume->GetNumberOfFluenceComponents() == 2); } void TestSortFunctionality() { m_ComposedVolume->AddSlice(createFluenceYOffsetPair(2, 2)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(-1, -1)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(1, 1)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); m_ComposedVolume->AddSlice(createFluenceYOffsetPair(-2, -2)); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(0, 0, 2, 0) == 2); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(1, 0, 2, 0) == -1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(2, 0, 2, 0) == 1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(3, 0, 2, 0) == 0); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(4, 0, 2, 0) == -2); m_ComposedVolume->Sort(); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(0, 0, 2, 0) == -2); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(1, 0, 2, 0) == -1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(2, 0, 2, 0) == 0); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(3, 0, 2, 0) == 1); CPPUNIT_ASSERT(m_ComposedVolume->GetFluenceValue(4, 0, 2, 0) == 2); } void TestAccessInvalidFluenceComponentIndex() { #ifdef _DEBUG m_ComposedVolume->AddSlice(createFluenceYOffsetPair(0, 0)); bool caughtException = false; try { double unusedValue = m_ComposedVolume->GetFluenceValue(0, 1, 2, 300); unusedValue = 0; } catch (mitk::Exception e) { caughtException = true; } CPPUNIT_ASSERT(caughtException); #endif } void TestAccessInvalidFluenceComponentForYOffset() { bool caughtException = false; try { m_ComposedVolume->GetYOffsetForFluenceComponentInPixels(0); } catch (mitk::Exception e) { caughtException = true; } CPPUNIT_ASSERT(caughtException); } void tearDown() override { m_ComposedVolume = nullptr; } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticComposedVolume) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticIOTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticIOTest.cpp index 50f7da00cc..ba66cf2099 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticIOTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticIOTest.cpp @@ -1,187 +1,189 @@ /*=================================================================== 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 class mitkPhotoacousticIOTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticIOTestSuite); MITK_TEST(testLoadInSilicoTissueNrrdFile); MITK_TEST(testLoad3DVolumeNrrdFile); MITK_TEST(testLoad3DVolumeNrrdFileWithBlur); MITK_TEST(testGetNumberOfNrrdFilesInTestDir); MITK_TEST(testGetChildFoldersFromFolder); MITK_TEST(testLoadFCMs); CPPUNIT_TEST_SUITE_END(); private: const std::string TEST_FOLDER_PATH = "testFiles/"; const std::string TEST_IN_SILICO_VOLUME_PATH = "testInSilicoVolume"; const std::string TEST_3D_Volume_PATH = "test3DVolume"; const std::string TEST_FILE_ENDING = ".nrrd"; const std::string TEST_QUALIFIED_FOLDER_PATH = TEST_FOLDER_PATH + TEST_IN_SILICO_VOLUME_PATH + "/"; const std::string FOLDER_FOLDER = "folder/"; const std::string FCM_PATH = TEST_FOLDER_PATH + "fcms/"; const int NUMBER_OF_NRRD_FILES_IN_TEST_DIR = 2; mitk::pa::TissueGeneratorParameters::Pointer m_VolumeProperties; mitk::pa::InSilicoTissueVolume::Pointer m_TestInSilicoVolume; mitk::pa::Volume::Pointer m_Test3DVolume; public: void setUp() override { m_VolumeProperties = createTestVolumeParameters(); - m_TestInSilicoVolume = mitk::pa::InSilicoTissueVolume::New(m_VolumeProperties); + auto rng = std::mt19937(); + m_TestInSilicoVolume = mitk::pa::InSilicoTissueVolume::New(m_VolumeProperties, &rng); m_Test3DVolume = createTest3DVolume(5); itk::FileTools::CreateDirectory(TEST_FOLDER_PATH); itk::FileTools::CreateDirectory(TEST_QUALIFIED_FOLDER_PATH); itk::FileTools::CreateDirectory(TEST_FOLDER_PATH + FOLDER_FOLDER + FOLDER_FOLDER); itk::FileTools::CreateDirectory(FCM_PATH); CPPUNIT_ASSERT(itksys::SystemTools::FileIsDirectory(TEST_FOLDER_PATH)); CPPUNIT_ASSERT(itksys::SystemTools::FileIsDirectory(TEST_QUALIFIED_FOLDER_PATH)); CPPUNIT_ASSERT(itksys::SystemTools::FileIsDirectory(TEST_FOLDER_PATH + FOLDER_FOLDER + FOLDER_FOLDER)); CPPUNIT_ASSERT(itksys::SystemTools::FileIsDirectory(FCM_PATH)); mitk::IOUtil::Save(m_TestInSilicoVolume->ConvertToMitkImage(), TEST_FOLDER_PATH + TEST_IN_SILICO_VOLUME_PATH + TEST_FILE_ENDING); mitk::IOUtil::Save(m_Test3DVolume->AsMitkImage(), TEST_FOLDER_PATH + TEST_3D_Volume_PATH + TEST_FILE_ENDING); auto yo0 = createTest3DVolume(1)->AsMitkImage(); auto yo1 = createTest3DVolume(2)->AsMitkImage(); yo0->GetPropertyList()->SetStringProperty("y-offset", "0"); yo1->GetPropertyList()->SetStringProperty("y-offset", "1"); mitk::CoreServices::GetPropertyPersistence()->AddInfo(mitk::PropertyPersistenceInfo::New("y-offset")); mitk::IOUtil::Save(yo0, TEST_QUALIFIED_FOLDER_PATH + TEST_IN_SILICO_VOLUME_PATH + "_yo0" + TEST_FILE_ENDING); mitk::IOUtil::Save(yo1, TEST_QUALIFIED_FOLDER_PATH + TEST_IN_SILICO_VOLUME_PATH + "_yo1" + TEST_FILE_ENDING); } mitk::pa::Volume::Pointer createTest3DVolume(double value) { unsigned int xDim = 10; unsigned int yDim = 10; unsigned int zDim = 10; unsigned int length = xDim * yDim * zDim; auto* data = new double[length]; for (unsigned int i = 0; i < length; i++) data[i] = value; - return mitk::pa::Volume::New(data, xDim, yDim, zDim); + return mitk::pa::Volume::New(data, xDim, yDim, zDim, 1); } mitk::pa::TissueGeneratorParameters::Pointer createTestVolumeParameters() { auto returnParameters = mitk::pa::TissueGeneratorParameters::New(); returnParameters->SetXDim(10); returnParameters->SetYDim(10); returnParameters->SetZDim(10); - returnParameters->SetBackgroundAbsorption(0); + returnParameters->SetMinBackgroundAbsorption(0); + returnParameters->SetMaxBackgroundAbsorption(0); returnParameters->SetBackgroundScattering(0); returnParameters->SetBackgroundAnisotropy(0); return returnParameters; } void assertEqual(mitk::pa::Volume::Pointer first, mitk::pa::Volume::Pointer second) { CPPUNIT_ASSERT(first->GetXDim() == second->GetXDim()); CPPUNIT_ASSERT(first->GetYDim() == second->GetYDim()); CPPUNIT_ASSERT(first->GetZDim() == second->GetZDim()); for (unsigned int x = 0; x < first->GetXDim(); ++x) for (unsigned int y = 0; y < first->GetYDim(); ++y) for (unsigned int z = 0; z < first->GetZDim(); ++z) { std::string message = "Expected " + std::to_string(first->GetData(x, y, z)) + " but was " + std::to_string(second->GetData(x, y, z)); CPPUNIT_ASSERT_MESSAGE(message, std::abs(first->GetData(x, y, z) - second->GetData(x, y, z)) < 1e-6); } } void testLoadInSilicoTissueNrrdFile() { auto loadedVolume = mitk::pa::IOUtil::LoadInSilicoTissueVolumeFromNrrdFile(TEST_FOLDER_PATH + TEST_IN_SILICO_VOLUME_PATH + TEST_FILE_ENDING); CPPUNIT_ASSERT(loadedVolume->GetTDim() == m_TestInSilicoVolume->GetTDim()); assertEqual(m_TestInSilicoVolume->GetAbsorptionVolume(), loadedVolume->GetAbsorptionVolume()); assertEqual(m_TestInSilicoVolume->GetScatteringVolume(), loadedVolume->GetScatteringVolume()); assertEqual(m_TestInSilicoVolume->GetAnisotropyVolume(), loadedVolume->GetAnisotropyVolume()); } void testLoad3DVolumeNrrdFile() { auto loadedVolume = mitk::pa::IOUtil::LoadNrrd(TEST_FOLDER_PATH + TEST_3D_Volume_PATH + TEST_FILE_ENDING); assertEqual(loadedVolume, m_Test3DVolume); } void testLoad3DVolumeNrrdFileWithBlur() { auto loadedVolume = mitk::pa::IOUtil::LoadNrrd(TEST_FOLDER_PATH + TEST_3D_Volume_PATH + TEST_FILE_ENDING, 1); assertEqual(loadedVolume, m_Test3DVolume); } void testGetNumberOfNrrdFilesInTestDir() { int numberOfFiles = mitk::pa::IOUtil::GetNumberOfNrrdFilesInDirectory(TEST_FOLDER_PATH); CPPUNIT_ASSERT(numberOfFiles == NUMBER_OF_NRRD_FILES_IN_TEST_DIR); } void testGetChildFoldersFromFolder() { std::vector childFolders = mitk::pa::IOUtil::GetAllChildfoldersFromFolder(TEST_FOLDER_PATH); CPPUNIT_ASSERT(childFolders.size() == 1); CPPUNIT_ASSERT(childFolders[0] == TEST_FOLDER_PATH); childFolders = mitk::pa::IOUtil::GetAllChildfoldersFromFolder(TEST_FOLDER_PATH + FOLDER_FOLDER); MITK_INFO << "ChildFolders: " << childFolders.size(); CPPUNIT_ASSERT(childFolders.size() == 1); CPPUNIT_ASSERT(childFolders[0] == TEST_FOLDER_PATH + FOLDER_FOLDER + "/folder"); } void testLoadFCMs() { auto fcm1 = createTest3DVolume(1); auto fcm2 = createTest3DVolume(2); auto fcm3 = createTest3DVolume(3); auto fcm4 = createTest3DVolume(4); mitk::IOUtil::Save(fcm1->AsMitkImage(), FCM_PATH + "fcm1_p0,0,0FluenceContributionMap.nrrd"); mitk::IOUtil::Save(fcm2->AsMitkImage(), FCM_PATH + "fcm1_p0,0,1FluenceContributionMap.nrrd"); mitk::IOUtil::Save(fcm3->AsMitkImage(), FCM_PATH + "fcm1_p1,0,0FluenceContributionMap.nrrd"); mitk::IOUtil::Save(fcm4->AsMitkImage(), FCM_PATH + "fcm1_p1,0,1FluenceContributionMap.nrrd"); int prog = 0; auto map = mitk::pa::IOUtil::LoadFluenceContributionMaps(FCM_PATH, 0, &prog); assertEqual(fcm1, map[mitk::pa::IOUtil::Position{ 0,0 }]); assertEqual(fcm2, map[mitk::pa::IOUtil::Position{ 0,1 }]); assertEqual(fcm3, map[mitk::pa::IOUtil::Position{ 1,0 }]); assertEqual(fcm4, map[mitk::pa::IOUtil::Position{ 1,1 }]); } void tearDown() override { //CPPUNIT_ASSERT_MESSAGE("Resource leak of test files onto hard drive..", itksys::SystemTools::RemoveADirectory(TEST_FOLDER_PATH) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticIO) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSaving.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSaving.cpp new file mode 100644 index 0000000000..5dbf93fa46 --- /dev/null +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSaving.cpp @@ -0,0 +1,82 @@ +/*=================================================================== + +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 + +class mitkPhotoacousticImageSavingTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPhotoacousticImageSavingTestSuite); + MITK_TEST(testSaveImagePlainMitk); + CPPUNIT_TEST_SUITE_END(); + +private: + +public: + + void setUp() + { + } + + void testSaveImagePlainMitk() + { + unsigned int x = 560; + unsigned int y = 400; + unsigned int z = 720; + unsigned int t = 4; + + unsigned long size = x*y*z*t; + + double* data = new double[size]; + + for (unsigned long i = 0; i < size; i++) + { + data[i] = rand() * 9.7327; + } + + mitk::Image::Pointer image = mitk::Image::New(); + mitk::PixelType TPixel = mitk::MakeScalarPixelType(); + unsigned int* dimensionsOfImage = new unsigned int[4]; + + // Copy dimensions + dimensionsOfImage[0] = 560; + dimensionsOfImage[1] = 400; + dimensionsOfImage[2] = 720; + dimensionsOfImage[3] = 4; + + image->Initialize(TPixel, 4, dimensionsOfImage, 1); + + mitk::Vector3D spacing; + spacing.Fill(0.1); + image->SetSpacing(spacing); + + image->SetImportVolume(data, 0, 0, mitk::Image::CopyMemory); + image->SetImportVolume(data, 1, 0, mitk::Image::CopyMemory); + image->SetImportVolume(data, 2, 0, mitk::Image::CopyMemory); + image->SetImportVolume(data, 3, 0, mitk::Image::CopyMemory); + + mitk::IOUtil::Save(image, "C:/Users/groehl/Desktop/test.nrrd"); + } + + void tearDown() + { + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticImageSaving) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSavingTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSavingTest.cpp new file mode 100644 index 0000000000..eb74325e89 --- /dev/null +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticImageSavingTest.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 +#include + +#include +#include + +class mitkPhotoacousticImageSavingTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPhotoacousticImageSavingTestSuite); + MITK_TEST(testSaveImagePlainMitk); + CPPUNIT_TEST_SUITE_END(); + +private: + +public: + + void setUp() + { + } + + void testSaveImagePlainMitk() + { + unsigned int x = pow(2, 30); + unsigned long size = x; + + float* data = new float[size]; + for (unsigned long i = 0; i < size; i++) + data[i] = 0; + + mitk::Image::Pointer image = mitk::Image::New(); + mitk::PixelType TPixel = mitk::MakeScalarPixelType(); + unsigned int* dimensionsOfImage = new unsigned int[1]; + dimensionsOfImage[0] = x; + image->Initialize(TPixel, 1, dimensionsOfImage, 1); + image->SetImportVolume(data, 0, 0, mitk::Image::CopyMemory); + + mitk::IOUtil::Save(image, "C:/Users/groehl/Desktop/test.nrrd"); + } + + void tearDown() + { + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticImageSaving) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticNoiseGeneratorTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticNoiseGeneratorTest.cpp index 04a988a528..30a43b9292 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticNoiseGeneratorTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticNoiseGeneratorTest.cpp @@ -1,71 +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. ===================================================================*/ #include #include #include #include "mitkPAVolume.h" #include "mitkPANoiseGenerator.h" class mitkPhotoacousticNoiseGeneratorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticNoiseGeneratorTestSuite); MITK_TEST(testNoiseGenerator); CPPUNIT_TEST_SUITE_END(); private: public: mitk::pa::Volume::Pointer m_Volume; void setUp() override { } void testNoiseGenerator() { int size = 1000 * 100 * 100; auto* volume = new double[size]; for (int i = 0; i < size; i++) { volume[i] = 1; } - m_Volume = mitk::pa::Volume::New(volume, 1000, 100, 100); + m_Volume = mitk::pa::Volume::New(volume, 1000, 100, 100, 1); mitk::pa::NoiseGenerator::ApplyNoiseModel(m_Volume, 0.75, 0.1); int negativecounter = 0; for (int i = 0; i < size; i++) { if (m_Volume->GetData()[i] <= 0) { negativecounter++; } } CPPUNIT_ASSERT_EQUAL_MESSAGE("More than one negative: " + std::to_string(negativecounter) + " (" + std::to_string((((double)negativecounter) / size) * 100) + "%)", negativecounter, 0); } void tearDown() override { } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticNoiseGenerator) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticTissueGeneratorTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticTissueGeneratorTest.cpp index 8199cdc0bf..0627bfb4b7 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticTissueGeneratorTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticTissueGeneratorTest.cpp @@ -1,83 +1,85 @@ /*=================================================================== 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 "mitkPATissueGenerator.h" class mitkPhotoacousticTissueGeneratorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticTissueGeneratorTestSuite); MITK_TEST(testCallWithEmptyParameters); MITK_TEST(testCallWithWorkingParameters); CPPUNIT_TEST_SUITE_END(); private: public: void setUp() override { } mitk::pa::TissueGeneratorParameters::Pointer createRandomTestVolumeParameters() { auto returnParameters = mitk::pa::TissueGeneratorParameters::New(); returnParameters->SetXDim(rand() % 50 + 1); returnParameters->SetYDim(rand() % 50 + 1); returnParameters->SetZDim(rand() % 50 + 1); - returnParameters->SetBackgroundAbsorption(rand() % 100 / 10.0); + double absorb = rand() % 100 / 10.0; + returnParameters->SetMinBackgroundAbsorption(absorb); + returnParameters->SetMaxBackgroundAbsorption(absorb); returnParameters->SetBackgroundScattering(rand() % 100 / 10.0); returnParameters->SetBackgroundAnisotropy(rand() % 100 / 10.0); int min = rand() % 10; returnParameters->SetMinNumberOfVessels(min); returnParameters->SetMaxNumberOfVessels(min + (rand() % 10)); returnParameters->SetCalculateNewVesselPositionCallback( &mitk::pa::VesselMeanderStrategy::CalculateRandomlyDivergingPosition); returnParameters->SetMinVesselZOrigin(rand() % 3 + 1); returnParameters->SetMaxVesselZOrigin(rand() % 3 + 1); int minRad = rand() % 100; returnParameters->SetMinVesselRadiusInMillimeters(minRad); returnParameters->SetMaxVesselRadiusInMillimeters(minRad + (rand() % 100)); returnParameters->SetVoxelSpacingInCentimeters(1); return returnParameters; } void testCallWithEmptyParameters() { auto parameters = mitk::pa::TissueGeneratorParameters::New(); auto volume = mitk::pa::InSilicoTissueGenerator::GenerateInSilicoData(parameters); CPPUNIT_ASSERT(volume.IsNotNull()); } void testCallWithWorkingParameters() { for (int i = 0; i < 20; i++) { auto parameters = createRandomTestVolumeParameters(); auto volume = mitk::pa::InSilicoTissueGenerator::GenerateInSilicoData(parameters); CPPUNIT_ASSERT(volume.IsNotNull()); } } void tearDown() override { } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticTissueGenerator) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTest.cpp index 17b06e9e21..c1e3949514 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTest.cpp @@ -1,169 +1,242 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include "mitkPAInSilicoTissueVolume.h" #include "mitkPAVector.h" #include "mitkPAVessel.h" #include "mitkIOUtil.h" class mitkPhotoacousticVesselTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticVesselTestSuite); MITK_TEST(testEmptyInitializationProperties); MITK_TEST(testWalkInStraightLine); MITK_TEST(testBifurcate); + MITK_TEST(testPartialVolume); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::Vessel::Pointer m_TestVessel; mitk::pa::Vessel::CalculateNewVesselPositionCallback m_StraightLine; mitk::pa::Vessel::CalculateNewVesselPositionCallback m_Diverging; mitk::pa::InSilicoTissueVolume::Pointer m_TestInSilicoVolume; mitk::pa::TissueGeneratorParameters::Pointer m_TestVolumeParameters; public: void setUp() override { auto params = mitk::pa::VesselProperties::New(); m_TestVessel = mitk::pa::Vessel::New(params); m_StraightLine = &mitk::pa::VesselMeanderStrategy::CalculateNewPositionInStraightLine; m_Diverging = &mitk::pa::VesselMeanderStrategy::CalculateRandomlyDivergingPosition; m_TestVolumeParameters = createTestVolumeParameters(); - m_TestInSilicoVolume = mitk::pa::InSilicoTissueVolume::New(m_TestVolumeParameters); + auto rng = std::mt19937(); + m_TestInSilicoVolume = mitk::pa::InSilicoTissueVolume::New(m_TestVolumeParameters, &rng); } mitk::pa::TissueGeneratorParameters::Pointer createTestVolumeParameters() { auto returnParameters = mitk::pa::TissueGeneratorParameters::New(); returnParameters->SetXDim(10); returnParameters->SetYDim(10); returnParameters->SetZDim(10); - returnParameters->SetBackgroundAbsorption(0); + returnParameters->SetMinBackgroundAbsorption(0); + returnParameters->SetMaxBackgroundAbsorption(0); returnParameters->SetBackgroundScattering(0); returnParameters->SetBackgroundAnisotropy(0); return returnParameters; } void testEmptyInitializationProperties() { CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == false); CPPUNIT_ASSERT(m_TestVessel->IsFinished() == true); } - void testWalkInStraightLine() + void testPartialVolume() { auto testPosition = mitk::pa::Vector::New(); testPosition->SetElement(0, 0); testPosition->SetElement(1, 4); testPosition->SetElement(2, 4); auto testDirection = mitk::pa::Vector::New(); testDirection->SetElement(0, 1); testDirection->SetElement(1, 0); testDirection->SetElement(2, 0); auto params = mitk::pa::VesselProperties::New(); + params->SetDoPartialVolume(true); params->SetRadiusInVoxel(1); params->SetBifurcationFrequency(100); params->SetAbsorptionCoefficient(10); params->SetScatteringCoefficient(10); params->SetAnisotopyCoefficient(10); params->SetPositionVector(testPosition); params->SetDirectionVector(testDirection); m_TestVessel = mitk::pa::Vessel::New(params); CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == false); CPPUNIT_ASSERT(m_TestVessel->IsFinished() == false); CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)) <= mitk::eps); m_TestVessel->ExpandVessel(m_TestInSilicoVolume, m_StraightLine, 0, nullptr); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 6, 4)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 5)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 5) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 3)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 3) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 5)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 5) - 5.85786438) <= 1e-6); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 3)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 3) - 5.85786438) <= 1e-6); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 3)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 3) - 5.85786438) <= 1e-6); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 5)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 3, 5) - 5.85786438) <= 1e-6); + } - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 5) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 6)) <= mitk::eps); + void testWalkInStraightLine() + { + auto testPosition = mitk::pa::Vector::New(); + testPosition->SetElement(0, 0); + testPosition->SetElement(1, 4); + testPosition->SetElement(2, 4); + auto testDirection = mitk::pa::Vector::New(); + testDirection->SetElement(0, 1); + testDirection->SetElement(1, 0); + testDirection->SetElement(2, 0); + auto params = mitk::pa::VesselProperties::New(); + params->SetDoPartialVolume(false); + params->SetRadiusInVoxel(1); + params->SetBifurcationFrequency(100); + params->SetAbsorptionCoefficient(10); + params->SetScatteringCoefficient(10); + params->SetAnisotopyCoefficient(10); + params->SetPositionVector(testPosition); + params->SetDirectionVector(testDirection); + m_TestVessel = mitk::pa::Vessel::New(params); + + CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == false); + CPPUNIT_ASSERT(m_TestVessel->IsFinished() == false); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)) <= mitk::eps); m_TestVessel->ExpandVessel(m_TestInSilicoVolume, m_StraightLine, 0, nullptr); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 5, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 6, 4)) <= mitk::eps); + mitk::IOUtil::Save(m_TestInSilicoVolume->GetAbsorptionVolume()->AsMitkImage(), "C:/Users/groehl/Desktop/test.nrrd"); + + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 5, 4)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 6, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 6, 4)) <= mitk::eps); + + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 5)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 5)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 6)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 6)) <= mitk::eps); + + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4)) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 5) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 6)) <= mitk::eps); + m_TestVessel->ExpandVessel(m_TestInSilicoVolume, m_StraightLine, 0, nullptr); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4) - 10) <= mitk::eps); - CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(3, 4, 4)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 5, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 5, 4)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 6, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 6, 4)) <= mitk::eps); + + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 5)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 5)) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 6)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 6)) <= mitk::eps); + + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(1, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(2, 4, 4) - 10) <= mitk::eps); + CPPUNIT_ASSERT_MESSAGE(std::to_string(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(3, 4, 4)), + abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(3, 4, 4)) <= mitk::eps); } void testBifurcate() { auto testPosition = mitk::pa::Vector::New(); testPosition->SetElement(0, 0); testPosition->SetElement(1, 4); testPosition->SetElement(2, 4); auto testDirection = mitk::pa::Vector::New(); testDirection->SetElement(0, 1); testDirection->SetElement(1, 0); testDirection->SetElement(2, 0); auto params = mitk::pa::VesselProperties::New(); params->SetRadiusInVoxel(1); params->SetBifurcationFrequency(1); params->SetAbsorptionCoefficient(10); params->SetScatteringCoefficient(10); params->SetAnisotopyCoefficient(10); params->SetPositionVector(testPosition); params->SetDirectionVector(testDirection); m_TestVessel = mitk::pa::Vessel::New(params); CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == false); CPPUNIT_ASSERT(m_TestVessel->IsFinished() == false); CPPUNIT_ASSERT(std::abs(m_TestInSilicoVolume->GetAbsorptionVolume()->GetData(0, 4, 4)) <= mitk::eps); m_TestVessel->ExpandVessel(m_TestInSilicoVolume, m_StraightLine, 0, nullptr); m_TestVessel->ExpandVessel(m_TestInSilicoVolume, m_StraightLine, 0, nullptr); CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == true); std::mt19937 rng; auto bifurcationVessel = m_TestVessel->Bifurcate(&rng); CPPUNIT_ASSERT(m_TestVessel->CanBifurcate() == false); CPPUNIT_ASSERT(bifurcationVessel->CanBifurcate() == false); } void tearDown() override { } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticVessel) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTreeTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTreeTest.cpp index a78d6a7bb9..1a022017f3 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTreeTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVesselTreeTest.cpp @@ -1,106 +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 "mitkPAVesselTree.h" #include "mitkPAInSilicoTissueVolume.h" using namespace mitk::pa; class mitkPhotoacousticVesselTreeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticVesselTreeTestSuite); MITK_TEST(testVesselTreeInitialBehavior); MITK_TEST(testCallStepMethod); CPPUNIT_TEST_SUITE_END(); private: public: VesselTree::Pointer m_Tree; VesselProperties::Pointer m_VesselProperties; Vessel::CalculateNewVesselPositionCallback m_StraightLine; InSilicoTissueVolume::Pointer m_TestInSilicoVolume; void setUp() override { m_VesselProperties = VesselProperties::New(); m_Tree = VesselTree::New(m_VesselProperties); m_StraightLine = &VesselMeanderStrategy::CalculateNewPositionInStraightLine; - m_TestInSilicoVolume = InSilicoTissueVolume::New(createTestVolumeParameters()); + auto rng = std::mt19937(); + m_TestInSilicoVolume = InSilicoTissueVolume::New(createTestVolumeParameters(), &rng); } TissueGeneratorParameters::Pointer createTestVolumeParameters() { auto returnParameters = TissueGeneratorParameters::New(); returnParameters->SetXDim(10); returnParameters->SetYDim(10); returnParameters->SetZDim(10); - returnParameters->SetBackgroundAbsorption(0); + returnParameters->SetMinBackgroundAbsorption(0); + returnParameters->SetMaxBackgroundAbsorption(0); returnParameters->SetBackgroundScattering(0); returnParameters->SetBackgroundAnisotropy(0); return returnParameters; } void testVesselTreeInitialBehavior() { CPPUNIT_ASSERT(m_Tree->IsFinished() == true); } void testCallStepMethod() { //really bad test atm.. The only thing that is tested is that the method can be called without a crash. //But hey - it is something :P m_VesselProperties->SetRadiusInVoxel(2); std::mt19937 rng; rng.seed(1); m_Tree = VesselTree::New(m_VesselProperties); m_Tree->Step(m_TestInSilicoVolume, m_StraightLine, 0, &rng); rng.seed(1); auto secondTree = VesselTree::New(m_VesselProperties); secondTree->Step(m_TestInSilicoVolume, m_StraightLine, 0, &rng); CPPUNIT_ASSERT(Equal(m_Tree, secondTree, 1e-6, true)); secondTree->Step(m_TestInSilicoVolume, m_StraightLine, 0, &rng); CPPUNIT_ASSERT(!Equal(m_Tree, secondTree, 1e-6, true)); int i = 0; for (; i < 1000; i++) { secondTree->Step(m_TestInSilicoVolume, m_StraightLine, 0, &rng); if (secondTree->IsFinished()) break; } CPPUNIT_ASSERT(i < 999); } void tearDown() override { } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticVesselTree) diff --git a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVolumeTest.cpp b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVolumeTest.cpp index 0af0c79d24..b3e874aa1c 100644 --- a/Modules/PhotoacousticsLib/test/mitkPhotoacousticVolumeTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkPhotoacousticVolumeTest.cpp @@ -1,347 +1,385 @@ /*=================================================================== 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 "mitkPAInSilicoTissueVolume.h" #include "mitkPATissueGeneratorParameters.h" class mitkPhotoacousticVolumeTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPhotoacousticVolumeTestSuite); + MITK_TEST(TestUniformDistributionIsUniform); MITK_TEST(TestInitializedTissueContainsOnlyZeros); MITK_TEST(TestConvertedMitkImageContainsOnlyZerosOrAir); MITK_TEST(TestTissueVolumeContainsCorrectAbsorptionNumber); MITK_TEST(TestTissueVolumeContainsCorrectScatteringNumber); MITK_TEST(TestTissueVolumeContainsCorrectAnisotropyNumber); MITK_TEST(testSecondConstructor); MITK_TEST(testCompleteAirVoxelInclusion); MITK_TEST(testHalfAirVoxelInclusion); MITK_TEST(testCompleteAirAndSkinVoxelInclusion); MITK_TEST(testRandomizeCoefficients); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::InSilicoTissueVolume::Pointer m_PhotoacousticVolume; mitk::pa::TissueGeneratorParameters::Pointer m_TissueGeneratorParameters; public: void setUp() override { m_TissueGeneratorParameters = mitk::pa::TissueGeneratorParameters::New(); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); + } + + void TestUniformDistributionIsUniform() + { + + int dims = 30; + m_TissueGeneratorParameters->SetXDim(dims); + m_TissueGeneratorParameters->SetYDim(dims); + m_TissueGeneratorParameters->SetZDim(dims); + m_TissueGeneratorParameters->SetAirThicknessInMillimeters(0); + + m_TissueGeneratorParameters->SetMinBackgroundAbsorption(0.001); + m_TissueGeneratorParameters->SetMaxBackgroundAbsorption(0.2); + + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); + + for (int x = 0; x < dims; x++) + { + for (int y = 0; y < dims; y++) + { + for (int z = 0; z < dims; z++) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE("Every absorption should be in bounds.", + m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(x, y, z) >= 0.001 && + m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(x, y, z) <= 0.2, true); + } + } + } + } void TestInitializedTissueContainsOnlyZeros() { int dims = 30; m_TissueGeneratorParameters->SetXDim(dims); m_TissueGeneratorParameters->SetYDim(dims); m_TissueGeneratorParameters->SetZDim(dims); m_TissueGeneratorParameters->SetAirThicknessInMillimeters(0); - m_TissueGeneratorParameters->SetBackgroundAbsorption(0); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + m_TissueGeneratorParameters->SetMinBackgroundAbsorption(0); + m_TissueGeneratorParameters->SetMaxBackgroundAbsorption(0); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); for (int x = 0; x < dims; x++) { for (int y = 0; y < dims; y++) { for (int z = 0; z < dims; z++) { CPPUNIT_ASSERT_EQUAL_MESSAGE("Every field should be initialized with 0.", std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(x, y, z)) < mitk::eps, true); } } } } void TestConvertedMitkImageContainsOnlyZerosOrAir() { int dims = 30; m_TissueGeneratorParameters->SetXDim(dims); m_TissueGeneratorParameters->SetYDim(dims); m_TissueGeneratorParameters->SetZDim(dims); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); mitk::Image::Pointer testImage = m_PhotoacousticVolume->ConvertToMitkImage(); mitk::ImageReadAccessor imgMemAcc(testImage); auto* imagePointer = (double*)imgMemAcc.GetData(); for (int index = 0; index < dims*dims*dims; index++, imagePointer++) { CPPUNIT_ASSERT_EQUAL_MESSAGE("Every voxel in image should be 0.1 or 0.0001.", true, std::abs(*imagePointer - 0.1) <= mitk::eps || std::abs(*imagePointer - 0.0001) <= mitk::eps); } } void TestTissueVolumeContainsCorrectAbsorptionNumber() { int dims = 2; m_TissueGeneratorParameters->SetXDim(dims); m_TissueGeneratorParameters->SetYDim(dims); m_TissueGeneratorParameters->SetZDim(dims); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 1, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 2, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 3, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 4, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 5, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 6, 0, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 7, 0, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 1)); } void TestTissueVolumeContainsCorrectScatteringNumber() { int dims = 2; m_TissueGeneratorParameters->SetXDim(dims); m_TissueGeneratorParameters->SetYDim(dims); m_TissueGeneratorParameters->SetZDim(dims); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 0, 1, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 0, 2, 0); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 0, 3, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 0, 4, 0); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 0, 5, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 0, 6, 0); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 0, 7, 0); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 1)); } void TestTissueVolumeContainsCorrectAnisotropyNumber() { int dims = 2; m_TissueGeneratorParameters->SetXDim(dims); m_TissueGeneratorParameters->SetYDim(dims); m_TissueGeneratorParameters->SetZDim(dims); - m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters); + auto rng = std::mt19937(); + m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(m_TissueGeneratorParameters, &rng); m_PhotoacousticVolume->SetVolumeValues(0, 0, 0, 0, 0, 0); m_PhotoacousticVolume->SetVolumeValues(0, 0, 1, 0, 0, 1); m_PhotoacousticVolume->SetVolumeValues(0, 1, 0, 0, 0, 2); m_PhotoacousticVolume->SetVolumeValues(0, 1, 1, 0, 0, 3); m_PhotoacousticVolume->SetVolumeValues(1, 0, 0, 0, 0, 4); m_PhotoacousticVolume->SetVolumeValues(1, 0, 1, 0, 0, 5); m_PhotoacousticVolume->SetVolumeValues(1, 1, 0, 0, 0, 6); m_PhotoacousticVolume->SetVolumeValues(1, 1, 1, 0, 0, 7); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 0.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 1.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 2.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 3.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 1, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 4.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 0, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 5.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 0, 1)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 6.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 0)); CPPUNIT_ASSERT_EQUAL_MESSAGE("Should be correct value", 7.0, m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 1)); } mitk::pa::Volume::Pointer createTestVolume(double value) { auto* data = new double[27]; for (int i = 0; i < 27; ++i) data[i] = value; - return mitk::pa::Volume::New(data, 3, 3, 3); + return mitk::pa::Volume::New(data, 3, 3, 3, 1); } void assertEqual(mitk::pa::Volume::Pointer first, mitk::pa::Volume::Pointer second) { CPPUNIT_ASSERT(first->GetXDim() == second->GetXDim()); CPPUNIT_ASSERT(first->GetYDim() == second->GetYDim()); CPPUNIT_ASSERT(first->GetZDim() == second->GetZDim()); for (unsigned int x = 0; x < first->GetXDim(); ++x) for (unsigned int y = 0; y < first->GetYDim(); ++y) for (unsigned int z = 0; z < first->GetZDim(); ++z) CPPUNIT_ASSERT(std::abs(first->GetData(x, y, z) - second->GetData(x, y, z)) < mitk::eps); } void testSecondConstructor() { mitk::pa::Volume::Pointer absorption = createTestVolume(1); mitk::pa::Volume::Pointer scattering = createTestVolume(2); mitk::pa::Volume::Pointer anisotropy = createTestVolume(3); mitk::pa::Volume::Pointer segmentation = createTestVolume(4); mitk::PropertyList::Pointer properties = mitk::PropertyList::New(); m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(absorption, scattering, anisotropy, segmentation, m_TissueGeneratorParameters, properties); assertEqual(m_PhotoacousticVolume->GetAbsorptionVolume(), absorption); assertEqual(m_PhotoacousticVolume->GetScatteringVolume(), scattering); assertEqual(m_PhotoacousticVolume->GetAnisotropyVolume(), anisotropy); assertEqual(m_PhotoacousticVolume->GetSegmentationVolume(), segmentation); } void testCompleteAirVoxelInclusion() { mitk::pa::Volume::Pointer absorption = createTestVolume(1); mitk::pa::Volume::Pointer scattering = createTestVolume(2); mitk::pa::Volume::Pointer anisotropy = createTestVolume(3); mitk::pa::Volume::Pointer segmentation = createTestVolume(4); mitk::PropertyList::Pointer properties = mitk::PropertyList::New(); m_TissueGeneratorParameters->SetXDim(3); m_TissueGeneratorParameters->SetYDim(3); m_TissueGeneratorParameters->SetZDim(3); m_TissueGeneratorParameters->SetAirThicknessInMillimeters(10); m_TissueGeneratorParameters->SetSkinThicknessInMillimeters(0); m_TissueGeneratorParameters->SetAirAbsorption(2); m_TissueGeneratorParameters->SetAirScattering(4); m_TissueGeneratorParameters->SetAirAnisotropy(6); m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(absorption, scattering, anisotropy, segmentation, m_TissueGeneratorParameters, properties); m_PhotoacousticVolume->FinalizeVolume(); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 0) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 1) - 1) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 2) - 1) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 0) - 4) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 1) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 2) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 0) - 6) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 1) - 3) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 2) - 3) < mitk::eps); } void testRandomizeCoefficients() { mitk::pa::Volume::Pointer absorption = createTestVolume(1); mitk::pa::Volume::Pointer scattering = createTestVolume(1); mitk::pa::Volume::Pointer anisotropy = createTestVolume(1); mitk::pa::Volume::Pointer segmentation = createTestVolume(4); mitk::PropertyList::Pointer properties = mitk::PropertyList::New(); m_TissueGeneratorParameters->SetXDim(3); m_TissueGeneratorParameters->SetYDim(3); m_TissueGeneratorParameters->SetZDim(3); m_TissueGeneratorParameters->SetRandomizePhysicalProperties(true); m_TissueGeneratorParameters->SetRandomizePhysicalPropertiesPercentage(1); m_TissueGeneratorParameters->SetRngSeed(17); m_TissueGeneratorParameters->SetUseRngSeed(true); m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(absorption, scattering, anisotropy, segmentation, m_TissueGeneratorParameters, properties); m_PhotoacousticVolume->FinalizeVolume(); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 0) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 1) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 2) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 0) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 1) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 2) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 0) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 1) - 1) < 0.1); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 2) - 1) < 0.1); } void testCompleteAirAndSkinVoxelInclusion() { mitk::pa::Volume::Pointer absorption = createTestVolume(1); mitk::pa::Volume::Pointer scattering = createTestVolume(2); mitk::pa::Volume::Pointer anisotropy = createTestVolume(3); mitk::pa::Volume::Pointer segmentation = createTestVolume(4); mitk::PropertyList::Pointer properties = mitk::PropertyList::New(); m_TissueGeneratorParameters->SetXDim(3); m_TissueGeneratorParameters->SetYDim(3); m_TissueGeneratorParameters->SetZDim(3); m_TissueGeneratorParameters->SetAirThicknessInMillimeters(10); m_TissueGeneratorParameters->SetSkinThicknessInMillimeters(10); m_TissueGeneratorParameters->SetAirAbsorption(2); m_TissueGeneratorParameters->SetAirScattering(4); m_TissueGeneratorParameters->SetAirAnisotropy(6); m_TissueGeneratorParameters->SetSkinAbsorption(4); m_TissueGeneratorParameters->SetSkinScattering(8); m_TissueGeneratorParameters->SetSkinAnisotropy(12); m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(absorption, scattering, anisotropy, segmentation, m_TissueGeneratorParameters, properties); m_PhotoacousticVolume->FinalizeVolume(); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 0) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 1) - 4) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 2) - 1) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 0) - 4) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 1) - 8) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 2) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 0) - 6) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 1) - 12) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 2) - 3) < mitk::eps); } void testHalfAirVoxelInclusion() { mitk::pa::Volume::Pointer absorption = createTestVolume(1); mitk::pa::Volume::Pointer scattering = createTestVolume(2); mitk::pa::Volume::Pointer anisotropy = createTestVolume(3); mitk::pa::Volume::Pointer segmentation = createTestVolume(4); mitk::PropertyList::Pointer properties = mitk::PropertyList::New(); m_TissueGeneratorParameters->SetXDim(3); m_TissueGeneratorParameters->SetYDim(3); m_TissueGeneratorParameters->SetZDim(3); m_TissueGeneratorParameters->SetAirThicknessInMillimeters(15); m_TissueGeneratorParameters->SetSkinThicknessInMillimeters(0); m_TissueGeneratorParameters->SetAirAbsorption(2); m_TissueGeneratorParameters->SetAirScattering(4); m_TissueGeneratorParameters->SetAirAnisotropy(6); m_PhotoacousticVolume = mitk::pa::InSilicoTissueVolume::New(absorption, scattering, anisotropy, segmentation, m_TissueGeneratorParameters, properties); m_PhotoacousticVolume->FinalizeVolume(); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(0, 0, 0) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 1) - 1.5) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAbsorptionVolume()->GetData(1, 1, 2) - 1) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(0, 0, 0) - 4) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 1) - 3) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetScatteringVolume()->GetData(1, 1, 2) - 2) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(0, 0, 0) - 6) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 1) - 4.5) < mitk::eps); CPPUNIT_ASSERT(std::abs(m_PhotoacousticVolume->GetAnisotropyVolume()->GetData(1, 1, 2) - 3) < mitk::eps); } void tearDown() override { m_PhotoacousticVolume = nullptr; } }; MITK_TEST_SUITE_REGISTRATION(mitkPhotoacousticVolume) diff --git a/Modules/PhotoacousticsLib/test/mitkSimulationBatchGeneratorTest.cpp b/Modules/PhotoacousticsLib/test/mitkSimulationBatchGeneratorTest.cpp index 2732c64bd5..10fdbbde73 100644 --- a/Modules/PhotoacousticsLib/test/mitkSimulationBatchGeneratorTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkSimulationBatchGeneratorTest.cpp @@ -1,90 +1,90 @@ ///*=================================================================== //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 class mitkSimulationBatchGeneratorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSimulationBatchGeneratorTestSuite); MITK_TEST(testGenerateBatchFileString); MITK_TEST(testGenerateBatchFileAndSaveFile); CPPUNIT_TEST_SUITE_END(); private: const std::string TEST_FOLDER_PATH = "testFiles/"; mitk::pa::SimulationBatchGeneratorParameters::Pointer m_Parameters; mitk::pa::Volume::Pointer m_Test3DVolume; public: void setUp() override { m_Parameters = mitk::pa::SimulationBatchGeneratorParameters::New(); m_Parameters->SetBinaryPath("binary"); m_Parameters->SetNrrdFilePath(TEST_FOLDER_PATH); m_Parameters->SetNumberOfPhotons(100); m_Parameters->SetTissueName("tissueName"); m_Parameters->SetVolumeIndex(0); m_Parameters->SetYOffsetLowerThresholdInCentimeters(-1); m_Parameters->SetYOffsetUpperThresholdInCentimeters(1); m_Parameters->SetYOffsetStepInCentimeters(0.5); m_Test3DVolume = createTest3DVolume(5); itk::FileTools::CreateDirectory(TEST_FOLDER_PATH); CPPUNIT_ASSERT(itksys::SystemTools::FileIsDirectory(TEST_FOLDER_PATH)); } mitk::pa::Volume::Pointer createTest3DVolume(double value) { unsigned int xDim = 10; unsigned int yDim = 10; unsigned int zDim = 10; unsigned int length = xDim * yDim * zDim; auto* data = new double[length]; for (unsigned int i = 0; i < length; i++) data[i] = value; - return mitk::pa::Volume::New(data, xDim, yDim, zDim); + return mitk::pa::Volume::New(data, xDim, yDim, zDim, 1); } void testGenerateBatchFileString() { std::string batchGenerationString = mitk::pa::SimulationBatchGenerator::CreateBatchSimulationString(m_Parameters); CPPUNIT_ASSERT(!batchGenerationString.empty()); } void testGenerateBatchFileAndSaveFile() { mitk::pa::SimulationBatchGenerator::WriteBatchFileAndSaveTissueVolume(m_Parameters, m_Test3DVolume->AsMitkImage()); CPPUNIT_ASSERT(itksys::SystemTools::FileExists(TEST_FOLDER_PATH + m_Parameters->GetTissueName() + "000.nrrd")); CPPUNIT_ASSERT(itksys::SystemTools::FileExists(TEST_FOLDER_PATH + "simulate_all.sh") || itksys::SystemTools::FileExists(TEST_FOLDER_PATH + "simulate_all.bat")); CPPUNIT_ASSERT(itksys::SystemTools::FileExists(TEST_FOLDER_PATH + m_Parameters->GetTissueName() + "000") && itksys::SystemTools::FileIsDirectory(TEST_FOLDER_PATH + m_Parameters->GetTissueName() + "000")); } void tearDown() override { m_Parameters = nullptr; CPPUNIT_ASSERT_MESSAGE("Resource leak of test files onto hard drive..", itksys::SystemTools::RemoveADirectory(TEST_FOLDER_PATH) == true); } }; MITK_TEST_SUITE_REGISTRATION(mitkSimulationBatchGenerator) diff --git a/Modules/PhotoacousticsLib/test/mitkSlicedVolumeGeneratorTest.cpp b/Modules/PhotoacousticsLib/test/mitkSlicedVolumeGeneratorTest.cpp index c4bfc1fa09..aab23e0aa2 100644 --- a/Modules/PhotoacousticsLib/test/mitkSlicedVolumeGeneratorTest.cpp +++ b/Modules/PhotoacousticsLib/test/mitkSlicedVolumeGeneratorTest.cpp @@ -1,187 +1,188 @@ ///*=================================================================== //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 class mitkSlicedVolumeGeneratorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkSlicedVolumeGeneratorTestSuite); MITK_TEST(testConstructorDestructor); MITK_TEST(testGetSlicedFluenceVolume); MITK_TEST(testGetSlicedFluenceVolumeInverse); MITK_TEST(testGetSlicedFluenceVolumeWithPrecorrection); MITK_TEST(testGetSlicedFluenceVolumeWithPrecorrectionInverse); MITK_TEST(testGetSlicedSignalVolume); MITK_TEST(testGetSlicedAbsorptionVolume); CPPUNIT_TEST_SUITE_END(); private: mitk::pa::ComposedVolume::Pointer m_ComposedVolume; mitk::pa::TissueGeneratorParameters::Pointer m_DefaultParameters; mitk::pa::InSilicoTissueVolume::Pointer m_InSilicoTissueVolume; mitk::pa::SlicedVolumeGenerator::Pointer m_SlicedVolumeGenerator; mitk::pa::Volume::Pointer m_PrecorrectionVolume; public: void setUp() override { m_SlicedVolumeGenerator = nullptr; m_DefaultParameters = mitk::pa::TissueGeneratorParameters::New(); m_DefaultParameters->SetXDim(3); m_DefaultParameters->SetYDim(3); m_DefaultParameters->SetZDim(3); - m_InSilicoTissueVolume = mitk::pa::InSilicoTissueVolume::New(m_DefaultParameters); + auto rng = std::mt19937(); + m_InSilicoTissueVolume = mitk::pa::InSilicoTissueVolume::New(m_DefaultParameters, &rng); m_ComposedVolume = mitk::pa::ComposedVolume::New(m_InSilicoTissueVolume); m_ComposedVolume->AddSlice(CreateValidationPair(-1, 1)); m_ComposedVolume->AddSlice(CreateValidationPair(0, 3)); m_ComposedVolume->AddSlice(CreateValidationPair(1, 6)); m_PrecorrectionVolume = CreatePrecorrectionVolume(); } mitk::pa::Volume::Pointer CreatePrecorrectionVolume() { auto* data = new double[27]; for (int i = 0; i < 27; ++i) data[i] = 0.5; - return mitk::pa::Volume::New(data, 3, 3, 3); + return mitk::pa::Volume::New(data, 3, 3, 3, 1); } void FillYSliceWith(mitk::pa::Volume::Pointer fluenceVolume, double ySlice, double value) { for (unsigned int x = 0; x < fluenceVolume->GetXDim(); ++x) for (unsigned int z = 0; z < fluenceVolume->GetZDim(); ++z) { fluenceVolume->SetData(value, x, ySlice, z); } } mitk::pa::FluenceYOffsetPair::Pointer CreateValidationPair(double yOffset, int start) { auto* data = new double[27]; - mitk::pa::Volume::Pointer fluenceVolume = mitk::pa::Volume::New(data, 3, 3, 3); + mitk::pa::Volume::Pointer fluenceVolume = mitk::pa::Volume::New(data, 3, 3, 3, 1); FillYSliceWith(fluenceVolume, 0, start + 0); FillYSliceWith(fluenceVolume, 1, start + 1); FillYSliceWith(fluenceVolume, 2, start + 2); return mitk::pa::FluenceYOffsetPair::New(fluenceVolume, yOffset); } void AssertYSliceValue(mitk::pa::Volume::Pointer fluenceVolume, double ySlice, double value) { for (unsigned int x = 0; x < fluenceVolume->GetXDim(); ++x) for (unsigned int z = 0; z < fluenceVolume->GetZDim(); ++z) { std::string msg = "Expected: " + std::to_string(value) + " actual: " + std::to_string(fluenceVolume->GetData(x, ySlice, z)); CPPUNIT_ASSERT_MESSAGE(msg, std::abs(fluenceVolume->GetData(x, ySlice, z) - value) < mitk::eps); } } void testConstructorDestructor() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(0, false, nullptr, false); CPPUNIT_ASSERT(m_SlicedVolumeGenerator.IsNotNull()); } void testGetSlicedFluenceVolume() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, false, nullptr, false); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedFluenceImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); AssertYSliceValue(slicedFluence, 0, 1); AssertYSliceValue(slicedFluence, 1, 4); AssertYSliceValue(slicedFluence, 2, 8); } void testGetSlicedFluenceVolumeInverse() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, false, nullptr, true); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedFluenceImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); AssertYSliceValue(slicedFluence, 0, 1); AssertYSliceValue(slicedFluence, 1, 1.0 / 4.0); AssertYSliceValue(slicedFluence, 2, 1.0 / 8.0); } void testGetSlicedFluenceVolumeWithPrecorrection() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, true, m_PrecorrectionVolume, false); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedFluenceImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); AssertYSliceValue(slicedFluence, 0, 2); AssertYSliceValue(slicedFluence, 1, 8); AssertYSliceValue(slicedFluence, 2, 16); } void testGetSlicedFluenceVolumeWithPrecorrectionInverse() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, true, m_PrecorrectionVolume, true); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedFluenceImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); AssertYSliceValue(slicedFluence, 0, 1.0 / 2); AssertYSliceValue(slicedFluence, 1, 1.0 / 8); AssertYSliceValue(slicedFluence, 2, 1.0 / 16); } void testGetSlicedSignalVolume() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, false, nullptr, false); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedSignalImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); - AssertYSliceValue(slicedFluence, 0, 1 * m_DefaultParameters->GetBackgroundAbsorption()); - AssertYSliceValue(slicedFluence, 1, 4 * m_DefaultParameters->GetBackgroundAbsorption()); - AssertYSliceValue(slicedFluence, 2, 8 * m_DefaultParameters->GetBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 0, 1 * m_DefaultParameters->GetMinBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 1, 4 * m_DefaultParameters->GetMinBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 2, 8 * m_DefaultParameters->GetMinBackgroundAbsorption()); } void testGetSlicedAbsorptionVolume() { m_SlicedVolumeGenerator = mitk::pa::SlicedVolumeGenerator::New(1, false, nullptr, false); mitk::pa::Volume::Pointer slicedFluence = m_SlicedVolumeGenerator->GetSlicedGroundTruthImageFromComposedVolume(m_ComposedVolume); CPPUNIT_ASSERT(slicedFluence->GetXDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetYDim() == 3); CPPUNIT_ASSERT(slicedFluence->GetZDim() == 3); - AssertYSliceValue(slicedFluence, 0, m_DefaultParameters->GetBackgroundAbsorption()); - AssertYSliceValue(slicedFluence, 1, m_DefaultParameters->GetBackgroundAbsorption()); - AssertYSliceValue(slicedFluence, 2, m_DefaultParameters->GetBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 0, m_DefaultParameters->GetMinBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 1, m_DefaultParameters->GetMinBackgroundAbsorption()); + AssertYSliceValue(slicedFluence, 2, m_DefaultParameters->GetMinBackgroundAbsorption()); } void tearDown() override { m_SlicedVolumeGenerator = nullptr; } }; MITK_TEST_SUITE_REGISTRATION(mitkSlicedVolumeGenerator) diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index fc924b63fb..4822eb025f 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 + mitkIDataStorageInspectorProvider.cpp + mitkQtWidgetsActivator.cpp + mitkDataStorageInspectorGenerator.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/QmitkDataStorageInspectorProviderBase.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h new file mode 100644 index 0000000000..4272175faf --- /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 provider 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 /* __QMITK_DATA_STORAGE_INSPECTOR_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..6bc899373d --- /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 QMITKDATASTORAGELISTINSPECTOR_H +#define QMITKDATASTORAGELISTINSPECTOR_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 // QMITKDATASTORAGELISTINSPECTOR_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..848c71645e --- /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 // QMITKDATASTORAGETREEINSPECTOR_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/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/include/mitkDataStorageInspectorGenerator.h b/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h new file mode 100644 index 0000000000..9ef6d60b7b --- /dev/null +++ b/Modules/QtWidgets/include/mitkDataStorageInspectorGenerator.h @@ -0,0 +1,45 @@ +/*=================================================================== + +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 mitkDataStorageInspectorGenerator_H +#define mitkDataStorageInspectorGenerator_H + +#include "mitkIDataStorageInspectorProvider.h" + +#include + +namespace mitk +{ + /** Convinvience class to get all or specific DataStorageInspectorProvider. */ + class MITKQTWIDGETS_EXPORT DataStorageInspectorGenerator + { + public: + using IDType = std::string; + + using ProviderMapType = std::map; + static ProviderMapType GetProviders(); + + static mitk::IDataStorageInspectorProvider *GetProvider(const IDType &id); + + protected: + DataStorageInspectorGenerator(); + virtual ~DataStorageInspectorGenerator(); + DataStorageInspectorGenerator(const DataStorageInspectorGenerator &source) = delete; + DataStorageInspectorGenerator& operator=(const DataStorageInspectorGenerator &) = delete; + }; +} + +#endif diff --git a/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h b/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.h new file mode 100644 index 0000000000..bbce815718 --- /dev/null +++ b/Modules/QtWidgets/include/mitkIDataStorageInspectorProvider.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_DATA_STORAGE_INSPECTOR_PROVIDER_H +#define __I_DATA_STORAGE_INSPECTOR_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_DATA_STORAGE_INSPECTOR_PROVIDER_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/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/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/QmitkRenderWindowMenu.cpp b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp index 28f4cedc33..733e097e33 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp @@ -1,1017 +1,1017 @@ /*=================================================================== 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 "QmitkRenderWindowMenu.h" #include "mitkProperties.h" #include "mitkResliceMethodProperty.h" #include #include #include #include - +#include #include #include #include #include #include #include #include #include "QmitkStdMultiWidget.h" //#include"iconClose.xpm" #include "iconCrosshairMode.xpm" #include "iconFullScreen.xpm" //#include"iconHoriSplit.xpm" #include "iconSettings.xpm" //#include"iconVertiSplit.xpm" #include "iconLeaveFullScreen.xpm" #include #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, Qt::WindowFlags, mitk::BaseRenderer *b, QmitkStdMultiWidget *mw) : QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint), #else QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget *parent, Qt::WindowFlags f, mitk::BaseRenderer *b, QmitkStdMultiWidget *mw) : QWidget(parent, f), #endif m_Settings(nullptr), m_CrosshairMenu(nullptr), m_Layout(0), m_LayoutDesign(0), m_OldLayoutDesign(0), m_FullScreenMode(false), m_Entered(false), m_Renderer(b), m_MultiWidget(mw), m_Parent(parent) { // Create Menu Widget this->CreateMenuWidget(); this->setMinimumWidth(61); // DIRTY.. If you add or remove a button, you need to change the size. this->setMaximumWidth(61); this->setAutoFillBackground(true); // Else part fixes the render window menu issue on Linux bug but caused bugs on Mac OS and Windows // for Mac OS see bug 3192 // for Windows see bug 12130 //... so Mac OS and Windows must be treated differently: #if defined(Q_OS_MAC) this->show(); this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif // this->setAttribute( Qt::WA_NoSystemBackground ); // this->setBackgroundRole( QPalette::Dark ); // this->update(); // SetOpacity -- its just posible if the widget is a window. // Windows indicates that the widget is a window, usually with a window system frame and a title bar, // irrespective of whether the widget has a parent or not. /* this->setWindowFlags( Qt::Window | Qt::FramelessWindowHint); */ // this->setAttribute(Qt::WA_TranslucentBackground); // this->setWindowOpacity(0.75); currentCrosshairRotationMode = 0; // for autorotating m_AutoRotationTimer.setInterval(75); connect(&m_AutoRotationTimer, SIGNAL(timeout()), this, SLOT(AutoRotateNextStep())); m_HideTimer.setSingleShot(true); connect(&m_HideTimer, SIGNAL(timeout()), this, SLOT(DeferredHideMenu())); connect(m_Parent, SIGNAL(destroyed()), this, SLOT(deleteLater())); } QmitkRenderWindowMenu::~QmitkRenderWindowMenu() { if (m_AutoRotationTimer.isActive()) m_AutoRotationTimer.stop(); } void QmitkRenderWindowMenu::CreateMenuWidget() { QHBoxLayout *layout = new QHBoxLayout(this); layout->setAlignment(Qt::AlignRight); layout->setContentsMargins(1, 1, 1, 1); QSize size(13, 13); m_CrosshairMenu = new QMenu(this); connect(m_CrosshairMenu, SIGNAL(aboutToShow()), this, SLOT(OnCrossHairMenuAboutToShow())); // button for changing rotation mode m_CrosshairModeButton = new QToolButton(this); m_CrosshairModeButton->setMaximumSize(15, 15); m_CrosshairModeButton->setIconSize(size); m_CrosshairModeButton->setMenu(m_CrosshairMenu); m_CrosshairModeButton->setIcon(QIcon(QPixmap(iconCrosshairMode_xpm))); m_CrosshairModeButton->setPopupMode(QToolButton::InstantPopup); m_CrosshairModeButton->setStyleSheet("QToolButton::menu-indicator { image: none; }"); m_CrosshairModeButton->setAutoRaise(true); layout->addWidget(m_CrosshairModeButton); // fullScreenButton m_FullScreenButton = new QToolButton(this); m_FullScreenButton->setMaximumSize(15, 15); m_FullScreenButton->setIconSize(size); m_FullScreenButton->setIcon(QIcon(QPixmap(iconFullScreen_xpm))); m_FullScreenButton->setAutoRaise(true); layout->addWidget(m_FullScreenButton); // settingsButton m_SettingsButton = new QToolButton(this); m_SettingsButton->setMaximumSize(15, 15); m_SettingsButton->setIconSize(size); m_SettingsButton->setIcon(QIcon(QPixmap(iconSettings_xpm))); m_SettingsButton->setAutoRaise(true); layout->addWidget(m_SettingsButton); // Create Connections -- coming soon? connect(m_FullScreenButton, SIGNAL(clicked(bool)), this, SLOT(OnFullScreenButton(bool))); connect(m_SettingsButton, SIGNAL(clicked(bool)), this, SLOT(OnSettingsButton(bool))); } void QmitkRenderWindowMenu::CreateSettingsWidget() { m_Settings = new QMenu(this); m_DefaultLayoutAction = new QAction("standard layout", m_Settings); m_DefaultLayoutAction->setDisabled(true); m_2DImagesUpLayoutAction = new QAction("2D images top, 3D bottom", m_Settings); m_2DImagesUpLayoutAction->setDisabled(false); m_2DImagesLeftLayoutAction = new QAction("2D images left, 3D right", m_Settings); m_2DImagesLeftLayoutAction->setDisabled(false); m_Big3DLayoutAction = new QAction("Big 3D", m_Settings); m_Big3DLayoutAction->setDisabled(false); m_Widget1LayoutAction = new QAction("Axial plane", m_Settings); m_Widget1LayoutAction->setDisabled(false); m_Widget2LayoutAction = new QAction("Sagittal plane", m_Settings); m_Widget2LayoutAction->setDisabled(false); m_Widget3LayoutAction = new QAction("Coronal plane", m_Settings); m_Widget3LayoutAction->setDisabled(false); m_RowWidget3And4LayoutAction = new QAction("Coronal top, 3D bottom", m_Settings); m_RowWidget3And4LayoutAction->setDisabled(false); m_ColumnWidget3And4LayoutAction = new QAction("Coronal left, 3D right", m_Settings); m_ColumnWidget3And4LayoutAction->setDisabled(false); m_SmallUpperWidget2Big3and4LayoutAction = new QAction("Sagittal top, Coronal n 3D bottom", m_Settings); m_SmallUpperWidget2Big3and4LayoutAction->setDisabled(false); m_2x2Dand3DWidgetLayoutAction = new QAction("Axial n Sagittal left, 3D right", m_Settings); m_2x2Dand3DWidgetLayoutAction->setDisabled(false); m_Left2Dand3DRight2DLayoutAction = new QAction("Axial n 3D left, Sagittal right", m_Settings); m_Left2Dand3DRight2DLayoutAction->setDisabled(false); m_Settings->addAction(m_DefaultLayoutAction); m_Settings->addAction(m_2DImagesUpLayoutAction); m_Settings->addAction(m_2DImagesLeftLayoutAction); m_Settings->addAction(m_Big3DLayoutAction); m_Settings->addAction(m_Widget1LayoutAction); m_Settings->addAction(m_Widget2LayoutAction); m_Settings->addAction(m_Widget3LayoutAction); m_Settings->addAction(m_RowWidget3And4LayoutAction); m_Settings->addAction(m_ColumnWidget3And4LayoutAction); m_Settings->addAction(m_SmallUpperWidget2Big3and4LayoutAction); m_Settings->addAction(m_2x2Dand3DWidgetLayoutAction); m_Settings->addAction(m_Left2Dand3DRight2DLayoutAction); m_Settings->setVisible(false); connect(m_DefaultLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToDefault(bool))); connect(m_2DImagesUpLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2DImagesUp(bool))); connect(m_2DImagesLeftLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2DImagesLeft(bool))); connect(m_Big3DLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToBig3D(bool))); connect(m_Widget1LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget1(bool))); connect(m_Widget2LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget2(bool))); connect(m_Widget3LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToWidget3(bool))); connect(m_RowWidget3And4LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToRowWidget3And4(bool))); connect( m_ColumnWidget3And4LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToColumnWidget3And4(bool))); connect(m_SmallUpperWidget2Big3and4LayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToSmallUpperWidget2Big3and4(bool))); connect(m_2x2Dand3DWidgetLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutTo2x2Dand3DWidget(bool))); connect( m_Left2Dand3DRight2DLayoutAction, SIGNAL(triggered(bool)), this, SLOT(OnChangeLayoutToLeft2Dand3DRight2D(bool))); } void QmitkRenderWindowMenu::paintEvent(QPaintEvent * /*e*/) { QPainter painter(this); QColor semiTransparentColor = Qt::black; semiTransparentColor.setAlpha(255); painter.fillRect(rect(), semiTransparentColor); } void QmitkRenderWindowMenu::SetLayoutIndex(unsigned int layoutIndex) { m_Layout = layoutIndex; } void QmitkRenderWindowMenu::HideMenu() { MITK_DEBUG << "menu hideEvent"; DeferredHideMenu(); } void QmitkRenderWindowMenu::ShowMenu() { MITK_DEBUG << "menu showMenu"; DeferredShowMenu(); } void QmitkRenderWindowMenu::enterEvent(QEvent * /*e*/) { MITK_DEBUG << "menu enterEvent"; DeferredShowMenu(); m_Entered = true; } void QmitkRenderWindowMenu::DeferredHideMenu() { MITK_DEBUG << "menu deferredhidemenu"; // Else part fixes the render window menu issue on Linux bug but caused bugs on Mac OS and Windows // for Mac OS see bug 3192 // for Windows see bug 12130 //... so Mac OS and Windows must be treated differently: #if defined(Q_OS_MAC) this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif // setVisible(false); // setWindowOpacity(0.0f); /// hide(); } void QmitkRenderWindowMenu::leaveEvent(QEvent * /*e*/) { MITK_DEBUG << "menu leaveEvent"; m_Entered = false; smoothHide(); } /* This method is responsible for non fluttering of the renderWindowMenu when mouse cursor moves along the renderWindowMenu*/ void QmitkRenderWindowMenu::smoothHide() { MITK_DEBUG << "menu leaveEvent"; m_HideTimer.start(10); } void QmitkRenderWindowMenu::ChangeFullScreenMode(bool state) { this->OnFullScreenButton(state); } /// \brief void QmitkRenderWindowMenu::OnFullScreenButton(bool /*checked*/) { if (!m_FullScreenMode) { m_FullScreenMode = true; m_OldLayoutDesign = m_LayoutDesign; switch (m_Layout) { case AXIAL: { emit SignalChangeLayoutDesign(LAYOUT_AXIAL); break; } case SAGITTAL: { emit SignalChangeLayoutDesign(LAYOUT_SAGITTAL); break; } case CORONAL: { emit SignalChangeLayoutDesign(LAYOUT_CORONAL); break; } case THREE_D: { emit SignalChangeLayoutDesign(LAYOUT_BIG3D); break; } } // Move Widget and show again this->MoveWidgetToCorrectPos(1.0f); // change icon this->ChangeFullScreenIcon(); } else { m_FullScreenMode = false; emit SignalChangeLayoutDesign(m_OldLayoutDesign); // Move Widget and show again this->MoveWidgetToCorrectPos(1.0f); // change icon this->ChangeFullScreenIcon(); } DeferredShowMenu(); } /// \brief void QmitkRenderWindowMenu::OnSettingsButton(bool /*checked*/) { if (m_Settings == nullptr) this->CreateSettingsWidget(); QPoint point = this->mapToGlobal(m_SettingsButton->geometry().topLeft()); m_Settings->setVisible(true); m_Settings->exec(point); } void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesUp(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2DIMAGEUP; emit SignalChangeLayoutDesign(LAYOUT_2DIMAGEUP); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutTo2DImagesLeft(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2DIMAGELEFT; emit SignalChangeLayoutDesign(LAYOUT_2DIMAGELEFT); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToDefault(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_DEFAULT; emit SignalChangeLayoutDesign(LAYOUT_DEFAULT); DeferredShowMenu(); } void QmitkRenderWindowMenu::DeferredShowMenu() { MITK_DEBUG << "deferred show menu"; m_HideTimer.stop(); // Else part fixes the render window menu issue on Linux bug but caused bugs on Mac OS and Windows // for Mac OS see bug 3192 // for Windows see bug 12130 //... so Mac OS and Windows must be treated differently: #if defined(Q_OS_MAC) this->setWindowOpacity(1.0f); #else this->setVisible(true); this->raise(); #endif } void QmitkRenderWindowMenu::OnChangeLayoutToBig3D(bool) { MITK_DEBUG << "OnChangeLayoutToBig3D"; // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_BIG3D; emit SignalChangeLayoutDesign(LAYOUT_BIG3D); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget1(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_AXIAL; emit SignalChangeLayoutDesign(LAYOUT_AXIAL); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget2(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_SAGITTAL; emit SignalChangeLayoutDesign(LAYOUT_SAGITTAL); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToWidget3(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_CORONAL; emit SignalChangeLayoutDesign(LAYOUT_CORONAL); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToRowWidget3And4(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_ROWWIDGET3AND4; emit SignalChangeLayoutDesign(LAYOUT_ROWWIDGET3AND4); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToColumnWidget3And4(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_COLUMNWIDGET3AND4; emit SignalChangeLayoutDesign(LAYOUT_COLUMNWIDGET3AND4); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToSmallUpperWidget2Big3and4(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_SMALLUPPERWIDGET2BIGAND4; emit SignalChangeLayoutDesign(LAYOUT_SMALLUPPERWIDGET2BIGAND4); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutTo2x2Dand3DWidget(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_2X2DAND3DWIDGET; emit SignalChangeLayoutDesign(LAYOUT_2X2DAND3DWIDGET); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnChangeLayoutToLeft2Dand3DRight2D(bool) { // set Full Screen Mode to false, if Layout Design was changed by the LayoutDesign_List m_FullScreenMode = false; this->ChangeFullScreenIcon(); m_LayoutDesign = LAYOUT_LEFT2DAND3DRIGHT2D; emit SignalChangeLayoutDesign(LAYOUT_LEFT2DAND3DRIGHT2D); DeferredShowMenu(); } void QmitkRenderWindowMenu::UpdateLayoutDesignList(int layoutDesignIndex) { m_LayoutDesign = layoutDesignIndex; if (m_Settings == nullptr) this->CreateSettingsWidget(); switch (m_LayoutDesign) { case LAYOUT_DEFAULT: { m_DefaultLayoutAction->setEnabled(false); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2DIMAGEUP: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(false); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2DIMAGELEFT: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(false); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_BIG3D: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(false); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_AXIAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(false); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_SAGITTAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(false); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_CORONAL: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(false); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_2X2DAND3DWIDGET: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(false); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_ROWWIDGET3AND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(false); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_COLUMNWIDGET3AND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(false); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_SMALLUPPERWIDGET2BIGAND4: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(false); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(true); break; } case LAYOUT_LEFT2DAND3DRIGHT2D: { m_DefaultLayoutAction->setEnabled(true); m_2DImagesUpLayoutAction->setEnabled(true); m_2DImagesLeftLayoutAction->setEnabled(true); m_Big3DLayoutAction->setEnabled(true); m_Widget1LayoutAction->setEnabled(true); m_Widget2LayoutAction->setEnabled(true); m_Widget3LayoutAction->setEnabled(true); m_RowWidget3And4LayoutAction->setEnabled(true); m_ColumnWidget3And4LayoutAction->setEnabled(true); m_SmallUpperWidget2Big3and4LayoutAction->setEnabled(true); m_2x2Dand3DWidgetLayoutAction->setEnabled(true); m_Left2Dand3DRight2DLayoutAction->setEnabled(false); break; } } } #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float opacity) #else void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float /*opacity*/) #endif { #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU int X = floor(double(this->m_Parent->width() - this->width() - 8.0)); int Y = 7; QPoint pos = this->m_Parent->mapToGlobal(QPoint(0, 0)); this->move(X + pos.x(), Y + pos.y()); if (opacity < 0) opacity = 0; else if (opacity > 1) opacity = 1; this->setWindowOpacity(opacity); #else int moveX = floor(double(this->m_Parent->width() - this->width() - 4.0)); this->move(moveX, 3); this->show(); #endif } void QmitkRenderWindowMenu::ChangeFullScreenIcon() { m_FullScreenButton->setIcon(m_FullScreenMode ? QPixmap(iconLeaveFullScreen_xpm) : QPixmap(iconFullScreen_xpm)); } void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction *action) { MITK_DEBUG << "selected crosshair mode " << action->data().toInt(); emit ChangeCrosshairRotationMode(action->data().toInt()); } void QmitkRenderWindowMenu::SetCrossHairVisibility(bool state) { if (m_Renderer.IsNotNull()) { mitk::DataNode *n; if (this->m_MultiWidget) { n = this->m_MultiWidget->GetWidgetPlane1(); if (n) n->SetVisibility(state); n = this->m_MultiWidget->GetWidgetPlane2(); if (n) n->SetVisibility(state); n = this->m_MultiWidget->GetWidgetPlane3(); if (n) n->SetVisibility(state); m_Renderer->GetRenderingManager()->RequestUpdateAll(); } } } void QmitkRenderWindowMenu::OnTSNumChanged(int num) { MITK_DEBUG << "Thickslices num: " << num << " on renderer " << m_Renderer.GetPointer(); if (m_Renderer.IsNotNull()) { if (num == 0) { m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New(0)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(num)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(false)); } else { m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New(1)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(num)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(true)); } m_TSLabel->setText(QString::number(num * 2 + 1)); m_Renderer->SendUpdateSlice(); m_Renderer->GetRenderingManager()->RequestUpdateAll(); } } void QmitkRenderWindowMenu::OnCrossHairMenuAboutToShow() { QMenu *crosshairModesMenu = m_CrosshairMenu; crosshairModesMenu->clear(); QAction *resetViewAction = new QAction(crosshairModesMenu); resetViewAction->setText("Reset view"); crosshairModesMenu->addAction(resetViewAction); connect(resetViewAction, SIGNAL(triggered()), this, SIGNAL(ResetView())); // Show hide crosshairs { bool currentState = true; if (m_Renderer.IsNotNull()) { mitk::DataStorage *ds = m_Renderer->GetDataStorage(); mitk::DataNode *n; if (ds) { n = this->m_MultiWidget->GetWidgetPlane1(); if (n) { bool v; if (n->GetVisibility(v, nullptr)) currentState &= v; } n = this->m_MultiWidget->GetWidgetPlane2(); if (n) { bool v; if (n->GetVisibility(v, nullptr)) currentState &= v; } n = this->m_MultiWidget->GetWidgetPlane3(); if (n) { bool v; if (n->GetVisibility(v, nullptr)) currentState &= v; } } } QAction *showHideCrosshairVisibilityAction = new QAction(crosshairModesMenu); showHideCrosshairVisibilityAction->setText("Show crosshair"); showHideCrosshairVisibilityAction->setCheckable(true); showHideCrosshairVisibilityAction->setChecked(currentState); crosshairModesMenu->addAction(showHideCrosshairVisibilityAction); connect(showHideCrosshairVisibilityAction, SIGNAL(toggled(bool)), this, SLOT(SetCrossHairVisibility(bool))); } // Rotation mode { QAction *rotationGroupSeparator = new QAction(crosshairModesMenu); rotationGroupSeparator->setSeparator(true); rotationGroupSeparator->setText("Rotation mode"); crosshairModesMenu->addAction(rotationGroupSeparator); QActionGroup *rotationModeActionGroup = new QActionGroup(crosshairModesMenu); rotationModeActionGroup->setExclusive(true); QAction *noCrosshairRotation = new QAction(crosshairModesMenu); noCrosshairRotation->setActionGroup(rotationModeActionGroup); noCrosshairRotation->setText("No crosshair rotation"); noCrosshairRotation->setCheckable(true); noCrosshairRotation->setChecked(currentCrosshairRotationMode == 0); noCrosshairRotation->setData(0); crosshairModesMenu->addAction(noCrosshairRotation); QAction *singleCrosshairRotation = new QAction(crosshairModesMenu); singleCrosshairRotation->setActionGroup(rotationModeActionGroup); singleCrosshairRotation->setText("Crosshair rotation"); singleCrosshairRotation->setCheckable(true); singleCrosshairRotation->setChecked(currentCrosshairRotationMode == 1); singleCrosshairRotation->setData(1); crosshairModesMenu->addAction(singleCrosshairRotation); QAction *coupledCrosshairRotation = new QAction(crosshairModesMenu); coupledCrosshairRotation->setActionGroup(rotationModeActionGroup); coupledCrosshairRotation->setText("Coupled crosshair rotation"); coupledCrosshairRotation->setCheckable(true); coupledCrosshairRotation->setChecked(currentCrosshairRotationMode == 2); coupledCrosshairRotation->setData(2); crosshairModesMenu->addAction(coupledCrosshairRotation); QAction *swivelMode = new QAction(crosshairModesMenu); swivelMode->setActionGroup(rotationModeActionGroup); swivelMode->setText("Swivel mode"); swivelMode->setCheckable(true); swivelMode->setChecked(currentCrosshairRotationMode == 3); swivelMode->setData(3); crosshairModesMenu->addAction(swivelMode); connect( rotationModeActionGroup, SIGNAL(triggered(QAction *)), this, SLOT(OnCrosshairRotationModeSelected(QAction *))); } // auto rotation support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D) { QAction *autoRotationGroupSeparator = new QAction(crosshairModesMenu); autoRotationGroupSeparator->setSeparator(true); crosshairModesMenu->addAction(autoRotationGroupSeparator); QAction *autoRotationAction = crosshairModesMenu->addAction("Auto Rotation"); autoRotationAction->setCheckable(true); autoRotationAction->setChecked(m_AutoRotationTimer.isActive()); connect(autoRotationAction, SIGNAL(triggered()), this, SLOT(OnAutoRotationActionTriggered())); } // Thickslices support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { QAction *thickSlicesGroupSeparator = new QAction(crosshairModesMenu); thickSlicesGroupSeparator->setSeparator(true); thickSlicesGroupSeparator->setText("ThickSlices mode"); crosshairModesMenu->addAction(thickSlicesGroupSeparator); QActionGroup *thickSlicesActionGroup = new QActionGroup(crosshairModesMenu); thickSlicesActionGroup->setExclusive(true); int currentMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices")); if (m.IsNotNull()) currentMode = m->GetValueAsId(); } int currentNum = 1; { mitk::IntProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices.num")); if (m.IsNotNull()) { currentNum = m->GetValue(); if (currentNum < 1) currentNum = 1; if (currentNum > 10) currentNum = 10; } } if (currentMode == 0) currentNum = 0; QSlider *m_TSSlider = new QSlider(crosshairModesMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(9); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect(m_TSSlider, SIGNAL(valueChanged(int)), this, SLOT(OnTSNumChanged(int))); QHBoxLayout *_TSLayout = new QHBoxLayout; _TSLayout->setContentsMargins(4, 4, 4, 4); _TSLayout->addWidget(new QLabel("TS: ")); _TSLayout->addWidget(m_TSSlider); _TSLayout->addWidget(m_TSLabel = new QLabel(QString::number(currentNum * 2 + 1), this)); QWidget *_TSWidget = new QWidget; _TSWidget->setLayout(_TSLayout); QWidgetAction *m_TSSliderAction = new QWidgetAction(crosshairModesMenu); m_TSSliderAction->setDefaultWidget(_TSWidget); crosshairModesMenu->addAction(m_TSSliderAction); } } void QmitkRenderWindowMenu::NotifyNewWidgetPlanesMode(int mode) { currentCrosshairRotationMode = mode; } void QmitkRenderWindowMenu::OnAutoRotationActionTriggered() { if (m_AutoRotationTimer.isActive()) { m_AutoRotationTimer.stop(); m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOff(); } else { m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOn(); m_AutoRotationTimer.start(); } } void QmitkRenderWindowMenu::AutoRotateNextStep() { if (m_Renderer->GetCameraRotationController()) m_Renderer->GetCameraRotationController()->GetSlice()->Next(); } diff --git a/Modules/QtWidgets/src/mitkDataStorageInspectorGenerator.cpp b/Modules/QtWidgets/src/mitkDataStorageInspectorGenerator.cpp new file mode 100644 index 0000000000..2439f4792f --- /dev/null +++ b/Modules/QtWidgets/src/mitkDataStorageInspectorGenerator.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 "mitkDataStorageInspectorGenerator.h" + +mitk::IDataStorageInspectorProvider* mitk::DataStorageInspectorGenerator::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; +}; + +mitk::DataStorageInspectorGenerator::ProviderMapType mitk::DataStorageInspectorGenerator::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; +}; + +mitk::DataStorageInspectorGenerator::DataStorageInspectorGenerator() += default; + +mitk::DataStorageInspectorGenerator::~DataStorageInspectorGenerator() += default; \ No newline at end of file diff --git a/Modules/Chart/src/QmitkChartData.cpp b/Modules/QtWidgets/src/mitkIDataStorageInspectorProvider.cpp similarity index 62% copy from Modules/Chart/src/QmitkChartData.cpp copy to Modules/QtWidgets/src/mitkIDataStorageInspectorProvider.cpp index 2dabbc46aa..65027755c7 100644 --- a/Modules/Chart/src/QmitkChartData.cpp +++ b/Modules/QtWidgets/src/mitkIDataStorageInspectorProvider.cpp @@ -1,27 +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 +#include "mitkIDataStorageInspectorProvider.h" -QmitkChartData::QmitkChartData() : m_ShowSubchart(true), m_YAxisScale("") +namespace mitk { -} + IDataStorageInspectorProvider::~IDataStorageInspectorProvider() {} + + std::string mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + { + static std::string s = "org.mitk.IDataStorageInspectorProvider.inspectorid"; + return s; + } -void QmitkChartData::SetAppearance(bool showSubChart, bool usePercentageInPieChart) -{ - m_ShowSubchart = showSubChart; - m_UsePercentageInPieChart = usePercentageInPieChart; } \ No newline at end of file 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..c2b3e7465d --- /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 "mitkIDataStorageInspectorProvider.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/RenderWindowManager/files.cmake b/Modules/RenderWindowManager/files.cmake index 5e95f08b7a..8d8bb99f84 100644 --- a/Modules/RenderWindowManager/files.cmake +++ b/Modules/RenderWindowManager/files.cmake @@ -1,19 +1,11 @@ set(H_FILES - include/QmitkRenderWindowDataModel.h - include/mitkRenderWindowLayerController.h - include/mitkRenderWindowViewDirectionController.h - include/mitkRenderWindowLayerUtilities.h + include/mitkRenderWindowViewDirectionController.h + include/mitkRenderWindowLayerUtilities.h ) set(CPP_FILES - QmitkRenderWindowDataModel.cpp - - mitkRenderWindowLayerController.cpp - mitkRenderWindowViewDirectionController.cpp - mitkRenderWindowLayerUtilities.cpp -) - -set(MOC_H_FILES - include/QmitkRenderWindowDataModel.h + mitkRenderWindowLayerController.cpp + mitkRenderWindowViewDirectionController.cpp + mitkRenderWindowLayerUtilities.cpp ) diff --git a/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h b/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h deleted file mode 100644 index b96a518bc2..0000000000 --- a/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h +++ /dev/null @@ -1,69 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef QMITKRENDERWINDOWDATAMODEL_H -#define QMITKRENDERWINDOWDATAMODEL_H - -// render window manager module -#include "MitkRenderWindowManagerExports.h" -#include "mitkRenderWindowLayerUtilities.h" - -//mitk core -#include -#include - -// qt -#include - -/* -* @brief This class extends the 'QAbstractTableModel' to meet the specific requirements of the QmitkRenderWindowDataModel. -*/ -class MITKRENDERWINDOWMANAGER_EXPORT QmitkRenderWindowDataModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - - QmitkRenderWindowDataModel(QObject* parent = nullptr); - ~QmitkRenderWindowDataModel() override; - - ////////////////////////////////////////////////////////////////////////// - /// overridden functions from QAbstractItemModel - ////////////////////////////////////////////////////////////////////////// - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - ////////////////////////////////////////////////////////////////////////// - /// end override - ///////////////////////////////////////////////////////////////////////// - - void SetDataStorage(mitk::DataStorage::Pointer dataStorage); - void SetCurrentRenderer(std::string rendererName); - mitk::BaseRenderer* GetCurrentRenderer() const { return m_BaseRenderer.GetPointer(); } - void DataChanged(const mitk::DataNode* dataNode); - -private: - - mitk::DataStorage::Pointer m_DataStorage; - mitk::BaseRenderer::Pointer m_BaseRenderer; - RenderWindowLayerUtilities::LayerStack m_TempLayerStack; - -}; - -#endif // QMITKRENDERWINDOWDATAMODEL_H diff --git a/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp b/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp deleted file mode 100644 index a8888f8042..0000000000 --- a/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -// render window manager UI module -#include "QmitkRenderWindowDataModel.h" - -#include "QmitkCustomVariants.h" - -QmitkRenderWindowDataModel::QmitkRenderWindowDataModel(QObject* parent /*= nullptr*/) - : QAbstractTableModel(parent) -{ - // nothing here -} - -QmitkRenderWindowDataModel::~QmitkRenderWindowDataModel() -{ - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } -} - -int QmitkRenderWindowDataModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const -{ - if (parent.isValid()) - { - return 0; - } - - return static_cast(m_TempLayerStack.size()); -} - -int QmitkRenderWindowDataModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const -{ - if (parent.isValid()) - { - return 0; - } - - return 2; -} - -QVariant QmitkRenderWindowDataModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - { - return QVariant(); - } - - if ((index.row()) < static_cast(m_TempLayerStack.size())) - { - RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); - std::advance(layerStackIt, index.row()); - mitk::DataNode* dataNode = layerStackIt->second; - if (Qt::CheckStateRole == role && 0 == index.column()) - { - bool visibility = false; - dataNode->GetVisibility(visibility, m_BaseRenderer); - if (visibility) - { - return Qt::Checked; - } - else - { - return Qt::Unchecked; - } - } - else if (Qt::DisplayRole == role && 1 == index.column()) - { - return QVariant(QString::fromStdString(dataNode->GetName())); - } - else if (Qt::ToolTipRole == role) - { - if (0 == index.column()) - { - return QVariant("Show/hide data node."); - } - else if (1 == index.column()) - { - return QVariant("Name of the data node."); - } - } - else if (Qt::UserRole == role) - { - // user role always returns a reference to the data node, - // which can be used to modify the data node in the data storage - return QVariant::fromValue(dataNode); - } - } - return QVariant(); -} - -Qt::ItemFlags QmitkRenderWindowDataModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; - if (0 == index.column()) - { - flags |= Qt::ItemIsUserCheckable; - } - - return flags; -} - -QVariant QmitkRenderWindowDataModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (Qt::Horizontal == orientation && Qt::DisplayRole == role) - { - if (0 == section) - { - return QVariant("Visibility"); - } - else if (1 == section) - { - return QVariant("Data node"); - } - } - return QVariant(); -} - -bool QmitkRenderWindowDataModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/) -{ - if (!index.isValid()) - { - return false; - } - - if ((index.row()) < static_cast(m_TempLayerStack.size())) - { - RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); - std::advance(layerStackIt, index.row()); - mitk::DataNode* dataNode = layerStackIt->second; - if (Qt::CheckStateRole == role) - { - Qt::CheckState newCheckState = static_cast(value.toInt()); - - if (Qt::PartiallyChecked == newCheckState || Qt::Checked == newCheckState) - { - dataNode->SetVisibility(true, m_BaseRenderer); - } - else - { - dataNode->SetVisibility(false, m_BaseRenderer); - } - emit dataChanged(index, index); - mitk::RenderingManager::GetInstance()->RequestUpdate(m_BaseRenderer->GetRenderWindow()); - return true; - } - } - return false; -} - -void QmitkRenderWindowDataModel::SetDataStorage(mitk::DataStorage::Pointer dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // given data storage is a new data storage - if (m_DataStorage.IsNotNull()) - { - // remove listener from old data storage - m_DataStorage->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } - // set the new data storage - m_DataStorage = dataStorage; - // register new data storage listener - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->ChangedNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } - DataChanged(nullptr); - } -} - -void QmitkRenderWindowDataModel::SetCurrentRenderer(std::string renderWindowName) -{ - m_BaseRenderer = mitk::BaseRenderer::GetByName(renderWindowName); - if (m_DataStorage.IsNotNull()) - { - DataChanged(nullptr); - } -} - -void QmitkRenderWindowDataModel::DataChanged(const mitk::DataNode* /*dataNode*/) -{ - if (m_BaseRenderer.IsNotNull()) - { - // update the model, so that the table will be filled with the nodes information of the new data storage - beginResetModel(); - // get the current layer stack of the given base renderer - m_TempLayerStack = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, m_BaseRenderer, true); - endResetModel(); - } -} diff --git a/Modules/RenderWindowManagerUI/files.cmake b/Modules/RenderWindowManagerUI/files.cmake index a998c3cf7f..a350cab98c 100644 --- a/Modules/RenderWindowManagerUI/files.cmake +++ b/Modules/RenderWindowManagerUI/files.cmake @@ -1,15 +1,18 @@ set(H_FILES include/QmitkRenderWindowManipulatorWidget.h + include/QmitkDataStorageLayerStackModel.h ) set(CPP_FILES QmitkRenderWindowManipulatorWidget.cpp + QmitkDataStorageLayerStackModel.cpp ) set(MOC_H_FILES include/QmitkRenderWindowManipulatorWidget.h + include/QmitkDataStorageLayerStackModel.h ) set(UI_FILES src/QmitkRenderWindowManipulatorWidget.ui ) \ No newline at end of file diff --git a/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h b/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h new file mode 100644 index 0000000000..d106d23db8 --- /dev/null +++ b/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h @@ -0,0 +1,93 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGELAYERSTACKMODEL_H +#define QMITKDATASTORAGELAYERSTACKMODEL_H + +// render window manager UI module +#include "MitkRenderWindowManagerUIExports.h" + +// render window manager module +#include "mitkRenderWindowLayerUtilities.h" + +// qt widgets module +#include + +/** +* @brief The 'QmitkDataStorageLayerStackModel' is a customized table model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a customized qt table model. +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +*/ +class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkDataStorageLayerStackModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkDataStorageLayerStackModel(QObject* parent = nullptr); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + void SetCurrentRenderer(const std::string& rendererName); + + mitk::BaseRenderer* GetCurrentRenderer() const; + + ////////////////////////////////////////////////////////////////////////// + /// overridden functions from QAbstractItemModel + ////////////////////////////////////////////////////////////////////////// + QModelIndex index(int row, int column, const QModelIndex& parent) const; + QModelIndex parent(const QModelIndex& child) const; + Qt::ItemFlags flags(const QModelIndex& index) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role) const override; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + ////////////////////////////////////////////////////////////////////////// + /// end override + ///////////////////////////////////////////////////////////////////////// + +private: + + void UpdateModelData(); + + mitk::WeakPointer m_BaseRenderer; + RenderWindowLayerUtilities::LayerStack m_TempLayerStack; + +}; + +#endif // QMITKDATASTORAGELAYERSTACKMODEL_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h index e08edafbce..c863b88052 100644 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h @@ -1,108 +1,114 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWMANIPULATORWIDGET_H #define QMITKRENDERWINDOWMANIPULATORWIDGET_H // render window manager UI module #include "MitkRenderWindowManagerUIExports.h" #include "ui_QmitkRenderWindowManipulatorWidget.h" +#include // render window manager module #include #include -#include // qt #include /** * The QmitkRenderWindowManipulatorWidget offers a GUI to manipulate the base renderer / render windows of the MITK workbench. * The widgets supports adding a layer to an active render window, moving layers up and down, removing layers, * resetting layers (hiding them) or removing all layers at once. * * In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to * a render window layer controller and a render window view direction controller. * The plugin also has to provide a Q_SLOT that is connected to the 'AddLayerButtonClicked'-Q_SIGNAL of this widget. * This allows for a customized add-layer functionality. */ class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowManipulatorWidget : public QWidget { Q_OBJECT public: QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent = nullptr); /** + * @brief Get the table view that displays the layer stack inside this widget + */ + QTableView* GetLayerStackTableView(); + /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); /** * @brief Set the currently selected render window * * @param renderWindowId the text inside the combo box */ void SetActiveRenderWindow(const QString &renderWindowId); /** * @brief Use the RenderWindowLayerController to insert the given data node into the currently active render window. * The new node is placed on top of all existing layer nodes in that render window. * * @param dataNode The data node that should be inserted. */ void AddLayer(mitk::DataNode* dataNode); /** * @brief Use the RenderWindowLayerController to insert the given data node into all controlled render windows. * The new node is placed on top of all existing layer nodes in the render window. * * @param dataNode The data node that should be inserted. */ void AddLayerToAllRenderer(mitk::DataNode* dataNode); /** * @brief Use the RenderWindowLayerController to hide the given data node in the currently active render window. * * @param dataNode The data node that should be hid. */ void HideDataNodeInAllRenderer(const mitk::DataNode* dataNode); Q_SIGNALS: + void AddLayerButtonClicked(); private Q_SLOTS: void RemoveLayer(); void SetAsBaseLayer(); void MoveLayer(const QString &direction); void ResetRenderer(); void ClearRenderer(); void ChangeViewDirection(const QString &viewDirection); private: void Init(); void SetUpConnections(); Ui::QmitkRenderWindowManipulatorWidget m_Controls; mitk::DataStorage::Pointer m_DataStorage; - std::unique_ptr m_RenderWindowDataModel; std::unique_ptr m_RenderWindowLayerController; std::unique_ptr m_RenderWindowViewDirectionController; + + QmitkDataStorageLayerStackModel* m_StorageModel; }; #endif // QMITKRENDERWINDOWMANIPULATORWIDGET_H diff --git a/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp new file mode 100644 index 0000000000..e4f627fffc --- /dev/null +++ b/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp @@ -0,0 +1,238 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkDataStorageLayerStackModel::QmitkDataStorageLayerStackModel(QObject* parent/* = nullptr*/) + : QmitkAbstractDataStorageModel(parent) +{ + // nothing here +} + +void QmitkDataStorageLayerStackModel::DataStorageChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodeAdded(const mitk::DataNode* /*node*/) +{ + // nothing here; layers (nodes) are only added after button click +} + +void QmitkDataStorageLayerStackModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::SetCurrentRenderer(const std::string& renderWindowName) +{ + if (!m_DataStorage.IsExpired()) + { + m_BaseRenderer = mitk::BaseRenderer::GetByName(renderWindowName); + UpdateModelData(); + } +} + +mitk::BaseRenderer* QmitkDataStorageLayerStackModel::GetCurrentRenderer() const +{ + return m_BaseRenderer.Lock(); +} + +QModelIndex QmitkDataStorageLayerStackModel::index(int row, int column, const QModelIndex& parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageLayerStackModel::parent(const QModelIndex& /*child*/) const +{ + return QModelIndex(); +} + +Qt::ItemFlags QmitkDataStorageLayerStackModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = Qt::NoItemFlags; + if (index.isValid() && index.model() == this) + { + flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if (0 == index.column()) + { + flags |= Qt::ItemIsUserCheckable; + } + } + + return flags; +} + +QVariant QmitkDataStorageLayerStackModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (Qt::Horizontal == orientation && Qt::DisplayRole == role) + { + if (0 == section) + { + return QVariant("Visibility"); + } + else if (1 == section) + { + return QVariant("Data node"); + } + } + return QVariant(); +} + +int QmitkDataStorageLayerStackModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return static_cast(m_TempLayerStack.size()); +} + +int QmitkDataStorageLayerStackModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return 2; +} + +QVariant QmitkDataStorageLayerStackModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + if ((index.row()) < 0 || index.row() >= static_cast(m_TempLayerStack.size())) + { + return QVariant(); + } + + RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + if (Qt::CheckStateRole == role && 0 == index.column()) + { + bool visibility = false; + dataNode->GetVisibility(visibility, m_BaseRenderer.Lock()); + if (visibility) + { + return Qt::Checked; + } + else + { + return Qt::Unchecked; + } + } + else if (Qt::DisplayRole == role && 1 == index.column()) + { + return QVariant(QString::fromStdString(dataNode->GetName())); + } + else if (Qt::ToolTipRole == role) + { + if (0 == index.column()) + { + return QVariant("Show/hide data node."); + } + else if (1 == index.column()) + { + return QVariant("Name of the data node."); + } + } + else if (QmitkDataNodeRole == role) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (QmitkDataNodeRawPointerRole == role) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +bool QmitkDataStorageLayerStackModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/) +{ + if (!index.isValid() || index.model() != this) + { + return false; + } + + if ((index.row()) < 0 || index.row() >= static_cast(m_TempLayerStack.size())) + { + return false; + } + + if (!m_BaseRenderer.IsExpired()) + { + auto baseRenderer = m_BaseRenderer.Lock(); + + RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + if (Qt::CheckStateRole == role) + { + Qt::CheckState newCheckState = static_cast(value.toInt()); + + if (Qt::PartiallyChecked == newCheckState || Qt::Checked == newCheckState) + { + dataNode->SetVisibility(true, baseRenderer); + } + else + { + dataNode->SetVisibility(false, baseRenderer); + } + emit dataChanged(index, index); + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + return true; + } + } + + return false; +} + +void QmitkDataStorageLayerStackModel::UpdateModelData() +{ + // update the model, so that the table will be filled with the nodes according to the current + // data storage and base renderer + beginResetModel(); + // get the current layer stack of the given base renderer + m_TempLayerStack = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage.Lock(), m_BaseRenderer.Lock(), true); + endResetModel(); +} diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp index c8ecd4bee7..cb8ad4eb8e 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp @@ -1,216 +1,272 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager UI module #include "QmitkRenderWindowManipulatorWidget.h" +// qt widgets module #include "QmitkCustomVariants.h" +#include "QmitkEnums.h" // mitk core #include // qt #include QmitkRenderWindowManipulatorWidget::QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent /*=nullptr*/) : QWidget(parent) , m_DataStorage(dataStorage) + , m_StorageModel(nullptr) { Init(); } void QmitkRenderWindowManipulatorWidget::Init() { - // create GUI from the Qt Designer's .ui file m_Controls.setupUi(this); // initialize the render window layer controller and the render window view direction controller // and set the controller renderer (in constructor) and the data storage m_RenderWindowLayerController = std::make_unique(); m_RenderWindowViewDirectionController = std::make_unique(); m_RenderWindowLayerController->SetDataStorage(m_DataStorage); m_RenderWindowViewDirectionController->SetDataStorage(m_DataStorage); - // create a new model - m_RenderWindowDataModel = std::make_unique(this); - m_RenderWindowDataModel->SetDataStorage(m_DataStorage); + m_Controls.layerStackTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_Controls.layerStackTableView->horizontalHeader()->setStretchLastSection(true); + m_Controls.layerStackTableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.layerStackTableView->setSelectionMode(QAbstractItemView::SingleSelection); - m_Controls.renderWindowTableView->setModel(m_RenderWindowDataModel.get()); - m_Controls.renderWindowTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_Controls.renderWindowTableView->horizontalHeader()->setStretchLastSection(true); - m_Controls.renderWindowTableView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_Controls.renderWindowTableView->setSelectionMode(QAbstractItemView::SingleSelection); + m_StorageModel = new QmitkDataStorageLayerStackModel(this); + m_StorageModel->SetDataStorage(m_DataStorage); + + m_Controls.layerStackTableView->setModel(m_StorageModel); SetUpConnections(); } void QmitkRenderWindowManipulatorWidget::SetUpConnections() { // signal to signal connection connect(m_Controls.pushButtonAddLayer, SIGNAL(clicked()), this, SIGNAL(AddLayerButtonClicked())); connect(m_Controls.pushButtonRemoveLayer, SIGNAL(clicked()), this, SLOT(RemoveLayer())); connect(m_Controls.pushButtonSetAsBaseLayer, SIGNAL(clicked()), this, SLOT(SetAsBaseLayer())); QSignalMapper* udSignalMapper = new QSignalMapper(this); udSignalMapper->setMapping(m_Controls.pushButtonMoveUp, QString("up")); udSignalMapper->setMapping(m_Controls.pushButtonMoveDown, QString("down")); connect(udSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(MoveLayer(const QString&))); connect(m_Controls.pushButtonMoveUp, SIGNAL(clicked()), udSignalMapper, SLOT(map())); connect(m_Controls.pushButtonMoveDown, SIGNAL(clicked()), udSignalMapper, SLOT(map())); connect(m_Controls.pushButtonResetRenderer, SIGNAL(clicked()), this, SLOT(ResetRenderer())); connect(m_Controls.pushButtonClearRenderer, SIGNAL(clicked()), this, SLOT(ClearRenderer())); QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); connect(changeViewDirectionSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(ChangeViewDirection(const QString&))); connect(m_Controls.radioButtonAxial, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); connect(m_Controls.radioButtonCoronal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); connect(m_Controls.radioButtonSagittal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); } +QTableView* QmitkRenderWindowManipulatorWidget::GetLayerStackTableView() +{ + return m_Controls.layerStackTableView; +} + void QmitkRenderWindowManipulatorWidget::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); } void QmitkRenderWindowManipulatorWidget::SetActiveRenderWindow(const QString &renderWindowId) { + if (nullptr == m_StorageModel) + { + return; + } + std::string currentRendererName = renderWindowId.toStdString(); - m_RenderWindowDataModel->SetCurrentRenderer(currentRendererName); + m_StorageModel->SetCurrentRenderer(currentRendererName); mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(currentRendererName); if (nullptr == selectedRenderer) { return; } mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); switch (viewDirection) { case mitk::SliceNavigationController::Axial: m_Controls.radioButtonAxial->setChecked(true); break; case mitk::SliceNavigationController::Frontal: m_Controls.radioButtonCoronal->setChecked(true); break; case mitk::SliceNavigationController::Sagittal: m_Controls.radioButtonSagittal->setChecked(true); break; default: break; } } void QmitkRenderWindowManipulatorWidget::AddLayer(mitk::DataNode* dataNode) { - m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, m_RenderWindowDataModel->GetCurrentRenderer()); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, m_StorageModel->GetCurrentRenderer()); } void QmitkRenderWindowManipulatorWidget::AddLayerToAllRenderer(mitk::DataNode* dataNode) { m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, nullptr); } void QmitkRenderWindowManipulatorWidget::HideDataNodeInAllRenderer(const mitk::DataNode* dataNode) { m_RenderWindowLayerController->HideDataNodeInAllRenderer(dataNode); } void QmitkRenderWindowManipulatorWidget::RemoveLayer() { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->RemoveLayerNode(dataNode, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + m_RenderWindowLayerController->RemoveLayerNode(dataNode, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } } } void QmitkRenderWindowManipulatorWidget::SetAsBaseLayer() { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } } } void QmitkRenderWindowManipulatorWidget::MoveLayer(const QString &direction) { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - const mitk::BaseRenderer* selectedRenderer = m_RenderWindowDataModel->GetCurrentRenderer(); + const mitk::BaseRenderer* selectedRenderer = m_StorageModel->GetCurrentRenderer(); bool success = false; if ("up" == direction) { success = m_RenderWindowLayerController->MoveNodeUp(dataNode, selectedRenderer); if (success) { // node has been successfully moved up - m_Controls.renderWindowTableView->selectRow(selectedIndex.row() - 1); + QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); + if (nullptr != tableView) + { + tableView->selectRow(selectedIndex.row() - 1); + } } } else { success = m_RenderWindowLayerController->MoveNodeDown(dataNode, selectedRenderer); if (success) { // node has been successfully moved down - m_Controls.renderWindowTableView->selectRow(selectedIndex.row() + 1); + QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); + if (nullptr != tableView) + { + tableView->selectRow(selectedIndex.row() + 1); + } } } } } } void QmitkRenderWindowManipulatorWidget::ResetRenderer() { - m_RenderWindowLayerController->ResetRenderer(true, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } void QmitkRenderWindowManipulatorWidget::ClearRenderer() { - m_RenderWindowLayerController->ResetRenderer(false, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->ResetRenderer(false, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } void QmitkRenderWindowManipulatorWidget::ChangeViewDirection(const QString &viewDirection) { - m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_RenderWindowDataModel->GetCurrentRenderer()); + if (nullptr == m_StorageModel) + { + return; + + } + + m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui index 01e6a1b05f..b0db32738a 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui @@ -1,120 +1,120 @@ QmitkRenderWindowManipulatorWidget 0 0 308 246 0 0 0 0 Render window manager Render window overview - + Add Layer Remove layer Set as base layer Move up Move down Reset render window Clear render window Axial true Coronal Sagittal diff --git a/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 48b901a8db..00920465ea 100644 --- a/Modules/US/USModel/mitkUSDevicePersistence.cpp +++ b/Modules/US/USModel/mitkUSDevicePersistence.cpp @@ -1,333 +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 - + QString::number(roi.topLeftX) + seperator - + QString::number(roi.topLeftY) + seperator - + QString::number(roi.bottomRightX) + seperator - + QString::number(roi.bottomRightY) + seperator + probes ; MITK_INFO << "Output String: " << returnValue.toStdString(); return returnValue; } QString mitk::USDevicePersistence::USProbeToString(mitk::USProbe::Pointer p) { - QString probe = p->GetName().c_str(); + 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() != 14) + 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(); - mitk::USImageVideoSource::USImageRoi cropArea; - cropArea.topLeftX = (QString(data.at(9).c_str())).toInt(); - cropArea.topLeftY = (QString(data.at(10).c_str())).toInt(); - cropArea.bottomRightX = (QString(data.at(11).c_str())).toInt(); - cropArea.bottomRightY = (QString(data.at(12).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); } - // Set Crop Area - imageSource->SetRegionOfInterest(cropArea); - std::string probes = data.at(13); + 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++) { - if (it == depthsWithSpacings.begin()) //first element is the name of the probe - { - probe->SetName(*it); - } - else //other elements are the scanning depths of the probe and the spacing + //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/US/USModel/mitkUSVideoDeviceCustomControls.cpp b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp index bf6ab39efc..72183efc48 100644 --- a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp +++ b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp @@ -1,116 +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. ===================================================================*/ #include "mitkUSVideoDeviceCustomControls.h" mitk::USVideoDeviceCustomControls::USVideoDeviceCustomControls(itk::SmartPointer device) : mitk::USAbstractControlInterface(device.GetPointer()), m_IsActive(false) { m_ImageSource = dynamic_cast(m_Device->GetUSImageSource().GetPointer()); } mitk::USVideoDeviceCustomControls::~USVideoDeviceCustomControls() { } void mitk::USVideoDeviceCustomControls::SetIsActive(bool isActive) { m_IsActive = isActive; } bool mitk::USVideoDeviceCustomControls::GetIsActive() { return m_IsActive; } void mitk::USVideoDeviceCustomControls::SetCropArea(mitk::USImageVideoSource::USImageCropping newArea) { MITK_INFO << "Set Crop Area L:" << newArea.left << " R:" << newArea.right << " T:" << newArea.top << " B:" << newArea.bottom; if (m_ImageSource.IsNotNull()) { // if area is empty, remove region if ((newArea.bottom == 0) && (newArea.top == 0) && (newArea.left == 0) && (newArea.right == 0)) { m_ImageSource->RemoveRegionOfInterest(); } else { m_ImageSource->SetCropping(newArea); } } else { MITK_WARN << "Cannot set crop are, source is not initialized!"; } } void mitk::USVideoDeviceCustomControls::SetNewDepth(double depth) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); if (device.IsNotNull()) { if( device->GetCurrentProbe().IsNotNull() ) { device->GetCurrentProbe()->SetCurrentDepth(depth); MITK_INFO << "SetCurrentDepth of currentProbe: " << depth; } } m_Device->DepthChanged(depth); } void mitk::USVideoDeviceCustomControls::SetNewProbeIdentifier(std::string probename) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); if( device.IsNotNull() ) { device->SetCurrentProbe(probename); } m_Device->ProbeChanged(probename); } -mitk::USImageVideoSource::USImageCropping mitk::USVideoDeviceCustomControls::GetCropArea() +mitk::USProbe::USProbeCropping mitk::USVideoDeviceCustomControls::GetCropArea() { // just return the crop area set at the image source - return m_ImageSource->GetCropping(); + mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); + if (device.IsNotNull()) + { + mitk::USProbe::Pointer probe = device->GetCurrentProbe(); + if (probe.IsNotNull()) + { + return probe->GetProbeCropping(); + } + } + mitk::USProbe::USProbeCropping defaultCropping; + return defaultCropping; +} + +void mitk::USVideoDeviceCustomControls::UpdateProbeCropping(mitk::USImageVideoSource::USImageCropping cropping) +{ + mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); + if (device.IsNotNull()) + { + mitk::USProbe::Pointer probe = device->GetCurrentProbe(); + if( probe.IsNotNull() ) + { + probe->SetProbeCropping(cropping.top, cropping.bottom, cropping.left, cropping.right); + } + } } std::vector mitk::USVideoDeviceCustomControls::GetProbes() { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); return device->GetAllProbes(); } std::vector mitk::USVideoDeviceCustomControls::GetDepthsForProbe(std::string name) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); mitk::USProbe::Pointer probe = device->GetProbeByName(name); std::map depthsAndSpacings = probe->GetDepthsAndSpacing(); std::vector depths; for (std::map::iterator it = depthsAndSpacings.begin(); it != depthsAndSpacings.end(); it++) { depths.push_back((it->first)); } return depths; } void mitk::USVideoDeviceCustomControls::SetDefaultProbeAsCurrentProbe() { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); device->SetDefaultProbeAsCurrentProbe(); } diff --git a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h index ce90da24b1..70b342011e 100644 --- a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h +++ b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h @@ -1,101 +1,107 @@ /*=================================================================== 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 MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ #define MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ #include "mitkUSAbstractControlInterface.h" #include "mitkUSImageVideoSource.h" #include "mitkUSVideoDevice.h" #include namespace mitk { /** * \brief Custom controls for mitk::USVideoDevice. * Controls image cropping of the corresponding mitk::USImageVideoSource. */ class MITKUS_EXPORT USVideoDeviceCustomControls : public USAbstractControlInterface { public: mitkClassMacro(USVideoDeviceCustomControls, USAbstractControlInterface); mitkNewMacro1Param(Self, itk::SmartPointer); /** * Activate or deactivate the custom controls. This is just for handling * widget visibility in a GUI for example. Cropping will not be deactivated * if this method is called with false. Use * mitk::USVideoDeviceCustomControls::SetCropArea() with an empty are * instead. */ void SetIsActive(bool isActive) override; /** * \return if this custom controls are currently activated */ bool GetIsActive() override; /** * \brief Sets the area that will be cropped from the US image. * Set [0,0,0,0] to disable it, which is also default. */ void SetCropArea(USImageVideoSource::USImageCropping newArea); /** - * \return area currently set for image cropping + * \return area currently set for image cropping defined by the actual current probe. */ - mitk::USImageVideoSource::USImageCropping GetCropArea(); + mitk::USProbe::USProbeCropping GetCropArea(); + + /** + * \brief Updates the cropping of the current probe given by the crop area of the + * USImageVideoSource. + */ + void UpdateProbeCropping( mitk::USImageVideoSource::USImageCropping cropping ); /** * \brief Sets a new depth value to the current probe. */ void SetNewDepth(double depth); /** * \ brief Sets new probe identifier */ void SetNewProbeIdentifier(std::string probename); /** *\brief Get all the probes for the current device */ std::vector GetProbes(); /** * \brief Get the scanning dephts of the given probe */ std::vector GetDepthsForProbe(std::string name); /** * \brief Sets the first existing probe or the default probe of a USVideoDevice * as the current probe of the USVideoDevice. */ void SetDefaultProbeAsCurrentProbe(); protected: /** * Class needs an mitk::USImageVideoSource object for beeing constructed. * This object will be manipulated by the custom controls methods. */ USVideoDeviceCustomControls(itk::SmartPointer device); ~USVideoDeviceCustomControls() override; bool m_IsActive; USImageVideoSource::Pointer m_ImageSource; }; } // namespace mitk #endif // MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp index 6785955e4a..132923bbc3 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp @@ -1,172 +1,181 @@ /*=================================================================== 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 "QmitkUSControlsCustomVideoDeviceWidget.h" #include "ui_QmitkUSControlsCustomVideoDeviceWidget.h" #include #include QmitkUSControlsCustomVideoDeviceWidget::QmitkUSControlsCustomVideoDeviceWidget() : ui(new Ui::QmitkUSControlsCustomVideoDeviceWidget) { } QmitkUSControlsCustomVideoDeviceWidget::QmitkUSControlsCustomVideoDeviceWidget(QWidget *parent) : QmitkUSAbstractCustomWidget(parent), ui(new Ui::QmitkUSControlsCustomVideoDeviceWidget) { m_Cropping.left = 0; m_Cropping.top = 0; m_Cropping.right = 0; m_Cropping.bottom = 0; } QmitkUSControlsCustomVideoDeviceWidget::~QmitkUSControlsCustomVideoDeviceWidget() { delete ui; } std::string QmitkUSControlsCustomVideoDeviceWidget::GetDeviceClass() const { return mitk::USVideoDevice::GetDeviceClassStatic(); } QmitkUSAbstractCustomWidget* QmitkUSControlsCustomVideoDeviceWidget::Clone(QWidget* parent) const { QmitkUSAbstractCustomWidget* clonedWidget = new QmitkUSControlsCustomVideoDeviceWidget(parent); clonedWidget->SetDevice(this->GetDevice()); return clonedWidget; } void QmitkUSControlsCustomVideoDeviceWidget::OnDeviceSet() { m_ControlInterface = dynamic_cast (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); if (m_ControlInterface.IsNotNull()) { - mitk::USImageVideoSource::USImageCropping cropping = m_ControlInterface->GetCropArea(); - ui->crop_left->setValue(cropping.left); - ui->crop_right->setValue(cropping.right); - ui->crop_bot->setValue(cropping.bottom); - ui->crop_top->setValue(cropping.top); - //get all probes and put their names into a combobox std::vector probes = m_ControlInterface->GetProbes(); for (std::vector::iterator it = probes.begin(); it != probes.end(); it++) { std::string probeName = (*it)->GetName(); ui->m_ProbeIdentifier->addItem(QString::fromUtf8(probeName.data(), probeName.size())); } m_ControlInterface->SetDefaultProbeAsCurrentProbe(); SetDepthsForProbe( ui->m_ProbeIdentifier->currentText().toStdString() ); m_ControlInterface->SetNewDepth( ui->m_UsDepth->currentText().toDouble() ); connect(ui->m_UsDepth, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnDepthChanged())); connect(ui->m_ProbeIdentifier, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnProbeChanged())); + // Call GetCropArea after the current ultrasound probe was set as default probe: + mitk::USProbe::USProbeCropping cropping = m_ControlInterface->GetCropArea(); + ui->crop_left->setValue(cropping.left); + ui->crop_right->setValue(cropping.right); + ui->crop_bot->setValue(cropping.bottom); + ui->crop_top->setValue(cropping.top); + } else { MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomVideoDeviceWidget") << "Did not get a custom video device control interface."; } ui->crop_left->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_right->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_bot->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_top->setEnabled(m_ControlInterface.IsNotNull()); } void QmitkUSControlsCustomVideoDeviceWidget::Initialize() { ui->setupUi(this); connect(ui->crop_left, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_right, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_top, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_bot, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); } void QmitkUSControlsCustomVideoDeviceWidget::OnCropAreaChanged() { if (m_ControlInterface.IsNull()) { return; } mitk::USImageVideoSource::USImageCropping cropping; cropping.left = ui->crop_left->value(); cropping.top = ui->crop_top->value(); cropping.right = ui->crop_right->value(); cropping.bottom = ui->crop_bot->value(); try { m_ControlInterface->SetCropArea(cropping); + m_ControlInterface->UpdateProbeCropping(cropping); m_Cropping = cropping; } catch (mitk::Exception e) { m_ControlInterface->SetCropArea(m_Cropping); // reset to last valid crop + m_ControlInterface->UpdateProbeCropping(m_Cropping); //reset values BlockSignalAndSetValue(ui->crop_left, m_Cropping.left); BlockSignalAndSetValue(ui->crop_right, m_Cropping.right); BlockSignalAndSetValue(ui->crop_top, m_Cropping.top); BlockSignalAndSetValue(ui->crop_bot, m_Cropping.bottom); // inform user QMessageBox msgBox; msgBox.setInformativeText("The crop area you specified is invalid.\nPlease make sure that no more pixels are cropped than are available."); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); MITK_WARN << "User tried to crop beyond limits of the image"; } } void QmitkUSControlsCustomVideoDeviceWidget::OnDepthChanged() { double depth = ui->m_UsDepth->currentText().toDouble(); MITK_INFO << "OnDepthChanged() " << depth; m_ControlInterface->SetNewDepth(depth); } void QmitkUSControlsCustomVideoDeviceWidget::OnProbeChanged() { std::string probename = ui->m_ProbeIdentifier->currentText().toStdString(); m_ControlInterface->SetNewProbeIdentifier(probename); SetDepthsForProbe(probename); + + mitk::USProbe::USProbeCropping cropping = m_ControlInterface->GetCropArea(); + ui->crop_left->setValue(cropping.left); + ui->crop_right->setValue(cropping.right); + ui->crop_bot->setValue(cropping.bottom); + ui->crop_top->setValue(cropping.top); } void QmitkUSControlsCustomVideoDeviceWidget::BlockSignalAndSetValue(QSpinBox* target, int value) { bool oldState = target->blockSignals(true); target->setValue(value); target->blockSignals(oldState); } void QmitkUSControlsCustomVideoDeviceWidget::SetDepthsForProbe(std::string probename) { ui->m_UsDepth->clear(); std::vector depths = m_ControlInterface->GetDepthsForProbe(probename); for (std::vector::iterator it = depths.begin(); it != depths.end(); it++) { ui->m_UsDepth->addItem(QString::number(*it)); } } 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 14f29d65ff..00eee0b30e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,38 +1,63 @@ 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/ImporterUtil.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..326526f925 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.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 "QmitkAbstractNodeSelectionWidget.h" + +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; + this->OnDataStorageChanged(); + this->UpdateInfo(); + } +}; + +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..4ec7267eb2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h @@ -0,0 +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. + +===================================================================*/ + + +#ifndef QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H +#define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H + +#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. The new (changed) predicate + is passed with the function call. It is the same like this->GetNodePredicate() called in the function call.*/ + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) = 0; + + /**Member is called if the data storage has changed. Thus the selection might change to.*/ + virtual void OnDataStorageChanged() = 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..a73c963a5e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp @@ -0,0 +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 "QmitkMultiNodeSelectionWidget.h" + +#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(); +}; + +void QmitkMultiNodeSelectionWidget::OnDataStorageChanged() +{ + 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..8bf5ac8715 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h @@ -0,0 +1,67 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef QMITK_MULTI_NODE_SELECTION_WIDGET_H +#define QMITK_MULTI_NODE_SELECTION_WIDGET_H + +#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; + +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) override; + virtual void OnDataStorageChanged() override; + + 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..cdba488356 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -0,0 +1,186 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkNodeSelectionDialog.h" + +#include +#include +#include + +QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent), + m_NodePredicate(nullptr), m_SelectOnlyVisibleNodes(false), m_SelectedNodes(NodeList()), m_SelectionMode(QAbstractItemView::SingleSelection) +{ + m_Controls.setupUi(this); + + auto providers = mitk::DataStorageInspectorGenerator::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..47c0118297 --- /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 + +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::OnDataStorageChanged() +{ +}; + +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..9cdccde270 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.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_SINGLE_NODE_SELECTION_WIDGET_H +#define QMITK_SINGLE_NODE_SELECTION_WIDGET_H + +#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; + +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) override; + virtual void OnDataStorageChanged() override; + + + 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/Chart/src/QmitkChartData.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp similarity index 55% copy from Modules/Chart/src/QmitkChartData.cpp copy to Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp index 2dabbc46aa..2f6a3ceaf1 100644 --- a/Modules/Chart/src/QmitkChartData.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp @@ -1,27 +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 +#include "QmitkNodeSelectionConstants.h" -QmitkChartData::QmitkChartData() : m_ShowSubchart(true), m_YAxisScale("") -{ -} - -void QmitkChartData::SetAppearance(bool showSubChart, bool usePercentageInPieChart) -{ - m_ShowSubchart = showSubChart; - m_UsePercentageInPieChart = usePercentageInPieChart; -} \ No newline at end of file +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..75d0b203d0 --- /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 = mitk::DataStorageInspectorGenerator::GetProviders(); + + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto allProviders = mitk::DataStorageInspectorGenerator::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..e07aa0a438 --- /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 "mitkDataStorageInspectorGenerator.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; + + mitk::DataStorageInspectorGenerator::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/Chart/src/QmitkChartData.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp similarity index 54% copy from Modules/Chart/src/QmitkChartData.cpp copy to Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp index 2dabbc46aa..deb5df0dc0 100644 --- a/Modules/Chart/src/QmitkChartData.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp @@ -1,27 +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 +#include "mitkPluginActivator.h" +#include "QmitkDataStorageViewerTestView.h" -QmitkChartData::QmitkChartData() : m_ShowSubchart(true), m_YAxisScale("") +namespace mitk { -} + void DataStorageViewerTestActivator::start(ctkPluginContext *context) + { + BERRY_REGISTER_EXTENSION_CLASS(QmitkDataStorageViewerTestView, context) + } -void QmitkChartData::SetAppearance(bool showSubChart, bool usePercentageInPieChart) -{ - m_ShowSubchart = showSubChart; - m_UsePercentageInPieChart = usePercentageInPieChart; -} \ No newline at end of file + 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.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui index e7196a043c..30c38e39f9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui @@ -1,299 +1,278 @@ QmitkConnectomicsDataViewControls 0 0 286 639 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a parcellation and a tractogram! Image 1: - Image 2: - Network Creation Options 6 6 6 6 Create a network from a parcellation and a fiber image Networkify Create Correlation Matrix true Synthetic Network Options 6 6 6 6 Parameter 2 false 3 999.899999999999977 Parameter 1 false 9999 Create Synthetic Networks 0 0 Anatomical labeling 6 6 6 6 Qt::Vertical 20 40 QmitkFreeSurferParcellationWidget QWidget

QmitkFreeSurferParcellationWidget.h
1 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui index 50883169d6..f82c28053d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui @@ -1,306 +1,285 @@ QmitkConnectomicsNetworkOperationsViewControls 0 0 283 639 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a network or a parcellation! Image 1: - Convert the selected image to RGBA format Turn Into RGBA Image Assign FreeSurfer Colors Divide in Modules Connectivity Matrix Image Options 6 6 6 6 Create Connectivity Matrix Image Rescale Binary Prune Options 6 6 6 6 Prune Network Target Density 1.000000000000000 0.010000000000000 Target Threshold Threshold weight Threshold Below Density Random Removal Threshold Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui index 1610d78f61..fccdcfe848 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui @@ -1,317 +1,296 @@ QmitkConnectomicsStatisticsViewControls 0 0 557 1218 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 Network: Network Statistics 6 6 6 6 true 0 0 true Informational Balloons. 6 6 6 6 false PointingHandCursor Qt::RightToLeft true false false -1 12 QComboBox::InsertAlphabetically 0 0 MS Shell Dlg 2 8 IBeamCursor false true Histograms 6 6 6 6 0 0 50 150 50 150 50 150 Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkNetworkHistogramCanvas QWidget
internal/QmitkNetworkHistogramCanvas.h
1
networkBalloonsNodeLabelsComboBox currentIndexChanged(int) networkBalloonsNodeLabelsComboBox setCurrentIndex(int) 360 409 360 409
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui index 0078a5b273..0e6a66e144 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui @@ -1,343 +1,322 @@ QmitkRandomParcellationViewControls true 0 0 327 591 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 QLabel { color: rgb(255, 0, 0) } Please select an image! true Nodes false 6 6 6 6 true Choose the number of nodes: 2 5000 true Merging 6 6 6 6 Merging on false QFrame::NoFrame QFrame::Raised 0 0 0 0 According to the number of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Number of Parcels: 1 5000 According to the size of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Size of the smallest parcel: 2 100000 Just merge small parcels false Do image processing Select random nodes Qt::Vertical 20 40 Counting 6 6 6 6 Number of voxels with value 1: Number of nodes: \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui index 7f732f0e06..f803e29af7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui @@ -1,375 +1,354 @@ QmitkDenoisingViewControls 0 0 351 734 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: Total-variation Discrete Gaussian Non-local means Filter: Parameters 6 6 6 6 Lambda: 4 0.000000000000000 1.000000000000000 0.100000000000000 0.100000000000000 Iterations: 1 999 1 Parameters 6 6 6 6 Sampling Radius: 1 999 10 1 999 4 1 999 4 Num. Patches: 1 50 1 Iterations: Patch Size: Parameters 6 6 6 6 4 1.000000000000000 99999.000000000000000 0.100000000000000 1.000000000000000 Variance: Start Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui index 9228e80e1e..b6a77c5b76 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui @@ -1,3608 +1,3687 @@ - + QmitkFiberfoxViewControls 0 0 463 875 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { - border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; -} - -QGroupBox { - background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; -} + + + + Load Parameters - :/QmitkDiffusionImaging/general_icons/upload.ico -:/QmitkDiffusionImaging/general_icons/upload.ico + :/QmitkDiffusionImaging/general_icons/upload.ico:/QmitkDiffusionImaging/general_icons/upload.ico + + + Save Parameters - :/QmitkDiffusionImaging/general_icons/download.ico -:/QmitkDiffusionImaging/general_icons/download.ico + :/QmitkDiffusionImaging/general_icons/download.ico:/QmitkDiffusionImaging/general_icons/download.ico - + + + 75 + true + + + + + + + + + 0 + 0 + 431 + 2692 + + Signal Generation 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true <html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html> + + + Start Simulation - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico + + QGroupBox { + background-color: transparent; +} + Input Data 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 - ... <html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html> QComboBox::AdjustToMinimumContentsLength - + - + - + Fiber Bundle: false - + - + - + Save path: false - + - + - + Tissue Mask: false <html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html> QComboBox::AdjustToMinimumContentsLength - + - + - + Template Image: false <html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html> QComboBox::AdjustToMinimumContentsLength true Stop current simulation. + + + Abort Simulation - :/QmitkDiffusionImaging/general_icons/abort.ico -:/QmitkDiffusionImaging/general_icons/abort.ico + :/QmitkDiffusionImaging/general_icons/abort.ico:/QmitkDiffusionImaging/general_icons/abort.ico Courier 7 true + + QGroupBox { + background-color: transparent; +} + Extra-axonal Compartments 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: - + Select signal model for extra-axonal compartment. Ball Model Astrosticks Model Dot Model Prototype Signal - + - + - + - + Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. - + - + - + Select signal model for extra-axonal compartment. -- Ball Model Astrosticks Model Dot Model Prototype Signal - + + + QGroupBox { + background-color: transparent; +} + Intra-axonal Compartment 6 6 6 6 - + - + - + Select signal model for intra-axonal compartment. Stick Model Zeppelin Model Tensor Model Prototype Signal - + QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. + + QGroupBox { + background-color: transparent; +} + Image Settings 6 6 6 6 Advanced Options QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 30 - + - + - + - <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> + <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> false b-value in s/mm² 0 10000 100 1000 color: rgb(255, 0, 0); Using geometry of selected image! color: rgb(255, 0, 0); Using gradients of selected DWI! QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - + - + - + <html><head/><body><p>Number of Channels:</p></body></html> false TR in milliseconds 1 999999999 1 4000 Output one image per compartment containing the corresponding volume fractions per voxel. Reverse Phase Encoding Direction false Signal Scale: Dwell time (time to read one line in k-space) in ms. 100.000000000000000 0.100000000000000 1.000000000000000 TE in milliseconds 1 999999999 1 100 Fiber Radius: - + - + - + Partial Fourier: false Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present. Disable Partial Volume Effects false - + - + - + <html><head/><body><p>Coil Sensitivity:</p></body></html> false Partial fourier factor (0.5-1) 3 0.500000000000000 1.000000000000000 0.100000000000000 1.000000000000000 Output phase image and volume fraction maps. Output Additional Images false Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). 1 10000 1 50 - + - + - + - <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> + <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> false Constant Linear Exponential - + - + - + Dwell Time: false - + - + - + - <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> + <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> false - <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> + <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> Simulate Signal Relaxation true - + - + - + - <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> + <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> false TE in milliseconds 1 10000 1 100 Number of coil elements used for the acquisiton. 1 128 1 1 Acquisition Type: Single Shot EPI Spin Echo Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. 9999.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 3 + + QGroupBox { + background-color: transparent; +} + Inter-axonal Compartment 6 6 6 6 Select signal model for intra-axonal compartment. -- Stick Model Zeppelin Model Tensor Model - + - + - + - + QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. + + QGroupBox { + background-color: transparent; +} + Noise and other Artifacts 6 6 6 6 Add Distortions false Add Spikes false true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 0 0 0 - + - + - + Gradient: false Eddy current induced magnetic field gradient (in mT/m). 4 1000.000000000000000 0.001000000000000 0.010000000000000 Add Motion Artifacts false Qt::Horizontal true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + K-Space Line Offset: false A larger offset increases the inensity of the ghost image. 3 1.000000000000000 0.010000000000000 0.250000000000000 Add Noise false QFrame::NoFrame QFrame::Raised 0 0 0 0 Num. Spikes: The number of randomly occurring signal spikes. 1 Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice. 0.100000000000000 0.100000000000000 Scale: true QFrame::NoFrame QFrame::Raised 0 6 0 0 6 Toggle between random movement and linear movement. Randomize motion true + + QGroupBox { + background-color: transparent; +} + Rotation 6 9 6 6 - + - + - + Degree: false - + - + - + x false - + - + - + Axis: false Maximum rotation around x-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 Maximum rotation around z-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 15.000000000000000 - + - + - + y false - + - + - + z false Maximum rotation around y-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 + + QGroupBox { + background-color: transparent; +} + Translation 6 6 6 - + - + - + Distance: false - + - + - + x false - + - + - + y false - + - + - + Axis: false - + - + - + z false Maximum translation along x-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along y-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along z-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Motion volumes: - Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes. + Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes. random Add ringing artifacts occuring at strong edges in the image. Add Gibbs Ringing false Qt::Horizontal Qt::Horizontal Qt::Horizontal Qt::Horizontal Add N/2 Ghosts false Add Aliasing false Qt::Horizontal Qt::Horizontal - + Add Eddy Current Effects false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + Shrink FOV (%): false Shrink FOV by this percentage. 1 0.000000000000000 90.000000000000000 0.100000000000000 25.000000000000000 true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + Frequency Map: false Select image specifying the frequency inhomogeneities (in Hz). QFrame::NoFrame QFrame::Raised 0 0 0 0 Variance: Variance of selected noise distribution. 10 0.000000000000000 999999999.000000000000000 0.001000000000000 50.000000000000000 Distribution: Noise distribution Complex Gaussian Rician - + + + + 0 + 0 + 431 + 979 + + Fiber Definition 25 Qt::Vertical 20 40 color: rgb(255, 0, 0); - Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. + Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true + + QGroupBox { + background-color: transparent; +} + Fiducial Options 6 6 6 6 All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. + + QCommandLinkButton:disabled { + border: none; +} + Align With Grid - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico + + QGroupBox { + background-color: transparent; +} + Operations 6 6 6 6 false + + QCommandLinkButton:disabled { + border: none; +} + Join Bundles - :/QmitkDiffusionImaging/general_icons/plus.ico -:/QmitkDiffusionImaging/general_icons/plus.ico + :/QmitkDiffusionImaging/general_icons/plus.ico:/QmitkDiffusionImaging/general_icons/plus.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 - + - + - + Y false Rotation angle (in degree) around x-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 - + - + - + Axis: false Rotation angle (in degree) around y-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 - + - + - + Translation: false Translation (in mm) in direction of the z-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 - + - + - + X false - + - + - + Rotation: false - + - + - + Z false Rotation angle (in degree) around z-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 - + - + - + Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false + + QCommandLinkButton:disabled { + border: none; +} + Copy Bundles - :/QmitkDiffusionImaging/general_icons/copy2.ico -:/QmitkDiffusionImaging/general_icons/copy2.ico + :/QmitkDiffusionImaging/general_icons/copy2.ico:/QmitkDiffusionImaging/general_icons/copy2.ico false + + QCommandLinkButton:disabled { + border: none; +} + Transform Selection - :/QmitkDiffusionImaging/general_icons/refresh.ico -:/QmitkDiffusionImaging/general_icons/refresh.ico + :/QmitkDiffusionImaging/general_icons/refresh.ico:/QmitkDiffusionImaging/general_icons/refresh.ico If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true + + QGroupBox { + background-color: transparent; +} + Fiber Options 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 - + - + - + Tension: false - + - + - + Fiber Sampling: false - + 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 - + - + - + Bias: false - + - + - + Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Distance of fiber sampling points (in mm) 1 0.100000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - + - + - + #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false + + QCommandLinkButton:disabled { + border: none; +} + Generate Fibers - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Select fiber distribution inside of the fiducials. Uniform Gaussian - + - + - + Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 - Disable to only generate fibers if "Generate Fibers" button is pressed. + Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true - Disable to only generate fibers if "Generate Fibers" button is pressed. + Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 0 0 0 false 30 30 Draw elliptical fiducial. - + - :/QmitkDiffusionImaging/circle.png -:/QmitkDiffusionImaging/circle.png + :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. - + - :/QmitkDiffusionImaging/general_icons/refresh.ico -:/QmitkDiffusionImaging/general_icons/refresh.ico + :/QmitkDiffusionImaging/general_icons/refresh.ico:/QmitkDiffusionImaging/general_icons/refresh.ico 32 32 false true Qt::Horizontal 40 20 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkTensorModelParametersWidget QWidget
QmitkTensorModelParametersWidget.h
1
QmitkStickModelParametersWidget QWidget
QmitkStickModelParametersWidget.h
1
QmitkZeppelinModelParametersWidget QWidget
QmitkZeppelinModelParametersWidget.h
1
QmitkBallModelParametersWidget QWidget
QmitkBallModelParametersWidget.h
1
QmitkAstrosticksModelParametersWidget QWidget
QmitkAstrosticksModelParametersWidget.h
1
QmitkDotModelParametersWidget QWidget
QmitkDotModelParametersWidget.h
1
QmitkPrototypeSignalParametersWidget QWidget
QmitkPrototypeSignalParametersWidget.h
1
m_CircleButton m_FlipButton m_RealTimeFibers m_AdvancedOptionsBox m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_FiberBundleComboBox m_MaskComboBox m_TemplateComboBox m_SavePathEdit m_OutputPathButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_AdvancedOptionsBox_2 m_SignalScaleBox m_TEbox m_TRbox m_LineReadoutTimeBox m_PartialFourier m_T2starBox m_FiberRadius m_ReversePhaseBox m_RelaxationBox m_EnforcePureFiberVoxelsBox m_VolumeFractionsBox m_Compartment1Box m_Comp1VolumeFraction m_Compartment2Box m_Comp2VolumeFraction m_Compartment3Box m_Comp3VolumeFraction m_Compartment4Box m_Comp4VolumeFraction m_AddNoise m_NoiseDistributionBox m_NoiseLevel m_AddSpikes m_SpikeNumBox m_SpikeScaleBox m_AddGhosts m_kOffsetBox m_AddAliasing m_WrapBox m_AddDistortions m_FrequencyMapBox m_AddMotion m_RandomMotion m_MaxRotationBoxX m_MaxRotationBoxY m_MaxRotationBoxZ m_MaxTranslationBoxX m_MaxTranslationBoxY m_MaxTranslationBoxZ m_AddEddy m_EddyGradientStrength m_AddGibbsRinging m_SaveParametersButton m_LoadParametersButton toolBox - + - -
\ No newline at end of file + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui index 58600b9fab..4f15c732be 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui @@ -1,407 +1,386 @@ QmitkFieldmapGeneratorViewControls 0 0 358 536 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Place Field Source QFrame::NoFrame QFrame::Raised 0 0 0 0 World Coordinates: - Index: - Generate Fieldmap Please Select Reference Image 6 6 6 6 Add Gradient 6 6 6 6 Gradient x: z: 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 y: 4 -1000.000000000000000 1000.000000000000000 Offset 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 Qt::Vertical QSizePolicy::Expanding 20 220 Edit Selected Source 6 6 6 6 Name: Height: Variance: - 999999.000000000000000 999999.000000000000000 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui index 83c5746932..22d11ae3eb 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui @@ -1,545 +1,524 @@ QmitkFiberClusteringViewControls 0 0 474 683 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Qt::Vertical 20 40 Metrics 6 6 6 6 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean true Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean STDEV Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean Maximum Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Inner Angles Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Distance is based on the selected parcellation. Anatomical Distance is based on the selected parcellation. Weighting factor for metric values. 1 999.000000000000000 30.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Distance is based on the scalar map values along the tract. Scalar Map Distance is based on the scalar map values along the tract. Streamline Length Input Data 6 6 6 6 Input Centroids: If set, the input tractogram is clustered around the input centroids and no new clusters are created. false 0 0 200 16777215 11 Start Tractogram: Parameters Only output clusters with ate least the specified number of fibers. 1 9999999 50 Only output the N largest clusters. Zero means no limit. 99999999 10 Min. Fibers per Cluster: Max. Clusters: Fiber Points: Merge duplicate clusters withthe specified distance threshold. If threshold is < 0, the threshold is set to half of the specified cluster size. -1.000000000000000 99999.000000000000000 0.000000000000000 Cluster Size: Cluster size in mm. 1 9999999 20 Fibers are resampled to the desired number of points for clustering. Smaller is faster but less accurate. 2 9999999 12 Merge Duplicate Clusters: Output Centroids: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui index 1712aaae56..521636a52e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui @@ -1,245 +1,224 @@ QmitkFiberFitViewControls 0 0 484 574 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 false Output Residuals: Weight for regularization. 999999.000000000000000 0.100000000000000 0.100000000000000 Tractogram: false 0 0 200 16777215 11 Start λ: Image: false Suppress Outliers: Regularization: Voxel-wise Variance Variance Mean Squared Magnitude Lasso None Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui index e155a9b83e..8a38651dfc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,1620 +1,1603 @@ - + QmitkFiberProcessingViewControls 0 0 385 684 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 + + + 75 + true + + 0 5 0 0 353 441 Fiber Extraction Extract a fiber subset from the selected fiber bundle using manually placed planar figures as waypoints or binary regions of interest. false 0 0 200 16777215 11 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Interactive Extraction 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 30 30 Draw circular ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/circle.png -:/QmitkDiffusionImaging/circle.png + :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true Qt::Horizontal 40 20 30 30 Draw polygonal ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/polygon.png -:/QmitkDiffusionImaging/polygon.png + :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png 32 32 true true 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 false 60 16777215 Create NOT composition from selected ROI. NOT false 60 16777215 Create OR composition with selected ROIs. OR Qt::Horizontal 40 20 false 60 16777215 Create AND composition with selected ROIs. AND false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. Generate ROI Image 0 0 Extract using planar figures Extract using ROI image QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. overlap: Extract fibers: Both ends true - Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". + Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". 3 1.000000000000000 0.100000000000000 0 0 Ending in ROI Not ending in ROI Passing ROI Not passing ROI Interpolate ROI true Threshold: Threshold on ROI image for positions to be considered as positive. 3 9999.000000000000000 0.100000000000000 0.500000000000000 0 0 367 408 Fiber Removal Remove fibers that satisfy certain criteria from the selected bundle. QFrame::NoFrame QFrame::Raised 0 0 0 0 If unchecked, the fiber exceeding the threshold will be split in two instead of removed. Remove Fiber false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Max. Angular Deviation: Qt::Horizontal 40 20 Maximum angular deviation in degree 180.000000000000000 0.100000000000000 30.000000000000000 Distance: Distance in mm 1 999.000000000000000 1.000000000000000 10.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 X: Y: - + - + Z: - + Angle: Angular deviation threshold in degree 1 90.000000000000000 1.000000000000000 25.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Qt::Horizontal 40 20 Minimum fiber length in mm 0 999999999 20 Max. Length: Min. Length: Maximum fiber length in mm 0 999999999 300 false 0 0 200 16777215 11 - + Remove Qt::Vertical 20 40 0 0 Remove fibers in direction Remove fibers by length Remove fibers by curvature Remove fiber parts outside mask Remove fiber parts inside mask Remove fibers by weight QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight threshold: Only fibers with weight larger than this threshold are kept. 5 99999.000000000000000 0.100000000000000 0 0 367 408 Bundle Modification Modify the selected bundle with operations such as fiber resampling, FA coloring, etc. QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Error threshold in mm: 999999999.000000000000000 0.100000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Sagittal Coronal Axial Select direction: QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 If checked, the image values are not only used to color the fibers but are also used as opaxity values. Values as opacity false - + Scalar map: The values used to color the fibers are min-max normalized. If not checked, the values should be between 0 and 1. Normalize values true 0 0 Resample fibers (spline) Resample fibers (linear) Compress fibers Color fibers by scalar map (e.g. FA) Mirror fibers Weight bundle Color fibers by curvature Color fibers by fiber weights Color fibers by length QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 0.010000000000000 999999999.000000000000000 0.100000000000000 1.000000000000000 Point distance in mm: Qt::Vertical 20 40 false 0 0 200 16777215 11 - + Execute QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight: 7 999999999.000000000000000 0.100000000000000 1.000000000000000 0 0 367 - 172 + 168 Bundle Operations Join, subtract or copy bundles. false 0 0 200 16777215 11 Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. Substract Qt::Vertical 20 40 false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Copy Please Select Input Data 6 6 6 6 - <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true - <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> + <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> true Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
- - + + - -
\ No newline at end of file + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index cd1848de92..336ebe38cd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,441 +1,440 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include // ITK #include #include #include #include -#include +#include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) , m_Visible(false) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); m_Controls->m_TractBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); m_Controls->m_TractBox->SetPredicate( isFib ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, is3D) ); connect( (QObject*)(m_Controls->m_TractBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkFiberQuantificationView::Activated() { } void QmitkFiberQuantificationView::Deactivated() { } void QmitkFiberQuantificationView::Visible() { m_Visible = true; } void QmitkFiberQuantificationView::Hidden() { m_Visible = false; } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*itk::Math::pi/180)); switch (m_Controls->m_FiberDirNormBox->currentIndex()) { case 0: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } - fOdfFilter->SetUseWorkingCopy(true); fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } Image::Pointer mitkImage = dynamic_cast(PeakImage::New().GetPointer()); mitk::CastToMitkImage(fOdfFilter->GetDirectionImage(), mitkImage); mitkImage->SetVolume(fOdfFilter->GetDirectionImage()->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } void QmitkFiberQuantificationView::UpdateGui() { m_SelectedFB.clear(); if (m_Controls->m_TractBox->GetSelectedNode().IsNotNull()) m_SelectedFB.push_back(m_Controls->m_TractBox->GetSelectedNode()); m_SelectedImage = nullptr; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_SelectedImage = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_SelectedImage.IsNotNull()) { mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); multilabelImage->InitializeByLabeledImage(img); mitk::Label::Pointer label = multilabelImage->GetActiveLabel(); label->SetName("Tractogram"); // label->SetColor(color); label->SetValue(1); // multilabelImage->GetActiveLabelSet()->AddLabel(label); multilabelImage->GetActiveLabelSet()->SetActiveLabel(1); PropertyList::Pointer dicomSegPropertyList = mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentationProperties(m_SelectedImage->GetPropertyList()); multilabelImage->GetPropertyList()->ConcatenatePropertyList(dicomSegPropertyList); mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentProperties(multilabelImage->GetActiveLabel(multilabelImage->GetActiveLayer())); // init data node node->SetData(multilabelImage); } else { // init data node node->SetData(img); } } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui index bd45e43f55..a2cd04430c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui @@ -1,441 +1,420 @@ QmitkFiberQuantificationViewControls 0 0 365 581 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Fiber-derived images 6 6 6 6 false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image 0 0 Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset Principal Fiber Directions 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 Fiber directions with an angle smaller than the defined threshold are clustered. 2 0.000000000000000 90.000000000000000 1.000000000000000 30.000000000000000 0 0 <html><head/><body><p>Directions shorter than the defined threshold are discarded.</p></body></html> 3 1.000000000000000 0.100000000000000 0.300000000000000 Angular Threshold: Max. Peaks: Size Threshold: 0 0 Maximum number of fiber directions per voxel. 100 3 Normalization: 0 0 0 Global maximum Single vector Voxel-wise maximum 0 0 Image containing the number of distinct fiber clusters per voxel. Output #Directions per Voxel false false Generate Directions Input Data 6 6 6 6 Tractogram: Reference Image: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/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.fiberprocessing/src/internal/QmitkTractometryViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui index fe454057d0..22b1a6a4e1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui @@ -1,157 +1,136 @@ QmitkTractometryViewControls 0 0 484 574 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Input Image: 3 99999 100 Sampling Points: Qt::Vertical 20 40 0 100 Show STDEV true QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkChartWidget QWidget
QmitkChartWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui index b83e5d07d1..3d114861ae 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui @@ -1,1208 +1,1187 @@ QmitkIVIMViewControls 0 0 423 1563 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 9 Intra Voxel Incoherent Motion Estimation 6 9 6 6 Input Data 6 6 6 6 Optional ROI image ROI: DWI to analyze Raw DWI: QFrame::NoFrame QFrame::Raised 0 0 0 0 warning display Qt::RichText true 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 0 IVIM Parameters 9 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 D* 100 60 Qt::Horizontal 51 16777215 200 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 neglect b< 250 34 Qt::Horizontal 51 16777215 46.5 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 #iterations 100 10 Qt::Horizontal 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 lambda 1000 10 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Plain 0 0 0 0 0 80 16777215 neglect Si< 100 0 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Raised 0 0 0 0 80 0 Output Images f true D false D* false true 0 0 0 400 Choose Method 2 3 Param. Fit Fit D & f with fixed D* value Fit D & f (high b), then fit D* Linearly fit D & f (high b), then fit D* Regularized Kurtosis QFrame::StyledPanel QFrame::Raised 2 2 2 2 2 Smoothing sigma Select Fit Type Omit b=0 Measurement 80 0 Output Images Force the fitting of K to remain within the given boundaries Boundaries for K Select if the data is fitted directly (straight) or the logarithmic equation is used Straight Fit Logarithmic Fit 2 QLayout::SetMaximumSize D false K true Signa for gaussian smoothing applied prior to map computation 0.000000000000000 5.000000000000000 0.100000000000000 On 0 0 0 400 Generate Output Images QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Datapoints to Clipboard Parameters to Clipboard QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkIVIMWidget QWidget
QmitkIVIMWidget.h
1
QmitkKurtosisWidget QWidget
QmitkKurtosisWidget.h
1
ctkRangeWidget QWidget
ctkRangeWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui index dc363b8334..80d9d455b5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,497 +1,476 @@ QmitkOdfMaximaExtractionViewControls 0 0 397 848 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Generate ODF image and MITK compatible SH coefficient from other toolkits. Start SH Coefficient Import true Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Peak Extraction Please Select Input Data 6 6 6 6 Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: Additional Output QFormLayout::AllNonFixedFieldsGrow 6 6 6 6 Output unsigned char image containing the number of directions per voxel. #Peaks per Voxel false Parameters 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Vector Normalization: <html><head/><body><p>The vector fields are always coorected for image spacing and using the lagest eigenvalue in case of the tensor peak extraction. This is done for visualizytion purposes. The output direction images are not affected.</p></body></html> 1 No Normalization MAX Normalize Single Vec Normalization true QFrame::NoFrame QFrame::Raised 0 0 0 0 6 true Max. Peaks: Relative Threshold: true Peak threshold relative to the largest peak per voxel. 3 0.000000000000000 1.000000000000000 0.100000000000000 0.500000000000000 true Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.010000000000000 0.030000000000000 true Maximum number of peaks to extract. 1 1000 3 Clustering Angle: Cluster close directions. Define "close" here. 90 30 Absolute Threshold: Angular Threshold: Discard smaller peaks in the defined angle around the maximum peaks that were too far away to be clustered. 0 90 0 Qt::Vertical 20 259 Spherical Harmonic Convention 6 6 6 6 Define SH coefficient convention (depends on toolkit) 0 MITK/MRtrix FSL QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui index baec9ccaa4..418ffce5e5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui @@ -1,879 +1,858 @@ QmitkPartialVolumeAnalysisViewControls true 0 0 360 565 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 9 3 9 3 Data 0 0 Tensor/Scalar Image: 0 0 Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> Parameters QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 0 false QFrame::NoFrame QFrame::Raised 0 30 30 Draw circular ROI :/QmitkDiffusionImaging/circle.png :/QmitkDiffusionImaging/circle.png 32 32 true true 30 30 Draw quadratic ROI :/QmitkDiffusionImaging/rectangle.png :/QmitkDiffusionImaging/rectangle.png 32 32 true true 30 30 Draw polygonal ROI :/QmitkDiffusionImaging/polygon.png :/QmitkDiffusionImaging/polygon.png 32 32 true true Qt::Horizontal 40 20 true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Upsampling QFrame::NoFrame QFrame::Raised 0 1 50 1 25 Qt::Horizontal 50 0 2.5 Similar angles QFrame::NoFrame 0 90 0 Qt::Horizontal QSlider::NoTicks 50 0 90° QFrame::NoFrame QFrame::Raised 0 0 display histogram true 0 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 20 20 true true Green Partial Volume Partial Volume Partial Volume Partial Volume PV Red true All Export clustering result as float image. ... :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png QFrame::NoFrame 0 Opacity 10 5 Qt::Horizontal QSlider::TicksBelow Qt::Vertical QSizePolicy::Fixed 20 10 The computed class values (median, variance of the gaussians) are automatically copied to clipboard. Qt::AutoText true Qt::Vertical QSizePolicy::Fixed 20 10 Histogram to Clipboard Advanced Qt::Vertical QSizePolicy::Preferred 10 1 QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Blurring QFrame::NoFrame QFrame::Raised 0 200 1 0 Qt::Horizontal 50 0 0.0 # Bins QFrame::NoFrame 0 1 100 10 Qt::Horizontal QSlider::NoTicks 50 0 50 quantiles QFrame::StyledPanel QFrame::Raised 0 1.000000000000000 0.010000000000000 0.250000000000000 1.000000000000000 0.010000000000000 0.750000000000000 Estimate circle from binary image "Thick" PFs Qt::Vertical 20 40 QmitkPartialVolumeAnalysisWidget QWidget
QmitkPartialVolumeAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui index 6120fc9c5f..ffff3e46a9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui @@ -1,1759 +1,1738 @@ QmitkPreprocessingViewControls 0 0 503 813 0 0 false QmitkPreprocessingViewControls true - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Please Select Input Data 6 6 6 6 Image: QComboBox::AdjustToMinimumContentsLength 0 Gradients 25 Qt::Vertical 20 40 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients QFrame::NoFrame QFrame::Raised 0 0 0 0 6 <html><head/><body><p>Define the sampling frame the b-Values are rounded with.</p></body></html> Sampling frame: false <html><head/><body><p>Round b-values to nearest multiple of this value (click &quot;Round b-value&quot; to create new image with these values).</p></body></html> QAbstractSpinBox::CorrectToNearestValue 1 10000 10 false Sometimes the gradient directions are not located on one half sphere. Mirror gradients to half sphere false Generate pointset displaying the gradient vectors (applied measurement frame). Show gradients false Generate pointset displaying the gradient vectors (applied measurement frame). Flip gradients false Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. Reduce number of gradients QFrame::NoFrame QFrame::Plain 0 0 0 0 0 x y z false Round b-values false By default, the image matrix is applied to the image gradients. This button removes this additional rotation. Clear rotation of gradients Remove or extract gradient volumes 6 6 6 6 6 6 false Remove gradient volume false Extract gradient volume Image Values 25 Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Merge radius false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs false Normalizes the diffusion-weighted image values across all weighted volumes to the given mean and standard deviation. Normalize image values QFrame::NoFrame QFrame::Raised 0 0 0 0 0 false Target b-value 100000 500 Select projection method. QComboBox::AdjustToMinimumContentsLength ADC Average AKC Bi-Exponential false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average repetitions false Project image values onto one b-shell. Project onto shell QFrame::NoFrame QFrame::Raised 0 0 0 0 0 true New stdev 100000 100 500 Select binary mask image. The mask is used to calculate the old mean and standard deviation. QComboBox::AdjustToMinimumContentsLength true New mean value 100000 100 1000 false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Flip axis QFrame::NoFrame QFrame::Raised 0 0 0 0 Y Qt::Horizontal 40 20 X Z Axis: QComboBox::AdjustToMinimumContentsLength Resample image 6 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 Sampling factor New image spacing New image size QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Interpolator: Nearest neighbour Linear B-spline Windowed sinc false Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 1 10000 1 10000 1 10000 Crop Image 6 6 6 6 6 x: y: z: Crop Image Header 25 Voxel size 6 6 6 6 4 0.000000000000000 99.989999999999995 4 4 false Apply new header information Direction matrix 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 0 0 Measurment frame 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 Qt::Vertical 20 40 Origin 6 6 6 6 4 -999999999.000000000000000 999999999.000000000000000 4 -99999999.000000000000000 999999999.000000000000000 4 -999999999.000000000000000 999999999.000000000000000 Align origins 6 6 6 6 QComboBox::AdjustToMinimumContentsLength Align to Other false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Estimate binary brain mask Maximum number of iterations. 10000 10000 Qt::Vertical 20 40 false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract baseline image Create a 3D+t data set containing all b0 images as timesteps Disable averaging QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_SelctedImageComboBox tabWidget m_B_ValueMap_TableWidget m_CreateLengthCorrectedDwi m_B_ValueMap_Rounder_SpinBox m_FlipGradientsButton m_FlipGradBoxX m_FlipGradBoxY m_FlipGradBoxZ m_ShowGradientsButton m_MirrorGradientToHalfSphereButton m_ReduceGradientsButton m_ClearRotationButton m_RemoveGradientButton m_RemoveGradientBox m_ExtractGradientButton m_ExtractGradientBox m_ButtonAverageGradients m_Blur m_ProjectSignalButton m_targetBValueSpinBox m_ProjectionMethodBox m_NormalizeImageValuesButton m_NewMean m_NewStdev m_NormalizationMaskBox m_FlipAxis m_FlipX m_FlipY m_FlipZ m_MergeDwisButton m_MergeDwiBox m_ResampleTypeBox m_ResampleDoubleX m_ResampleDoubleY m_ResampleDoubleZ m_ResampleIntX m_ResampleIntY m_ResampleIntZ m_InterpolatorBox m_ResampleImageButton m_XstartBox m_XendBox m_YstartBox m_YendBox m_ZstartBox m_ZendBox m_CropImageButton m_ModifyHeader m_HeaderOriginX m_HeaderOriginY m_HeaderOriginZ m_HeaderSpacingX m_HeaderSpacingY m_HeaderSpacingZ m_DirectionMatrixTable m_MeasurementFrameTable m_ButtonExtractB0 m_CheckExtractAll m_ExtractBrainMask m_BrainMaskIterationsBox
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui index 3671293c44..6c6eadc387 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui @@ -1,118 +1,97 @@ QmitkBrainExtractionViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } false Start Brain Extraction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/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.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui index 6002ee62c4..7c58ae24d6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui @@ -1,451 +1,430 @@ QmitkDiffusionQuantificationViewControls 0 0 343 888 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 Image Scale Image Values: 9999999.000000000000000 1.000000000000000 Raw diffusion-weighted image 6 6 6 6 false ADC false MD false Ball-Stick false Multi-Tensor Fit ODF image 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Generalized GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 true k true true p true false GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. angle Max. angle false Curvature Tensor image 6 6 6 6 false FA (Fractional Anisotropy) false RA (Relative Anisotropy) false AD (Axial Diffusivity) false RD (Radial Diffusivity) false MD (Mean Diffusivity) false 1-(λ2+λ3)/(2*λ1) Qt::Vertical QSizePolicy::Expanding 20 220 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui index bad0fc4932..f25a1adb7b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui @@ -1,280 +1,259 @@ QmitkODFDetailsViewControls 0 0 351 734 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 6 9 9 9 9 Please Select Input Data 6 6 6 6 DTI/ODF: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Overview 6 6 6 6 0 0 0 0 true 0 0 200 200 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 ODF Values 6 6 6 6 true 0 0 0 200 Qt::Vertical QSizePolicy::Expanding 20 220 QmitkODFDetailsWidget QWidget
QmitkODFDetailsWidget.h
1
QmitkODFRenderWidget QWidget
QmitkODFRenderWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui index bb4d30e9be..f73ef39cc5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui @@ -1,450 +1,429 @@ QmitkQBallReconstructionViewControls 0 0 372 844 0 0 true QmitkQBallReconstructionViewControls - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Parameters 6 6 6 6 2 Numerical Standard Solid Angle Constraint Solid Angle ADC-Profile only Raw Signal only Multi-Shell TextLabel QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Regularization Parameter Lambda: false Regularization factor 3 1.000000000000000 0.001000000000000 0.006000000000000 true SH-Order: false true -1 true B0 Threshold false 10000 Output SH-Coefficient Image false false Start Reconstruction Input Data 6 6 6 6 Input for Q-Ball reconstruction. Raw DWI: true Qt::LeftToRight false Multi-Shell Reconstruction 6 6 6 6 Qt::Vertical 20 0 Convert SH to sampled ODF image 6 6 6 6 false Convert QFrame::NoFrame QFrame::Raised 0 0 0 0 Input for Q-Ball reconstruction. SH Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui index a7512461be..1650d5269f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui @@ -1,778 +1,757 @@ QmitkTensorReconstructionViewControls 0 0 368 1019 0 0 true QmitkTensorReconstructionViewControls - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 ODF Image from Tensors 6 6 6 6 false Calculate ODF value as tensor value in the according direction Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Diffusion-weighted Image from Tensors 6 6 6 6 false Estimates the original diffusion weighted image based on a reconstructed tensor image. Estimate DWI based on Tensor Image QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 6 0 0 0 0 how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" B-Value false #Gradient Directions 3 12 42 92 162 252 362 492 642 812 1002 10000 100 1000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Calculate Residuals false false 6 6 6 6 6 false percentages of error 0 Per volume 200 300 Per slice outliers per slice QFrame::NoFrame QFrame::Raised 0 0 0 0 300 400 QFrame::NoFrame QFrame::Raised 0 0 0 0 20 255 Volume: .., Slice:.. false Calculate the residual from a dti and a dwi image Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: Tensor Image: Qt::Vertical 20 40 Tensor Reconstruction 6 6 6 6 Advanced Settings false false Select raw DWI! Start Reconstruction QFrame::StyledPanel QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 B0 Threshold false 10000 Only influences WLS reconstruction Ignore voxels with negative eigenvalues 0 ITK Linear Least Squares With correction for negative eigenvalues QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkResidualAnalysisWidget QWidget
QmitkResidualAnalysisWidget.h
1
QmitkResidualViewWidget QGraphicsView
QmitkResidualViewWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui index c73acb1a3a..e919050341 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui @@ -1,118 +1,97 @@ QmitkHeadMotionCorrectionViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } false Start DWI registration/Head Motion Correction Start Head Motion Correction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui index 1073648dd4..005a0cec60 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui @@ -1,309 +1,288 @@ QmitkSimpleRegistrationViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Qt::Vertical 20 40 Image Registration 6 6 6 6 false Start Registration QFrame::NoFrame QFrame::Raised 0 0 0 0 Rigid Affine Registration Type: Output Registration Object: QFrame::NoFrame QFrame::Raised 0 0 0 0 Moving Image: false Select dMRI volume used to calculate transformation. false Select dMRI volume used to calculate transformation. Fixed Image: QFrame::NoFrame QFrame::Raised 0 0 0 0 false Start Tractography Registration Tractography Registration 6 6 6 6 Registration Object: Tractogram: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/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.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui index 3edd0a05a2..cfcacb84f6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui @@ -1,158 +1,137 @@ QmitkTbssSkeletonizationViewControls 0 0 431 811 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 0 80 QFrame::StyledPanel QFrame::Raised false Mean: false Patient Data: false Tubular Structure Mask: false Skeletonize false Skeletonize and Project false Output binary mask true false Output distance map true \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui index fc056a2cfa..2fe7b197fa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui @@ -1,495 +1,474 @@ QmitkTractbasedSpatialStatisticsViewControls 0 0 265 811 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 FSL import Subject Data false false QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised Group information QAbstractItemView::SelectRows 0 0 110 100 QFrame::NoFrame QFrame::Raised 0 0 Add group entry. After that give the group a name and the correct number Add 0 0 Remove selected entries Remove false 0 0 Import a 4D image containing group data after group information has been set Import data 0 0 QFrame::StyledPanel QFrame::Raised 0 0 Measure Measurement in the to be imported 4D image FA 0 0 Tract-specific analysis true To create a roi first load a tbss meta image into the datamanager 0 ROIs 0 0 Points on Roi 100 100 0 100 Use this widget to create points on the ROI by shift-leftclick on the right positions on the skeleton. Then click Create Roi. The Roi that will be created will pass through the points in the order of occurence in this list false 0 0 No suitable tbss meta image selected yet. The meta image needs to contain a mean FA skeleton and a skeleton mask Create ROI 0 0 Points on the ROI 0 0 Name Give a name to the region of interest roiname 0 0 Structure info On what anatomical structure lies the ROI? Structure 0 0 current selection mean FA skeleton: Qt::Horizontal 253 20 Measuring 16777215 50 false #segments false 100 25 false Average false Cut To plot, load a tbss image with subject information and a region of interest corresponding to the study and select them both Copy to clipboard QmitkPointListWidget QWidget
QmitkPointListWidget.h
QmitkTbssRoiAnalysisWidget QWidget
QmitkTbssRoiAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui index ea598ceab8..4822482046 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1199 +1,1178 @@ QmitkGibbsTrackingViewControls 0 0 463 1011 0 0 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFormLayout::AllNonFixedFieldsGrow QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 false No ODF/tensor image selected. Qt::LeftToRight Start Tractography :/QtWidgetsExt/play.xpm :/QtWidgetsExt/play.xpm false Qt::LeftToRight Stop Tractography :/QtWidgetsExt/stop.xpm :/QtWidgetsExt/stop.xpm Parameters 6 6 6 6 Output File: Advanced Settings true Activate continuous visualization of intermediate results. Visualize Tractography true QFrame::NoFrame QFrame::Plain 0 0 0 0 0 0 Select output file name and folder. ... N/A true Visualize intermediate result. :/QmitkDiffusionImaging/Refresh_48.png :/QmitkDiffusionImaging/Refresh_48.png true Iterations: 1e9 true QFrame::StyledPanel QFrame::Raised 0 0 0 0 6 Particle Width: 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0.1 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Particle Weight: 1 99 1 10 Qt::Horizontal QSlider::NoTicks Start Temperature: automatic estimation from gfa map and ODF data. 0 1000 1 0 Qt::Horizontal true QSlider::NoTicks IE Bias < 0 < EE Bias -50 50 1 Qt::Horizontal QSlider::NoTicks 0.001 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Curvature Threshold: Balance In/Ex Energy: 45° Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 0.5 * min. spacing; sigma 100 1 Qt::Horizontal QSlider::NoTicks Particle Length: auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Min. Fiber Length: Only fibers longer than specified are accepted. 500 1 20 Qt::Horizontal QSlider::NoTicks Allow only fiber curvature values smaller than the selected threshold. 180 1 45 Qt::Horizontal QSlider::NoTicks End Temperature: 20mm Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 1 100 1 10 Qt::Horizontal false false QSlider::NoTicks auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l 100 1 Qt::Horizontal QSlider::NoTicks Random Seed auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l -1 100 1 -1 Qt::Horizontal QSlider::NoTicks QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 true Save current parameters as xml (.gtp) Qt::LeftToRight Save Parameters :/QmitkDiffusionImaging/general_icons/download.ico :/QmitkDiffusionImaging/general_icons/download.ico true Load parameters from xml file (.gtp) Qt::LeftToRight Load Parameters :/QmitkDiffusionImaging/general_icons/upload.ico :/QmitkDiffusionImaging/general_icons/upload.ico Qt::Vertical QSizePolicy::Expanding 0 0 0 0 Input Data 6 6 6 6 0 0 ODF/Tensor Image: Mask Image: 0 0 0 0 0 0 Monitor 6 6 6 6 6 Progress: - Will only be updated if tracking is visualized Will only be updated if tracking is visualized Accepted Fibers: Connections: Particles: Proposal Acceptance Rate: Tracking Time: Will only be updated if tracking is visualized - - - - - QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui index cc06db5811..eea4153d87 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui @@ -1,465 +1,444 @@ QmitkMLBTViewControls 0 0 476 548 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Remove training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg Add additional training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">It is recommended to use the command line application 'RfTraining' instead of this graphical user interface for the training process. Additional feature images are not supported here.</span></p><p><span style=" font-weight:600; color:#ff0000;">The GUI is intended for testing using small examples.</span></p></body></html> Qt::RichText Qt::AlignCenter true 5 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Input DWI: Qt::AlignCenter Reference Tractogram: Qt::AlignCenter Mask: Qt::AlignCenter WM: Qt::AlignCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 Fraction of samples used to train each tree. 3 1.000000000000000 0.100000000000000 0.700000000000000 Num. Trees: Sample Fraction: Max. Depth: Fiber sampling in mm. Determines the number of white-matter samples (-1 = auto). 3 -1.000000000000000 999.000000000000000 0.100000000000000 -1.000000000000000 Number of tress in the final random forest. 1 999999999 30 Non-WM Sampling Points: Fiber Sampling: Maximum tree depth. 1 999999999 25 Number of sampling points outside of the white-matter (-1 = automatic estimation). -1 999999999 -1 Num. previous directions: Number of previous fiber directions used as features. 0 50 1 dMRI Features: Spherical Harmonics Coefficients Raw Data Start Training. This can take up to a couple of hours. Start Training Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/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.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui index 32fc1145d5..0ea54e5f85 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -1,1590 +1,1575 @@ - + QmitkStreamlineTrackingViewControls 0 0 453 859 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 3 3 0 40 QFrame::NoFrame QFrame::Raised 0 15 0 0 6 15 true 0 0 true QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image. ODF, tensor and peak images are currently supported. Input Image: Input Image. ODF, tensor, peak, and, in case of ML tractography, raw diffusion-weighted images are currently supported. - <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> true - + Tractography Forest: Random forest for machine learning based tractography. QComboBox::AdjustToMinimumContentsLength - true Stop tractography and return all fibers reconstructed until now. Stop Tractography false Start Tractography 0 0 0 0 + + + 75 + true + + 0 0 0 421 262 Seeding Specify how, where and how many tractography seed points are placed. QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points equally distributed around selected position. 1 9999999 50 - + Radius: Seedpoints are equally distributed within a sphere centered at the selected position with the specified radius (in mm). 2 50.000000000000000 0.100000000000000 2.000000000000000 - + Num. Seeds: true When checked, parameter changes cause instant retracking while in interactive mode. Update on Parameter Change true QFrame::NoFrame QFrame::Raised 0 0 0 0 Try each seed N times until a valid streamline is obtained (only for probabilistic tractography). Minimum fiber length (in mm) 1 999 10 - + Trials Per Seed: - + Max. Num. Fibers: Tractography is stopped after the desired number of fibers is reached, even before all seed points are processed (-1 means no limit). -1 999999999 -1 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points placed in each voxel. 1 9999999 - + Seeds per Voxel: Seed points are only placed inside the regions defined in the seed image. If no seed image is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - - + Seed Image: true Dynamically pick a seed location by click into image. Enable Interactive Tractography Qt::Vertical 20 40 0 0 435 224 ROI Constraints Specify various ROI and mask images to constrain the tractography process. - + Mask Image: Fibers that enter a region defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - Select which fibers should be accepted or rejected based on the location of their endpoints. QComboBox::AdjustToMinimumContentsLength No Constraints on EP locations Both EPs in Target Image Both EPs in Target Image But Different Label One EP in Seed Image and One EP in Target Image At Least One EP in Target Image Exactly One EP in Target Image No EP in Target Image - + Endpoint Constraints: - + Stop ROI Image: The target image is used for the endpoint constraint strategy defined above. QComboBox::AdjustToMinimumContentsLength - - + Exclusion ROI Image: Fibers that leave the regions defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - - + Target ROI Image: Fibers that enter a region defined in this image will be discarded. QComboBox::AdjustToMinimumContentsLength - Qt::Vertical 20 40 0 0 421 351 Tractography Parameters Specify the behavior of the tractography at each streamline integration step (step size, deterministic/probabilistic, ...). Qt::Vertical 20 40 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 0.000000000000000 Toggle between deterministic and probabilistic tractography. Some modes might not be available for all types of tractography. Deterministic Probabilistic - + Cutoff: - + FA/GFA Image: - + Mode: - + Angular Threshold: Step size (in voxels) 2 0.010000000000000 10.000000000000000 0.100000000000000 0.500000000000000 Maximum allowed angular SDTEV over 4 voxel lengths. Default: no loop check. - + -1 180 -1 If an image is selected, the stopping criterion is not calculated from the input image but instead the selected image is used. QComboBox::AdjustToMinimumContentsLength - - + Step Size: Additional threshold on the ODF magnitude. This is useful in case of CSD fODF tractography. For fODFs a good default value is 0.1, for normalized dODFs, e.g. Q-ball ODFs, this threshold should be very low (0.00025) or 0. 5 1.000000000000000 0.100000000000000 0.000250000000000 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 1.000000000000000 If you are using dODF images as input, it is advisable to sharpen the ODFs (min-max normalize and raise to the power of 4). This is not necessary for CSD fODFs, since they are naturally much sharper. - + f parameter of tensor tractography. f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). f: - + Min. Tract Length: Threshold on peak magnitude, FA, GFA, ... 5 1.000000000000000 0.100000000000000 0.100000000000000 - + ODF Cutoff: Minimum tract length in mm. Shorter fibers are discarded. Minimum fiber length (in mm) 1 999.000000000000000 1.000000000000000 20.000000000000000 - + Loop Check: Angular threshold between two steps (in degree). Default: 90° * step_size -1 90 1 -1 - + g: - + Sharpen ODFs: 0 0 435 224 Tractography Prior Restrict to Prior: Weight: Peak Image: Weighting factor between prior and data. 1.000000000000000 0.100000000000000 0.500000000000000 Restrict tractography to regions where the prior is valid. - + true - + Qt::Vertical 20 40 New Directions from Prior: If unchecked, the prior cannot create directions where there are none in the data. - + true 0 0 435 224 Neighborhood Sampling Specify if and how information about the current streamline neighborhood should be used. Only neighborhood samples in front of the current streamline position are considered. Use Only Frontal Samples false If checked, the majority of sampling points has to place a stop-vote for the streamline to terminate. If not checked, all sampling positions have to vote for a streamline termination. Use Stop-Votes false QFrame::NoFrame QFrame::Raised 0 0 0 0 - + Num. Samples: Number of neighborhood samples that are used to determine the next fiber progression direction. 50 - + Sampling Distance: Sampling distance (in voxels) 2 10.000000000000000 0.100000000000000 0.250000000000000 Qt::Vertical 20 40 0 0 435 224 Data Handling Specify interpolation and direction flips. QFrame::NoFrame QFrame::Raised 0 0 0 0 Trilinearly interpolate the input image used for tractography. Interpolate Tractography Data true Trilinearly interpolate the ROI images used to constrain the tractography. Interpolate ROI Images true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Internally flips progression directions. This might be necessary depending on the input data. x Internally flips progression directions. This might be necessary depending on the input data. y Internally flips progression directions. This might be necessary depending on the input data. z - + Flip directions: Qt::Vertical 20 40 0 0 435 224 Output and Postprocessing Specify the tractography output (streamlines or probability maps) and postprocessing steps. QFrame::NoFrame QFrame::Raised 0 0 0 0 Compress fibers using the specified error constraint. Compress Fibers true Qt::StrongFocus Lossy fiber compression. Recommended for large tractograms. Maximum error in mm. 3 10.000000000000000 0.010000000000000 0.100000000000000 Output map with voxel-wise visitation counts instead of streamlines. Output Probability Map false Qt::Vertical 20 40 - + QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
- - -
\ No newline at end of file + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui index 9d779a6a02..ee1c8be363 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui @@ -1,1030 +1,1009 @@ QmitkControlVisualizationPropertiesViewControls 0 0 567 619 0 100 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Multislice Projection MIP QToolButton::MenuButtonPopup Qt::NoArrow QFrame::NoFrame QFrame::Plain 0 0 0 0 Toggle visibility of ODF glyphs (axial) :/QmitkDiffusionImaging/glyphsoff_T.png :/QmitkDiffusionImaging/glyphson_T.png :/QmitkDiffusionImaging/glyphsoff_T.png true false Toggle visibility of ODF glyphs (sagittal) :/QmitkDiffusionImaging/glyphsoff_S.png :/QmitkDiffusionImaging/glyphson_S.png :/QmitkDiffusionImaging/glyphsoff_S.png true false Toggle visibility of ODF glyphs (coronal) :/QmitkDiffusionImaging/glyphsoff_C.png :/QmitkDiffusionImaging/glyphson_C.png :/QmitkDiffusionImaging/glyphsoff_C.png true false #Glyphs 9999 Qt::Horizontal 20 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF normalization false Min-Max Max None ODF Normalization: ODF normalization false ODF Value Principal Direction Color ODFs/Tensors by: QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF Scale: false None FA/GFA * Additional scaling factor 3 999999999.000000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Position Crosshair by 3D-Click :/QmitkDiffusionImaging/crosshair.png :/QmitkDiffusionImaging/crosshair.png true false 2D Fiberfading on/off Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 2D Clipping 100 10 10 10 Qt::Horizontal 90 0 10000 16777215 Range QFrame::NoFrame QFrame::Raised 0 0 0 0 Tube Radius 3 0.100000000000000 Ribbon Width 3 0.100000000000000 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">One or more slices are rotated. ODF Visualisation is not possible in rotated planes. Use 'Reinit' on the image node to reset. </span></p></body></html> Qt::AutoText true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 y z x 0 0 Flip Peaks QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Qt::Horizontal 40 20 Line Width 1 1.000000000000000 0.100000000000000 1.000000000000000 3D Clipping 6 6 6 6 0 Coronal Axial No clipping true Sagittal Flipp Clipping Direction Enable 3D Rendering Qt::Vertical 20 40 QmitkDataStorageComboBox.h \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui index 5c160ad17e..e31cb7a178 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui @@ -1,186 +1,165 @@ QmitkDicomTractogramTagEditorViewControls 0 0 397 366 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 3 3 0 QFrame::NoFrame QFrame::Raised 0 0 0 9 Tractogram: Seed points are only placed inside the mask image. If no seed mask is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - Tractography DICOM Tags 6 6 6 6 0 QFrame::NoFrame Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::Vertical QSizePolicy::Expanding 20 220 Copies the DICOM properties of the tractogram selected in this view to the one selected in the datamanager. Copy Properties From Image QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui index 336dc2fbac..fbe4a816f8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui @@ -1,401 +1,380 @@ QmitkDiffusionDicomImportControls 0 0 374 603 0 0 true QmitkDiffusionDicomImport - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 16777215 70 QFrame::NoFrame QFrame::Plain 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Each input folder must only contain DICOM-images that can be combined into one vector-valued 3D output volume. Different patients must be loaded from different input-folders. The folders must not contain other acquisitions (e.g. T1,T2,localizer).</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">In case many imports are performed at once, it is recommended to set the the optional output folder argument. This prevents the images from being kept in memory.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p></td></tr></table></body></html> 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Add Input Folders Remove Clear 0 0 0 70 QFrame::Box QFrame::Plain 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOn QListView::Adjust true QFrame::StyledPanel QFrame::Raised Recursive 8 QLayout::SetNoConstraint Set Prefix Reset Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them anyway by taking into account all directions within a certain radius. QFrame::NoFrame QFrame::Raised 0 0 0 0 Merge duplicate gradients: false 4 2.000000000000000 0.000100000000000 0.001000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 40 25 30 16777215 Files are automaticall saved to disc. If the files can not be written, they are added to the data manager. Set ... optional out-folder ... false true 50 25 30 16777215 Clear Override existing files Split Mosaic Import DICOM as *.dwi Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp index 417146690b..c1fa703c99 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp @@ -1,99 +1,99 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDiffusionImagingAppWorkbenchAdvisor.h" #include "internal/QmitkDiffusionApplicationPlugin.h" #include #include #include #include #include #include #include #include const QString QmitkDiffusionImagingAppWorkbenchAdvisor::WELCOME_PERSPECTIVE_ID = "org.mitk.diffusionimagingapp.perspectives.welcome"; class QmitkDiffusionImagingAppWorkbenchWindowAdvisor : public QmitkExtWorkbenchWindowAdvisor { public: QmitkDiffusionImagingAppWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer) : QmitkExtWorkbenchWindowAdvisor(wbAdvisor, configurer) { } void PostWindowOpen() override { QmitkExtWorkbenchWindowAdvisor::PostWindowOpen(); berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); - configurer->GetWindow()->GetWorkbench()->GetIntroManager()->ShowIntro(configurer->GetWindow(), false); +// configurer->GetWindow()->GetWorkbench()->GetIntroManager()->ShowIntro(configurer->GetWindow(), false); } }; void QmitkDiffusionImagingAppWorkbenchAdvisor::Initialize(berry::IWorkbenchConfigurer::Pointer configurer) { berry::QtWorkbenchAdvisor::Initialize(configurer); configurer->SetSaveAndRestore(true); } berry::WorkbenchWindowAdvisor* QmitkDiffusionImagingAppWorkbenchAdvisor::CreateWorkbenchWindowAdvisor( berry::IWorkbenchWindowConfigurer::Pointer configurer) { QList perspExcludeList; perspExcludeList.push_back( "org.blueberry.uitest.util.EmptyPerspective" ); perspExcludeList.push_back( "org.blueberry.uitest.util.EmptyPerspective2" ); perspExcludeList.push_back("org.blueberry.perspectives.help"); QList viewExcludeList; viewExcludeList.push_back( "org.mitk.views.controlvisualizationpropertiesview" ); viewExcludeList.push_back( "org.mitk.views.modules" ); //QRect rec = QApplication::desktop()->screenGeometry(); //configurer->SetInitialSize(QPoint(rec.width(),rec.height())); QmitkDiffusionImagingAppWorkbenchWindowAdvisor* advisor = new QmitkDiffusionImagingAppWorkbenchWindowAdvisor(this, configurer); advisor->ShowViewMenuItem(true); advisor->ShowNewWindowMenuItem(true); advisor->ShowClosePerspectiveMenuItem(true); advisor->SetPerspectiveExcludeList(perspExcludeList); advisor->SetViewExcludeList(viewExcludeList); advisor->ShowViewToolbar(false); advisor->ShowPerspectiveToolbar(true); advisor->ShowVersionInfo(false); advisor->ShowMitkVersionInfo(false); advisor->ShowMemoryIndicator(false); advisor->SetProductName("MITK Diffusion"); advisor->SetWindowIcon(":/org.mitk.gui.qt.diffusionimagingapp/app-icon.png"); return advisor; } QString QmitkDiffusionImagingAppWorkbenchAdvisor::GetInitialWindowPerspectiveId() { return WELCOME_PERSPECTIVE_ID; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui index e567f646f8..c8e0f4f8ad 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui @@ -1,64 +1,43 @@ QmitkWelcomeScreenViewControls 0 0 458 398 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.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/PAImageProcessing.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp index 36f37eadde..37cbed4acd 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp @@ -1,1166 +1,1042 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ - // Blueberry #include #include // Qmitk #include "PAImageProcessing.h" // Qt #include #include #include #include //mitk image #include -#include "mitkPhotoacousticImage.h" -#include "mitkPhotoacousticBeamformingFilter.h" +#include "mitkPhotoacousticFilterService.h" +#include "mitkCastToFloatImageFilter.h" +#include "mitkBeamformingFilter.h" //other #include #include #include const std::string PAImageProcessing::VIEW_ID = "org.mitk.views.paimageprocessing"; -PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false), m_FilterBank(mitk::PhotoacousticImage::New()) +PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false), m_FilterBank(mitk::PhotoacousticFilterService::New()) { qRegisterMetaType(); qRegisterMetaType(); } void PAImageProcessing::SetFocus() { m_Controls.buttonApplyBModeFilter->setFocus(); } void PAImageProcessing::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.buttonApplyBModeFilter, SIGNAL(clicked()), this, SLOT(StartBmodeThread())); connect(m_Controls.DoResampling, SIGNAL(clicked()), this, SLOT(UseResampling())); connect(m_Controls.Logfilter, SIGNAL(clicked()), this, SLOT(UseLogfilter())); connect(m_Controls.ResamplingValue, SIGNAL(valueChanged(double)), this, SLOT(SetResampling())); connect(m_Controls.buttonApplyBeamforming, SIGNAL(clicked()), this, SLOT(StartBeamformingThread())); connect(m_Controls.buttonApplyCropFilter, SIGNAL(clicked()), this, SLOT(StartCropThread())); connect(m_Controls.buttonApplyBandpass, SIGNAL(clicked()), this, SLOT(StartBandpassThread())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UseImageSpacing())); connect(m_Controls.ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBeamforming())); connect(m_Controls.BPSpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBandpass())); connect(m_Controls.Samples, SIGNAL(valueChanged(int)), this, SLOT(UpdateImageInfo())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UpdateImageInfo())); connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(LowerSliceBoundChanged())); connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpperSliceBoundChanged())); connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(SliceBoundsEnabled())); connect(m_Controls.BatchProcessing, SIGNAL(clicked()), this, SLOT(BatchProcessing())); connect(m_Controls.StepBeamforming, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepCropping, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBandpass, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBMode, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + connect(m_Controls.UseSignalDelay, SIGNAL(clicked()), this, SLOT(UseSignalDelay())); UpdateSaveBoxes(); + UseSignalDelay(); m_Controls.DoResampling->setChecked(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(100); m_Controls.progressBar->setVisible(false); m_Controls.UseImageSpacing->setToolTip("Image spacing of y-Axis must be in us, x-Axis in mm."); m_Controls.UseImageSpacing->setToolTipDuration(5000); m_Controls.ProgressInfo->setVisible(false); - m_Controls.UseBP->hide(); m_Controls.UseGPUBmode->hide(); - #ifndef PHOTOACOUSTICS_USE_GPU - m_Controls.UseGPUBf->setEnabled(false); - m_Controls.UseGPUBf->setChecked(false); - m_Controls.UseGPUBmode->setEnabled(false); - m_Controls.UseGPUBmode->setChecked(false); - #endif - +#ifndef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(false); + m_Controls.UseGPUBf->setChecked(false); + m_Controls.UseGPUBmode->setEnabled(false); + m_Controls.UseGPUBmode->setChecked(false); +#endif + UseImageSpacing(); } +void PAImageProcessing::UseSignalDelay() +{ + if (m_Controls.UseSignalDelay->isChecked()) + { + m_Controls.SignalDelay->setEnabled(true); + } + else + { + m_Controls.SignalDelay->setEnabled(false); + } +} + void PAImageProcessing::ChangedSOSBandpass() { m_Controls.SpeedOfSound->setValue(m_Controls.BPSpeedOfSound->value()); } void PAImageProcessing::ChangedSOSBeamforming() { m_Controls.BPSpeedOfSound->setValue(m_Controls.SpeedOfSound->value()); } std::vector splitpath( const std::string& str , const std::set delimiters) { std::vector result; char const* pch = str.c_str(); char const* start = pch; for (; *pch; ++pch) { if (delimiters.find(*pch) != delimiters.end()) { if (start != pch) { std::string str(start, pch); result.push_back(str); } else { result.push_back(""); } start = pch + 1; } } result.push_back(start); return result; } void PAImageProcessing::UpdateSaveBoxes() { if (m_Controls.StepBeamforming->isChecked()) m_Controls.SaveBeamforming->setEnabled(true); else m_Controls.SaveBeamforming->setEnabled(false); if (m_Controls.StepCropping->isChecked()) m_Controls.SaveCropping->setEnabled(true); else m_Controls.SaveCropping->setEnabled(false); if (m_Controls.StepBandpass->isChecked()) m_Controls.SaveBandpass->setEnabled(true); else m_Controls.SaveBandpass->setEnabled(false); if (m_Controls.StepBMode->isChecked()) m_Controls.SaveBMode->setEnabled(true); else m_Controls.SaveBMode->setEnabled(false); } void PAImageProcessing::BatchProcessing() { QFileDialog LoadDialog(nullptr, "Select Files to be processed"); LoadDialog.setFileMode(QFileDialog::FileMode::ExistingFiles); LoadDialog.setNameFilter(tr("Images (*.nrrd)")); LoadDialog.setViewMode(QFileDialog::Detail); QStringList fileNames; if (LoadDialog.exec()) fileNames = LoadDialog.selectedFiles(); QString saveDir = QFileDialog::getExistingDirectory(nullptr, tr("Select Directory To Save To"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); DisableControls(); - std::set delims{'/'}; + std::set delims{ '/' }; bool doSteps[] = { m_Controls.StepBeamforming->isChecked(), m_Controls.StepCropping->isChecked() , m_Controls.StepBandpass->isChecked(), m_Controls.StepBMode->isChecked() }; bool saveSteps[] = { m_Controls.SaveBeamforming->isChecked(), m_Controls.SaveCropping->isChecked() , m_Controls.SaveBandpass->isChecked(), m_Controls.SaveBMode->isChecked() }; for (int fileNumber = 0; fileNumber < fileNames.size(); ++fileNumber) { m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("loading file"); QString filename = fileNames.at(fileNumber); auto split = splitpath(filename.toStdString(), delims); - std::string imageName = split.at(split.size()-1); + std::string imageName = split.at(split.size() - 1); // remove ".nrrd" - imageName = imageName.substr(0, imageName.size()-5); + imageName = imageName.substr(0, imageName.size() - 5); mitk::Image::Pointer image = mitk::IOUtil::Load(filename.toStdString().c_str()); + auto BFconfig = CreateBeamformingSettings(image); - UpdateBFSettings(image); // Beamforming if (doSteps[0]) { std::function progressHandle = [this](int progress, std::string progressInfo) { this->UpdateProgress(progress, progressInfo); }; m_Controls.progressBar->setValue(100); - std::string errorMessage = ""; - image = m_FilterBank->ApplyBeamforming(image, BFconfig, errorMessage, progressHandle); + image = m_FilterBank->ApplyBeamforming(image, BFconfig, progressHandle); if (saveSteps[0]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " beamformed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Cropping if (doSteps[1]) { m_Controls.ProgressInfo->setText("cropping image"); - image = m_FilterBank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, image->GetDimension(2) - 1); + image = m_FilterBank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, 0); if (saveSteps[1]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " cropped" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bandpass if (doSteps[2]) { m_Controls.ProgressInfo->setText("applying bandpass"); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] - if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) + if (BPLowPass > maxFrequency) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } - if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) + if (BPLowPass < 0) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } - if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) + if (BPHighPass > maxFrequency) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } - if (BPHighPass > maxFrequency - BFconfig.BPLowPass) + if (BPHighPass > maxFrequency - BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } - image = m_FilterBank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, - m_Controls.BPFalloffHigh->value(), - m_Controls.BPFalloffLow->value()); + image = m_FilterBank->ApplyBandpassFilter(image, BPHighPass, BPLowPass, + m_Controls.BPFalloffHigh->value(), + m_Controls.BPFalloffLow->value()); if (saveSteps[2]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bandpassed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } - // Bmode + // Bmode if (doSteps[3]) { m_Controls.ProgressInfo->setText("applying bmode filter"); - bool useGPU = m_Controls.UseGPUBmode->isChecked(); - + if (m_Controls.BModeMethod->currentText() == "Absolute Filter") - image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU, m_UseLogfilter, m_ResampleSpacing); + image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticFilterService::BModeMethod::Abs, m_UseLogfilter); else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") - image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU, m_UseLogfilter, m_ResampleSpacing); - + image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, m_UseLogfilter); + + double desiredSpacing[2]{ image->GetGeometry()->GetSpacing()[0], m_ResampleSpacing }; + + image = m_FilterBank->ApplyResampling(image, desiredSpacing); + if (saveSteps[3]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bmode" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } m_Controls.progressBar->setVisible(false); } EnableControls(); } void PAImageProcessing::StartBeamformingThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { - UpdateBFSettings(image); + auto BFconfig = CreateBeamformingSettings(image); std::stringstream message; std::string name; message << "Performing beamforming for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("started"); - m_Controls.buttonApplyBeamforming->setText("working..."); DisableControls(); BeamformingThread *thread = new BeamformingThread(); - connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleBeamformingResults); + connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BeamformingThread::updateProgress, this, &PAImageProcessing::UpdateProgress); - connect(thread, &BeamformingThread::message, this, &PAImageProcessing::PAMessageBox); connect(thread, &BeamformingThread::finished, thread, &QObject::deleteLater); thread->setConfig(BFconfig); + + if (m_Controls.UseSignalDelay->isChecked()) + thread->setSignalDelay(m_Controls.SignalDelay->value()); + thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Beamforming"; thread->start(); } } } -void PAImageProcessing::HandleBeamformingResults(mitk::Image::Pointer image) +void PAImageProcessing::HandleResults(mitk::Image::Pointer image, std::string nameExtension) { + MITK_INFO << "Handling results..."; auto newNode = mitk::DataNode::New(); newNode->SetData(image); - // name the new Data node - std::stringstream newNodeName; - - newNodeName << m_OldNodeName << " "; - - if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DAS) - newNodeName << "DAS bf, "; - else if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DMAS) - newNodeName << "DMAS bf, "; - - if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::QuadApprox) - newNodeName << "q. delay"; - if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::Spherical) - newNodeName << "s. delay"; - - newNode->SetName(newNodeName.str()); + newNode->SetName(m_OldNodeName + nameExtension); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); levelWindow.SetAuto(image, true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.ProgressInfo->setVisible(false); - m_Controls.buttonApplyBeamforming->setText("Apply Beamforming"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews(image->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + MITK_INFO << "Handling results...[Done]"; } void PAImageProcessing::StartBmodeThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { - UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); - m_Controls.buttonApplyBModeFilter->setText("working..."); DisableControls(); BmodeThread *thread = new BmodeThread(); - connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleBmodeResults); + connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BmodeThread::finished, thread, &QObject::deleteLater); bool useGPU = m_Controls.UseGPUBmode->isChecked(); - if(m_Controls.BModeMethod->currentText() == "Absolute Filter") - thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU); - else if(m_Controls.BModeMethod->currentText() == "Envelope Detection") - thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU); + if (m_Controls.BModeMethod->currentText() == "Absolute Filter") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticFilterService::BModeMethod::Abs, useGPU); + else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") + thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, useGPU); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Processing"; thread->start(); } } } -void PAImageProcessing::HandleBmodeResults(mitk::Image::Pointer image) -{ - auto newNode = mitk::DataNode::New(); - newNode->SetData(image); - - // name the new Data node - std::stringstream newNodeName; - newNodeName << m_OldNodeName << " "; - newNodeName << "B-Mode"; - - newNode->SetName(newNodeName.str()); - - // update level window for the current dynamic range - mitk::LevelWindow levelWindow; - newNode->GetLevelWindow(levelWindow); - auto data = newNode->GetData(); - levelWindow.SetAuto(dynamic_cast(data), true, true); - newNode->SetLevelWindow(levelWindow); - - // add new node to data storage - this->GetDataStorage()->Add(newNode); - - // disable progress bar - m_Controls.progressBar->setVisible(false); - m_Controls.buttonApplyBModeFilter->setText("Apply B-mode Filter"); - EnableControls(); - - // update rendering - mitk::RenderingManager::GetInstance()->InitializeViews( - dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - void PAImageProcessing::StartCropThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { - UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image cropping for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); - m_Controls.buttonApplyCropFilter->setText("working..."); DisableControls(); CropThread *thread = new CropThread(); - connect(thread, &CropThread::result, this, &PAImageProcessing::HandleCropResults); + connect(thread, &CropThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &CropThread::finished, thread, &QObject::deleteLater); - thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, image->GetDimension(2) - 1); + if(m_Controls.Partial->isChecked()) + thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), m_Controls.boundLow->value(), m_Controls.boundHigh->value()); + else + thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, image->GetDimension(2) - 1); + thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Cropping"; thread->start(); } } } -void PAImageProcessing::HandleCropResults(mitk::Image::Pointer image) -{ - auto newNode = mitk::DataNode::New(); - newNode->SetData(image); - - // name the new Data node - std::stringstream newNodeName; - newNodeName << m_OldNodeName << " "; - newNodeName << "Cropped"; - - newNode->SetName(newNodeName.str()); - - // update level window for the current dynamic range - mitk::LevelWindow levelWindow; - newNode->GetLevelWindow(levelWindow); - auto data = newNode->GetData(); - levelWindow.SetAuto(dynamic_cast(data), true, true); - newNode->SetLevelWindow(levelWindow); - - // add new node to data storage - this->GetDataStorage()->Add(newNode); - - m_Controls.buttonApplyCropFilter->setText("Apply Crop Filter"); - EnableControls(); - - // update rendering - mitk::RenderingManager::GetInstance()->InitializeViews( - dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - void PAImageProcessing::StartBandpassThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return - QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); + QMessageBox::information(NULL, "Template", "Please load and select an image before applying a bandpass filter."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { - UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing Bandpass filter on image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); - m_Controls.buttonApplyBandpass->setText("working..."); DisableControls(); BandpassThread *thread = new BandpassThread(); - connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleBandpassResults); + connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BandpassThread::finished, thread, &QObject::deleteLater); - float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); - - // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image - float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; - float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] - float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] - - if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) - { - QMessageBox Msgbox; - Msgbox.setText("LowPass too low, disabled it."); - Msgbox.exec(); - - BPLowPass = 0; - } - if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) - { - QMessageBox Msgbox; - Msgbox.setText("LowPass too high, disabled it."); - Msgbox.exec(); - - BPLowPass = 0; - } - if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) - { - QMessageBox Msgbox; - Msgbox.setText("HighPass too high, disabled it."); - Msgbox.exec(); + float BPHighPass = 1000000.0f * m_Controls.BPhigh->value(); // [Now in Hz] + float BPLowPass = 1000000.0f * m_Controls.BPlow->value(); // [Now in Hz] - BPHighPass = 0; - } - if (BPHighPass > maxFrequency - BFconfig.BPLowPass) - { - QMessageBox Msgbox; - Msgbox.setText("HighPass higher than LowPass, disabled both."); - Msgbox.exec(); - - BPHighPass = 0; - BPLowPass = 0; - } - - thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloffLow->value(), m_Controls.BPFalloffHigh->value(), recordTime); + thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloffLow->value(), m_Controls.BPFalloffHigh->value(), 0); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Bandpass filter"; thread->start(); } } } -void PAImageProcessing::HandleBandpassResults(mitk::Image::Pointer image) -{ - auto newNode = mitk::DataNode::New(); - newNode->SetData(image); - - // name the new Data node - std::stringstream newNodeName; - newNodeName << m_OldNodeName << " "; - newNodeName << "Bandpassed"; - - newNode->SetName(newNodeName.str()); - - // update level window for the current dynamic range - mitk::LevelWindow levelWindow; - newNode->GetLevelWindow(levelWindow); - auto data = newNode->GetData(); - levelWindow.SetAuto(dynamic_cast(data), true, true); - newNode->SetLevelWindow(levelWindow); - - // add new node to data storage - this->GetDataStorage()->Add(newNode); - - m_Controls.buttonApplyBandpass->setText("Apply Bandpass"); - EnableControls(); - - // update rendering - mitk::RenderingManager::GetInstance()->InitializeViews( - dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - void PAImageProcessing::SliceBoundsEnabled() { if (!m_Controls.Partial->isChecked()) { m_Controls.boundLow->setEnabled(false); m_Controls.boundHigh->setEnabled(false); return; } else { m_Controls.boundLow->setEnabled(true); m_Controls.boundHigh->setEnabled(true); } } void PAImageProcessing::UpperSliceBoundChanged() { - if(m_Controls.boundLow->value() > m_Controls.boundHigh->value()) + if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundLow->setValue(m_Controls.boundHigh->value()); } } void PAImageProcessing::LowerSliceBoundChanged() { if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundHigh->setValue(m_Controls.boundLow->value()); } } void PAImageProcessing::UpdateProgress(int progress, std::string progressInfo) { if (progress < 100) m_Controls.progressBar->setValue(progress); else m_Controls.progressBar->setValue(100); m_Controls.ProgressInfo->setText(progressInfo.c_str()); qApp->processEvents(); } void PAImageProcessing::PAMessageBox(std::string message) { if (0 != message.compare("noMessage")) { QMessageBox msgBox; msgBox.setText(message.c_str()); msgBox.exec(); } } void PAImageProcessing::UpdateImageInfo() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { // beamforming configs if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ElementCount->setValue(image->GetDimension(0)); m_Controls.Pitch->setValue(image->GetGeometry()->GetSpacing()[0]); } m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); m_Controls.boundHigh->setMaximum(image->GetDimension(2) - 1); - UpdateBFSettings(image); - - m_Controls.CutoffBeforeBF->setValue(0.000001 / BFconfig.TimeSpacing); // 1us standard offset for our transducer - + float speedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] std::stringstream frequency; - float maxFrequency = (1 / BFconfig.TimeSpacing) * image->GetDimension(1) / 2 / 2 / 1000; + float timeSpacing; + if (m_Controls.UseImageSpacing->isChecked()) + { + timeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000.0f; + MITK_INFO << "Calculated Scan Depth of " << (image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / + 1000000) * speedOfSound * 100 / 2 << "cm"; + } + else + { + timeSpacing = (2 * m_Controls.ScanDepth->value() / 1000 / speedOfSound) / image->GetDimension(1); + } + float maxFrequency = (1 / timeSpacing) * image->GetDimension(1) / 2 / 2 / 1000; frequency << maxFrequency / 1000000; //[MHz] frequency << "MHz"; m_Controls.BPhigh->setMaximum(maxFrequency / 1000000); m_Controls.BPlow->setMaximum(maxFrequency / 1000000); frequency << " is the maximal allowed frequency for the selected image."; m_Controls.BPhigh->setToolTip(frequency.str().c_str()); m_Controls.BPlow->setToolTip(frequency.str().c_str()); m_Controls.BPhigh->setToolTipDuration(5000); m_Controls.BPlow->setToolTipDuration(5000); } } } -void PAImageProcessing::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, - const QList& nodes ) +void PAImageProcessing::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, + const QList& nodes) { // iterate all selected objects, adjust warning visibility - foreach( mitk::DataNode::Pointer node, nodes ) + foreach(mitk::DataNode::Pointer node, nodes) { - if( node.IsNotNull() && dynamic_cast(node->GetData()) ) + if (node.IsNotNull() && dynamic_cast(node->GetData())) { - m_Controls.labelWarning->setVisible( false ); - m_Controls.buttonApplyBModeFilter->setEnabled( true ); + m_Controls.labelWarning->setVisible(false); + m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.labelWarning2->setVisible(false); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.labelWarning3->setVisible(false); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.labelWarning4->setVisible(false); m_Controls.buttonApplyBeamforming->setEnabled(true); UpdateImageInfo(); return; } } - m_Controls.labelWarning->setVisible( true ); - m_Controls.buttonApplyBModeFilter->setEnabled( false ); + m_Controls.labelWarning->setVisible(true); + m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.labelWarning2->setVisible(true); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.labelWarning3->setVisible(true); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.labelWarning4->setVisible(true); m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseResampling() { if (m_Controls.DoResampling->isChecked()) { m_Controls.ResamplingValue->setEnabled(true); m_ResampleSpacing = m_Controls.ResamplingValue->value(); } else { m_Controls.ResamplingValue->setEnabled(false); m_ResampleSpacing = 0; } } void PAImageProcessing::UseLogfilter() { m_UseLogfilter = m_Controls.Logfilter->isChecked(); } void PAImageProcessing::SetResampling() { m_ResampleSpacing = m_Controls.ResamplingValue->value(); } -void PAImageProcessing::UpdateBFSettings(mitk::Image::Pointer image) +mitk::BeamformingSettings::Pointer PAImageProcessing::CreateBeamformingSettings(mitk::Image::Pointer image) { + mitk::BeamformingSettings::BeamformingAlgorithm algorithm; if ("DAS" == m_Controls.BFAlgorithm->currentText()) - BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; + algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; else if ("DMAS" == m_Controls.BFAlgorithm->currentText()) - BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; + algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; else if ("sDMAS" == m_Controls.BFAlgorithm->currentText()) - BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; + algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; - if ("Quad. Approx." == m_Controls.DelayCalculation->currentText()) - { - BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::QuadApprox; - } - else if ("Spherical Wave" == m_Controls.DelayCalculation->currentText()) - { - BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::Spherical; - } + mitk::BeamformingSettings::DelayCalc delay = mitk::BeamformingSettings::DelayCalc::Spherical; + mitk::BeamformingSettings::Apodization apod; if ("Von Hann" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hann; + apod = mitk::BeamformingSettings::Apodization::Hann; } else if ("Hamming" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hamm; + apod = mitk::BeamformingSettings::Apodization::Hamm; } else if ("Box" == m_Controls.Apodization->currentText()) { - BFconfig.Apod = mitk::BeamformingSettings::Apodization::Box; + apod = mitk::BeamformingSettings::Apodization::Box; } - BFconfig.Pitch = m_Controls.Pitch->value() / 1000; // [m] - BFconfig.SpeedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] - BFconfig.SamplesPerLine = m_Controls.Samples->value(); - BFconfig.ReconstructionLines = m_Controls.Lines->value(); - BFconfig.TransducerElements = m_Controls.ElementCount->value(); - BFconfig.apodizationArraySize = m_Controls.Lines->value(); - BFconfig.Angle = m_Controls.Angle->value(); // [deg] - BFconfig.UseBP = m_Controls.UseBP->isChecked(); - BFconfig.UseGPU = m_Controls.UseGPUBf->isChecked(); - BFconfig.upperCutoff = m_Controls.CutoffBeforeBF->value(); + float pitchInMeters = m_Controls.Pitch->value() / 1000; // [m] + float speedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] + unsigned int samplesPerLine = m_Controls.Samples->value(); + unsigned int reconstructionLines = m_Controls.Lines->value(); + unsigned int apodizatonArraySize = m_Controls.Lines->value(); + float angle = m_Controls.Angle->value(); // [deg] + bool useGPU = m_Controls.UseGPUBf->isChecked(); + float timeSpacing; if (m_Controls.UseImageSpacing->isChecked()) { - BFconfig.RecordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000; // [s] - BFconfig.TimeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000; - MITK_INFO << "Calculated Scan Depth of " << BFconfig.RecordTime * BFconfig.SpeedOfSound * 100 / 2 << "cm"; + timeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000.0f; + MITK_INFO << "Calculated Scan Depth of " << (image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / + 1000000) * speedOfSound * 100 / 2 << "cm"; } else { - BFconfig.RecordTime = 2 * m_Controls.ScanDepth->value() / 1000 / BFconfig.SpeedOfSound; // [s] - BFconfig.TimeSpacing = BFconfig.RecordTime / image->GetDimension(1); + timeSpacing = (2 * m_Controls.ScanDepth->value() / 1000 / speedOfSound) / image->GetDimension(1); } + bool isPAImage; if ("US Image" == m_Controls.ImageType->currentText()) { - BFconfig.isPhotoacousticImage = false; + isPAImage = false; } else if ("PA Image" == m_Controls.ImageType->currentText()) { - BFconfig.isPhotoacousticImage = true; + isPAImage = true; } - BFconfig.partial = m_Controls.Partial->isChecked(); - BFconfig.CropBounds[0] = m_Controls.boundLow->value(); - BFconfig.CropBounds[1] = m_Controls.boundHigh->value(); + float reconstructionDepth = m_Controls.ReconstructionDepth->value() / 1000.f; // [m] + + return mitk::BeamformingSettings::New(pitchInMeters, + speedOfSound, timeSpacing, angle, isPAImage, samplesPerLine, reconstructionLines, + image->GetDimensions(), reconstructionDepth, useGPU, 16, delay, apod, + apodizatonArraySize, algorithm); } void PAImageProcessing::EnableControls() { m_Controls.BatchProcessing->setEnabled(true); m_Controls.StepBeamforming->setEnabled(true); m_Controls.StepBandpass->setEnabled(true); m_Controls.StepCropping->setEnabled(true); m_Controls.StepBMode->setEnabled(true); UpdateSaveBoxes(); m_Controls.DoResampling->setEnabled(true); UseResampling(); m_Controls.Logfilter->setEnabled(true); m_Controls.BModeMethod->setEnabled(true); m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.CutoffAbove->setEnabled(true); m_Controls.CutoffBelow->setEnabled(true); - m_Controls.CutoffBeforeBF->setEnabled(true); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.BPSpeedOfSound->setEnabled(true); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.Partial->setEnabled(true); m_Controls.boundHigh->setEnabled(true); m_Controls.boundLow->setEnabled(true); m_Controls.BFAlgorithm->setEnabled(true); - m_Controls.DelayCalculation->setEnabled(true); + m_Controls.ReconstructionDepth->setEnabled(true); m_Controls.ImageType->setEnabled(true); m_Controls.Apodization->setEnabled(true); - m_Controls.UseBP->setEnabled(true); - #ifdef PHOTOACOUSTICS_USE_GPU - m_Controls.UseGPUBf->setEnabled(true); - m_Controls.UseGPUBmode->setEnabled(true); - #endif +#ifdef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(true); + m_Controls.UseGPUBmode->setEnabled(true); +#endif m_Controls.BPhigh->setEnabled(true); m_Controls.BPlow->setEnabled(true); m_Controls.BPFalloffLow->setEnabled(true); m_Controls.BPFalloffHigh->setEnabled(true); m_Controls.UseImageSpacing->setEnabled(true); UseImageSpacing(); m_Controls.Pitch->setEnabled(true); m_Controls.ElementCount->setEnabled(true); m_Controls.SpeedOfSound->setEnabled(true); m_Controls.Samples->setEnabled(true); m_Controls.Lines->setEnabled(true); m_Controls.Angle->setEnabled(true); m_Controls.buttonApplyBeamforming->setEnabled(true); + m_Controls.UseSignalDelay->setEnabled(true); + m_Controls.SignalDelay->setEnabled(true); } void PAImageProcessing::DisableControls() { m_Controls.BatchProcessing->setEnabled(false); m_Controls.StepBeamforming->setEnabled(false); m_Controls.StepBandpass->setEnabled(false); m_Controls.StepCropping->setEnabled(false); m_Controls.StepBMode->setEnabled(false); m_Controls.SaveBeamforming->setEnabled(false); m_Controls.SaveBandpass->setEnabled(false); m_Controls.SaveCropping->setEnabled(false); m_Controls.SaveBMode->setEnabled(false); m_Controls.DoResampling->setEnabled(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.Logfilter->setEnabled(false); m_Controls.BModeMethod->setEnabled(false); m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.CutoffAbove->setEnabled(false); m_Controls.CutoffBelow->setEnabled(false); - m_Controls.CutoffBeforeBF->setEnabled(false); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.BPSpeedOfSound->setEnabled(false); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.Partial->setEnabled(false); m_Controls.boundHigh->setEnabled(false); m_Controls.boundLow->setEnabled(false); m_Controls.BFAlgorithm->setEnabled(false); - m_Controls.DelayCalculation->setEnabled(false); + m_Controls.ReconstructionDepth->setEnabled(false); m_Controls.ImageType->setEnabled(false); m_Controls.Apodization->setEnabled(false); - m_Controls.UseBP->setEnabled(false); - #ifdef PHOTOACOUSTICS_USE_GPU - m_Controls.UseGPUBf->setEnabled(false); - m_Controls.UseGPUBmode->setEnabled(false); - #endif +#ifdef PHOTOACOUSTICS_USE_GPU + m_Controls.UseGPUBf->setEnabled(false); + m_Controls.UseGPUBmode->setEnabled(false); +#endif m_Controls.BPhigh->setEnabled(false); m_Controls.BPlow->setEnabled(false); m_Controls.BPFalloffLow->setEnabled(false); m_Controls.BPFalloffHigh->setEnabled(false); m_Controls.UseImageSpacing->setEnabled(false); m_Controls.ScanDepth->setEnabled(false); m_Controls.Pitch->setEnabled(false); m_Controls.ElementCount->setEnabled(false); m_Controls.SpeedOfSound->setEnabled(false); m_Controls.Samples->setEnabled(false); m_Controls.Lines->setEnabled(false); m_Controls.Angle->setEnabled(false); m_Controls.buttonApplyBeamforming->setEnabled(false); + m_Controls.UseSignalDelay->setEnabled(false); + m_Controls.SignalDelay->setEnabled(false); } void PAImageProcessing::UseImageSpacing() { if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ScanDepth->setDisabled(true); } else { m_Controls.ScanDepth->setEnabled(true); } } #include void BeamformingThread::run() { - mitk::Image::Pointer resultImage = mitk::Image::New(); - mitk::Image::Pointer resultImageBuffer; - std::string errorMessage = ""; - std::function progressHandle = [this](int progress, std::string progressInfo) { - emit updateProgress(progress, progressInfo); - }; - - resultImageBuffer = m_FilterBank->ApplyBeamforming(m_InputImage, m_BFconfig, errorMessage, progressHandle); - mitk::ImageReadAccessor copy(resultImageBuffer); - - resultImage->Initialize(resultImageBuffer); - resultImage->SetSpacing(resultImageBuffer->GetGeometry()->GetSpacing()); - resultImage->SetImportVolume(const_cast(copy.GetData()), 0, 0, mitk::Image::CopyMemory); + mitk::Image::Pointer preprocessedImage = m_InputImage; + if (m_SignalDelay != 0) + { + int cropPixels = std::round(m_SignalDelay / m_BFconfig->GetTimeSpacing() / 1000000); + MITK_INFO << cropPixels; + preprocessedImage = m_FilterBank->ApplyCropping(m_InputImage, cropPixels, 0, 0, 0, 0, m_InputImage->GetDimension(2) - 1); + } - emit result(resultImage); - emit message(errorMessage); + mitk::Image::Pointer resultImage; + std::function progressHandle = [this](int progress, std::string progressInfo) { + emit updateProgress(progress, progressInfo); + }; + resultImage = m_FilterBank->ApplyBeamforming(preprocessedImage, m_BFconfig, progressHandle); + emit result(resultImage, "_bf"); } -void BeamformingThread::setConfig(mitk::BeamformingSettings BFconfig) +void BeamformingThread::setConfig(mitk::BeamformingSettings::Pointer BFconfig) { m_BFconfig = BFconfig; } +void BeamformingThread::setSignalDelay(float delay) +{ + m_SignalDelay = delay; +} + void BeamformingThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BmodeThread::run() { - mitk::Image::Pointer resultImage; + mitk::Image::Pointer resultImage = m_FilterBank->ApplyBmodeFilter(m_InputImage, + m_Method, m_UseLogfilter); - resultImage = m_FilterBank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseGPU, m_UseLogfilter, m_ResampleSpacing); - - emit result(resultImage); + if (m_ResampleSpacing != 0) + { + double desiredSpacing[2]{ m_InputImage->GetGeometry()->GetSpacing()[0], m_ResampleSpacing }; + resultImage = m_FilterBank->ApplyResampling(resultImage, desiredSpacing); + } + emit result(resultImage, "_bmode"); } -void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU) +void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticFilterService::BModeMethod method, bool useGPU) { m_UseLogfilter = useLogfilter; m_ResampleSpacing = resampleSpacing; m_Method = method; m_UseGPU = useGPU; } void BmodeThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void CropThread::run() { mitk::Image::Pointer resultImage; - resultImage = m_FilterBank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, m_CutSliceFirst, m_CutSliceLast); - - emit result(resultImage); + resultImage = m_FilterBank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, m_CutSliceFirst, (m_InputImage->GetDimension(2) - 1) - m_CutSliceLast); + emit result(resultImage, "_cropped"); } void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast) { m_CutAbove = CutAbove; m_CutBelow = CutBelow; m_CutSliceLast = CutSliceLast; m_CutSliceFirst = CutSliceFirst; } void CropThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BandpassThread::run() { - mitk::Image::Pointer resultImage; - - resultImage = m_FilterBank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlphaHighPass, m_TukeyAlphaLowPass); - emit result(resultImage); + mitk::Image::Pointer resultImage = m_FilterBank->ApplyBandpassFilter(m_InputImage, m_BPHighPass, m_BPLowPass, m_TukeyAlphaHighPass, m_TukeyAlphaLowPass); + emit result(resultImage, "_bandpassed"); } void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime) { m_BPHighPass = BPHighPass; m_BPLowPass = BPLowPass; m_TukeyAlphaHighPass = TukeyAlphaHighPass; m_TukeyAlphaLowPass = TukeyAlphaLowPass; m_RecordTime = recordTime; } void BandpassThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h index 8bb5eb860e..1b90f0d277 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h @@ -1,255 +1,242 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef PAImageProcessing_h #define PAImageProcessing_h -#include +#include #include #include #include #include "ui_PAImageProcessingControls.h" -#include "mitkPhotoacousticBeamformingFilter.h" -#include "mitkPhotoacousticBeamformingSettings.h" +#include "mitkBeamformingFilter.h" +#include "mitkBeamformingSettings.h" Q_DECLARE_METATYPE(mitk::Image::Pointer) Q_DECLARE_METATYPE(std::string) /*! * \brief Plugin implementing an interface for the Photoacoustic Algorithms Module * * Beamforming, Image processing as B-Mode filtering, cropping, resampling, as well as batch processing can be performed using this plugin. */ class PAImageProcessing : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT - public: +public: - static const std::string VIEW_ID; + static const std::string VIEW_ID; - PAImageProcessing(); + PAImageProcessing(); protected slots: - void UpperSliceBoundChanged(); - void LowerSliceBoundChanged(); - void SliceBoundsEnabled(); - - void UseResampling(); - void UseLogfilter(); - void SetResampling(); - void UseImageSpacing(); - void UpdateImageInfo(); - - /** \brief Method called when the beamforming thread finishes; - * it adds the image to a new data node and registers it to the worbench's data storage - */ - void HandleBeamformingResults(mitk::Image::Pointer image); - /** \brief Beamforming is being performed in a separate thread to keep the workbench from freezing. - */ - void StartBeamformingThread(); - - /** \brief Method called when the B-mode filter thread finishes; - * it adds the image to a new data node and registers it to the worbench's data storage - */ - void HandleBmodeResults(mitk::Image::Pointer image); - /** \brief B-mode filtering is being performed in a separate thread to keep the workbench from freezing. - */ - void StartBmodeThread(); - - /** \brief Method called when the Cropping thread finishes; - * it adds the image to a new data node and registers it to the worbench's data storage - */ - void HandleCropResults(mitk::Image::Pointer image); - /** \brief Cropping is being performed in a separate thread to keep the workbench from freezing. - */ - void StartCropThread(); - - /** \brief Method called when the bandpass thread finishes; - * it adds the image to a new data node and registers it to the worbench's data storage - */ - void HandleBandpassResults(mitk::Image::Pointer image); - /** \brief Bandpassing is being performed in a separate thread to keep the workbench from freezing. - */ - void StartBandpassThread(); - - void UpdateProgress(int progress, std::string progressInfo); - void PAMessageBox(std::string message); - - void BatchProcessing(); - void UpdateSaveBoxes(); - - void ChangedSOSBandpass(); - void ChangedSOSBeamforming(); - - protected: - virtual void CreateQtPartControl(QWidget *parent) override; - - virtual void SetFocus() override; - - /** \brief called by QmitkFunctionality when DataManager's selection has changed. - * On a change some parameters are internally updated to calculate bounds for GUI elements as the slice selector for beamforming or - * the bandpass filter settings. - */ - virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, - const QList& nodes ) override; - - /** \brief Instance of the GUI controls - */ - Ui::PAImageProcessingControls m_Controls; - - float m_ResampleSpacing; - bool m_UseLogfilter; - std::string m_OldNodeName; - - /** \brief The settings set which is used for beamforming, updated through this class. - */ - mitk::BeamformingSettings BFconfig; - - /** \brief Method for updating the BFconfig by using a selected image and the GUI configuration. - */ - void UpdateBFSettings(mitk::Image::Pointer image); - - void EnableControls(); - void DisableControls(); - - /** \brief Class through which the filters are called. - */ - mitk::PhotoacousticImage::Pointer m_FilterBank; + void UpperSliceBoundChanged(); + void LowerSliceBoundChanged(); + void SliceBoundsEnabled(); + + void UseResampling(); + void UseLogfilter(); + void SetResampling(); + void UseImageSpacing(); + void UpdateImageInfo(); + void UseSignalDelay(); + + /** \brief Beamforming is being performed in a separate thread to keep the workbench from freezing. + */ + void StartBeamformingThread(); + + /** \brief B-mode filtering is being performed in a separate thread to keep the workbench from freezing. + */ + void StartBmodeThread(); + + /** \brief Cropping is being performed in a separate thread to keep the workbench from freezing. + */ + void StartCropThread(); + + /** \brief Method called when the bandpass thread finishes; + * it adds the image to a new data node and registers it to the worbench's data storage + */ + void HandleResults(mitk::Image::Pointer image, std::string nameExtension); + + /** \brief Bandpassing is being performed in a separate thread to keep the workbench from freezing. + */ + void StartBandpassThread(); + + void UpdateProgress(int progress, std::string progressInfo); + void PAMessageBox(std::string message); + + void BatchProcessing(); + void UpdateSaveBoxes(); + + void ChangedSOSBandpass(); + void ChangedSOSBeamforming(); + +protected: + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /** \brief called by QmitkFunctionality when DataManager's selection has changed. + * On a change some parameters are internally updated to calculate bounds for GUI elements as the slice selector for beamforming or + * the bandpass filter settings. + */ + virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, + const QList& nodes) override; + + /** \brief Instance of the GUI controls + */ + Ui::PAImageProcessingControls m_Controls; + + float m_ResampleSpacing; + bool m_UseLogfilter; + std::string m_OldNodeName; + + /** \brief Method for updating the BFconfig by using a selected image and the GUI configuration. + */ + mitk::BeamformingSettings::Pointer CreateBeamformingSettings(mitk::Image::Pointer image); + + void EnableControls(); + void DisableControls(); + + /** \brief Class through which the filters are called. + */ + mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class BeamformingThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; - signals: - void result(mitk::Image::Pointer); - void updateProgress(int, std::string); - void message(std::string); +signals: + void result(mitk::Image::Pointer, std::string nameExtension); + void updateProgress(int, std::string); + void message(std::string); - public: - void setConfig(mitk::BeamformingSettings BFconfig); - void setInputImage(mitk::Image::Pointer image); - void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) - { - m_FilterBank = filterBank; - } +public: + BeamformingThread() : m_SignalDelay(0) {} + void setConfig(mitk::BeamformingSettings::Pointer BFconfig); + void setSignalDelay(float delay); + void setInputImage(mitk::Image::Pointer image); + void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) + { + m_FilterBank = filterBank; + } - protected: - mitk::BeamformingSettings m_BFconfig; - mitk::Image::Pointer m_InputImage; - int m_Cutoff; +protected: + mitk::BeamformingSettings::Pointer m_BFconfig; + mitk::Image::Pointer m_InputImage; + int m_Cutoff; + float m_SignalDelay; // [us] - mitk::PhotoacousticImage::Pointer m_FilterBank; + mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class BmodeThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; - signals: - void result(mitk::Image::Pointer); - - public: - enum BModeMethod { ShapeDetection, Abs }; +signals: + void result(mitk::Image::Pointer, std::string nameExtension); - void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU); - void setInputImage(mitk::Image::Pointer image); - void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) - { - m_FilterBank = filterBank; - } +public: + enum BModeMethod { ShapeDetection, Abs }; + void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticFilterService::BModeMethod method, bool useGPU); + void setInputImage(mitk::Image::Pointer image); + void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) + { + m_FilterBank = filterBank; + } - protected: - mitk::Image::Pointer m_InputImage; +protected: + mitk::Image::Pointer m_InputImage; - mitk::PhotoacousticImage::BModeMethod m_Method; - bool m_UseLogfilter; - double m_ResampleSpacing; - bool m_UseGPU; + mitk::PhotoacousticFilterService::BModeMethod m_Method; + bool m_UseLogfilter; + double m_ResampleSpacing; + bool m_UseGPU; - mitk::PhotoacousticImage::Pointer m_FilterBank; + mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class CropThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: - void result(mitk::Image::Pointer); + void result(mitk::Image::Pointer, std::string nameExtension); public: void setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast); void setInputImage(mitk::Image::Pointer image); - void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; unsigned int m_CutAbove; unsigned int m_CutBelow; unsigned int m_CutSliceLast; unsigned int m_CutSliceFirst; - mitk::PhotoacousticImage::Pointer m_FilterBank; + mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; - class BandpassThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: - void result(mitk::Image::Pointer); + void result(mitk::Image::Pointer, std::string nameExtension); public: void setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime); void setInputImage(mitk::Image::Pointer image); - void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) + void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; float m_BPHighPass; float m_BPLowPass; float m_TukeyAlphaHighPass; float m_TukeyAlphaLowPass; float m_RecordTime; - mitk::PhotoacousticImage::Pointer m_FilterBank; + mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; #endif // PAImageProcessing_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui index 2cf6316fd3..5901dcb238 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui @@ -1,1027 +1,1011 @@ PAImageProcessingControls 0 0 385 1278 0 0 QmitkTemplate <html><head/><body><p><span style=" font-weight:600;">Batch Processing</span></p></body></html> Start Batch Processing Bandpass true Crop true Save false Save false Save true Beamform true BMode true Save true <html><head/><body><p><span style=" font-weight:600;">B-mode Filter Settings</span></p></body></html> - Envelope Detection + Absolute Filter Absolute Filter Envelope Detection Do Resampling true 0 0 13 0 11 3 0.010000000000000 1.000000000000000 0.010000000000000 0.150000000000000 [mm] Resampled Depth Spacing Logarithmic Compression Use GPU QLabel { color: rgb(255, 0, 0) } <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Please select an image!</span></p></body></html> 0 0 Do image processing Apply B-mode Filter Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Bandpass Filter Settings</span></p></body></html> QLayout::SetDefaultConstraint 0 0 0 3 0.010000000000000 200.000000000000000 + + 0.100000000000000 + 1.000000000000000 [MHz] f High Pass [MHz] f Low Pass 0 0 3 200.000000000000000 + + 0.100000000000000 + 1 200.000000000000000 3000.000000000000000 5.000000000000000 1540.000000000000000 [m/s] Speed of Sound 1.000000000000000 0.100000000000000 0.500000000000000 Tukey Window α High Pass 2 1.000000000000000 0.100000000000000 0.000000000000000 Tukey Window α Low Pass <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Bandpass Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Crop Filter Settings</span></p></body></html> 99999 300 Cut Top Cut Bottom 99999 5 800 + + + + false + + + 99999 + + + + + + + Maximal beamformed slice + + + max + + + + + + + false + + + 99999 + + + 10 + + + + + + + minimal beamformed slice + + + min + + + + + + + select slices + + + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Crop Filer Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Beamforming Filter Settings</span></p></body></html> 5 2 - - - - Delay Calculation + + + + + 0 + 0 + + + + 1 + + + 200.000000000000000 + + + 3000.000000000000000 + + + 5.000000000000000 + + + 1540.000000000000000 - + Auto Get Depth true - + Apply Beamforming - + - + Beamforming Method - + [mm] Scan Depth - + 0 0 3 0.010000000000000 9.000000000000000 0.050000000000000 0.300000000000000 - + Transducer Elements - + 0 0 4 300.000000000000000 0.100000000000000 50.000000000000000 - + [mm] Transducer Pitch - + 0 0 64 1024 128 128 - + 0 0 256 16384 256 2048 - + 0 0 64 2048 128 256 - + Samples - + Reconstruction Lines - + true 0 0 100 0 - - - - - 0 - 0 - - - - 900 - - - 10 - - - 0 - - - - + 0 0 DAS DMAS sDMAS - - - - - 0 - 0 - - - - Spherical Wave - - - - Quad. Approx. - - - - - Spherical Wave - - - - - + 0 0 PA Image US Image - + Image Type - + 0 0 Von Hann Hamming Box - + Apodization - - - - - 0 - 0 - - - - 1 - - - 200.000000000000000 - - - 3000.000000000000000 - - - 5.000000000000000 - - - 1540.000000000000000 - - - - + [m/s] Speed of Sound - - - - - - false - - - 99999 - - - - - - - minimal beamformed slice - - - min - - - - + + - - - - - - false - - - 99999 - - - 10 - - - - - - - Maximal beamformed slice - - - max - - - - + + - + - - - - select slices - - - - + Compute On GPU true - - - - true - - - Auto Use Bandpass - - - - + 0 0 1 1.000000000000000 180.000000000000000 27.000000000000000 - + [°] Element Angle - - + + - Cutoff Upper Voxels + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> - - + + - <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> + [mm] Reconstruction Depth + + + + + + + 4 + + + 300.000000000000000 + + + 0.100000000000000 + + + 10.000000000000000 + + + + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + <html><head/><body><p>Some setups' hardware produces signal delays that need to be cropped out of the image before performing beamforming. To do this, select this box.</p></body></html> + + + Consider Hardware Delay [µs] + + + false Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.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/PASimulator.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.cpp index e1b432613a..20109b4428 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.cpp @@ -1,271 +1,256 @@ /*=================================================================== 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 "PASimulator.h" // Qt #include #include #include // mitk #include #include #include #include #include const std::string PASimulator::VIEW_ID = "org.mitk.views.pasimulator"; void PASimulator::SetFocus() { m_Controls.pushButtonShowRandomTissue->setFocus(); } void PASimulator::CreateQtPartControl(QWidget *parent) { m_Controls.setupUi(parent); connect(m_Controls.pushButtonShowRandomTissue, SIGNAL(clicked()), this, SLOT(DoImageProcessing())); - connect(m_Controls.checkBoxGauss, SIGNAL(stateChanged(int)), this, SLOT(ClickedGaussBox())); connect(m_Controls.pushButtonOpenPath, SIGNAL(clicked()), this, SLOT(OpenFolder())); connect(m_Controls.pushButtonOpenBinary, SIGNAL(clicked()), this, SLOT(OpenBinary())); connect(m_Controls.checkBoxGenerateBatch, SIGNAL(clicked()), this, SLOT(UpdateVisibilityOfBatchCreation())); connect(m_Controls.pushButtonAjustWavelength, SIGNAL(clicked()), this, SLOT(UpdateParametersAccordingToWavelength())); connect(m_Controls.checkBoxRngSeed, SIGNAL(clicked()), this, SLOT(ClickedCheckboxFixedSeed())); connect(m_Controls.checkBoxRandomizeParameters, SIGNAL(clicked()), this, SLOT(ClickedRandomizePhysicalParameters())); - m_Controls.spinboxSigma->setEnabled(false); - m_Controls.labelSigma->setEnabled(false); - - std::string home_env = std::string(std::getenv("HOME")); - if (home_env.empty()) + auto home = std::getenv("HOME"); + std::string home_env = ""; + if (home != nullptr) { - home_env = std::string(std::getenv("HOMEPATH")); + home_env = std::string(home); } - if (home_env.empty()) + else { - home_env = ""; + home = std::getenv("HOMEPATH"); + if (home != nullptr) + { + home_env = std::string(home); + } } m_Controls.label_NrrdFilePath->setText(home_env.c_str()); m_PhotoacousticPropertyCalculator = mitk::pa::PropertyCalculator::New(); UpdateVisibilityOfBatchCreation(); ClickedRandomizePhysicalParameters(); ClickedCheckboxFixedSeed(); - ClickedGaussBox(); } void PASimulator::ClickedRandomizePhysicalParameters() { m_Controls.spinboxRandomizeParameters->setEnabled(m_Controls.checkBoxRandomizeParameters->isChecked()); } void PASimulator::ClickedCheckboxFixedSeed() { m_Controls.spinBoxRngSeed->setEnabled(m_Controls.checkBoxRngSeed->isChecked()); } void PASimulator::UpdateParametersAccordingToWavelength() { int wavelength = m_Controls.spinboxWavelength->value(); double bloodOxygenation = m_Controls.spinboxBloodOxygenSaturation->value() / 100; auto result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::pa::PropertyCalculator::TissueType::BLOOD, wavelength, bloodOxygenation); m_Controls.spinboxMaxAbsorption->setValue(result.mua); m_Controls.spinboxMinAbsorption->setValue(result.mua); m_Controls.spinboxBloodVesselScatteringMinimum->setValue(result.mus); m_Controls.spinboxBloodVesselScatteringMaximum->setValue(result.mus); m_Controls.spinboxBloodVesselAnisotropyMinimum->setValue(result.g); m_Controls.spinboxBloodVesselAnisotropyMaximum->setValue(result.g); result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::pa::PropertyCalculator::TissueType::EPIDERMIS, wavelength, bloodOxygenation); m_Controls.spinboxSkinAbsorption->setValue(result.mua); m_Controls.spinboxSkinScattering->setValue(result.mus); m_Controls.spinboxSkinAnisotropy->setValue(result.g); result = m_PhotoacousticPropertyCalculator->CalculatePropertyForSpecificWavelength( mitk::pa::PropertyCalculator::TissueType::STANDARD_TISSUE, wavelength, bloodOxygenation); m_Controls.spinboxBackgroundAbsorption->setValue(result.mua); m_Controls.spinboxBackgroundScattering->setValue(result.mus); m_Controls.spinboxBackgroundAnisotropy->setValue(result.g); } void PASimulator::UpdateVisibilityOfBatchCreation() { m_Controls.widgetBatchFile->setVisible(m_Controls.checkBoxGenerateBatch->isChecked()); } mitk::pa::TissueGeneratorParameters::Pointer PASimulator::GetParametersFromUIInput() { auto parameters = mitk::pa::TissueGeneratorParameters::New(); // Getting settings from UI // General settings parameters->SetXDim(m_Controls.spinboxXDim->value()); parameters->SetYDim(m_Controls.spinboxYDim->value()); parameters->SetZDim(m_Controls.spinboxZDim->value()); - parameters->SetDoVolumeSmoothing(m_Controls.checkBoxGauss->isChecked()); - if (parameters->GetDoVolumeSmoothing()) - parameters->SetVolumeSmoothingSigma(m_Controls.spinboxSigma->value()); + parameters->SetDoPartialVolume(m_Controls.checkBoxPartialVolume->isChecked()); parameters->SetRandomizePhysicalProperties(m_Controls.checkBoxRandomizeParameters->isChecked()); parameters->SetRandomizePhysicalPropertiesPercentage(m_Controls.spinboxRandomizeParameters->value()); parameters->SetVoxelSpacingInCentimeters(m_Controls.spinboxSpacing->value()); parameters->SetUseRngSeed(m_Controls.checkBoxRngSeed->isChecked()); parameters->SetRngSeed(m_Controls.spinBoxRngSeed->value()); // Monte Carlo simulation parameters parameters->SetMCflag(m_Controls.spinboxMcFlag->value()); parameters->SetMCLaunchflag(m_Controls.spinboxLaunchFlag->value()); parameters->SetMCBoundaryflag(m_Controls.spinboxboundaryFlag->value()); parameters->SetMCLaunchPointX(m_Controls.spinboxLaunchpointX->value()); parameters->SetMCLaunchPointY(m_Controls.spinboxLaunchpointY->value()); parameters->SetMCLaunchPointZ(m_Controls.spinboxLaunchpointZ->value()); parameters->SetMCFocusPointX(m_Controls.spinboxFocuspointX->value()); parameters->SetMCFocusPointY(m_Controls.spinboxFocuspointY->value()); parameters->SetMCFocusPointZ(m_Controls.spinboxFocuspointZ->value()); parameters->SetMCTrajectoryVectorX(m_Controls.spinboxTrajectoryVectorX->value()); parameters->SetMCTrajectoryVectorY(m_Controls.spinboxTrajectoryVectorY->value()); parameters->SetMCTrajectoryVectorZ(m_Controls.spinboxTrajectoryVectorZ->value()); parameters->SetMCRadius(m_Controls.spinboxRadius->value()); parameters->SetMCWaist(m_Controls.spinboxWaist->value()); // Vessel settings parameters->SetMaxVesselAbsorption(m_Controls.spinboxMaxAbsorption->value()); parameters->SetMinVesselAbsorption(m_Controls.spinboxMinAbsorption->value()); parameters->SetMaxVesselBending(m_Controls.spinboxMaxBending->value()); parameters->SetMinVesselBending(m_Controls.spinboxMinBending->value()); parameters->SetMaxVesselRadiusInMillimeters(m_Controls.spinboxMaxDiameter->value()); parameters->SetMinVesselRadiusInMillimeters(m_Controls.spinboxMinDiameter->value()); parameters->SetMaxNumberOfVessels(m_Controls.spinboxMaxVessels->value()); parameters->SetMinNumberOfVessels(m_Controls.spinboxMinVessels->value()); parameters->SetMinVesselScattering(m_Controls.spinboxBloodVesselScatteringMinimum->value()); parameters->SetMaxVesselScattering(m_Controls.spinboxBloodVesselScatteringMaximum->value()); parameters->SetMinVesselAnisotropy(m_Controls.spinboxBloodVesselAnisotropyMinimum->value()); parameters->SetMaxVesselAnisotropy(m_Controls.spinboxBloodVesselAnisotropyMaximum->value()); parameters->SetVesselBifurcationFrequency(m_Controls.spinboxBifurcationFrequency->value()); parameters->SetMinVesselZOrigin(m_Controls.spinboxMinSpawnDepth->value()); parameters->SetMaxVesselZOrigin(m_Controls.spinboxMaxSpawnDepth->value()); // Background tissue settings - parameters->SetBackgroundAbsorption(m_Controls.spinboxBackgroundAbsorption->value()); + parameters->SetMinBackgroundAbsorption(m_Controls.spinboxBackgroundAbsorption->value()); + parameters->SetMaxBackgroundAbsorption(m_Controls.spinboxBackgroundAbsorption->value()); parameters->SetBackgroundScattering(m_Controls.spinboxBackgroundScattering->value()); parameters->SetBackgroundAnisotropy(m_Controls.spinboxBackgroundAnisotropy->value()); // Air settings parameters->SetAirThicknessInMillimeters(m_Controls.spinboxAirThickness->value()); //Skin tissue settings parameters->SetSkinThicknessInMillimeters(m_Controls.spinboxSkinThickness->value()); parameters->SetSkinAbsorption(m_Controls.spinboxSkinAbsorption->value()); parameters->SetSkinScattering(m_Controls.spinboxSkinScattering->value()); parameters->SetSkinAnisotropy(m_Controls.spinboxSkinAnisotropy->value()); parameters->SetCalculateNewVesselPositionCallback(&mitk::pa::VesselMeanderStrategy::CalculateRandomlyDivergingPosition); return parameters; } void PASimulator::DoImageProcessing() { int numberOfVolumes = 1; if (m_Controls.checkBoxGenerateBatch->isChecked()) { if (m_Controls.labelBinarypath->text().isNull() || m_Controls.labelBinarypath->text().isEmpty()) { QMessageBox::warning(nullptr, QString("Warning"), QString("You need to specify the binary first!")); return; } numberOfVolumes = m_Controls.spinboxNumberVolumes->value(); if (numberOfVolumes < 1) { QMessageBox::warning(nullptr, QString("Warning"), QString("You need to create at least one volume!")); return; } } auto tissueParameters = GetParametersFromUIInput(); for (int volumeIndex = 0; volumeIndex < numberOfVolumes; volumeIndex++) { mitk::pa::InSilicoTissueVolume::Pointer volume = mitk::pa::InSilicoTissueGenerator::GenerateInSilicoData(tissueParameters); mitk::Image::Pointer tissueVolume = volume->ConvertToMitkImage(); if (m_Controls.checkBoxGenerateBatch->isChecked()) { std::string nrrdFilePath = m_Controls.label_NrrdFilePath->text().toStdString(); std::string tissueName = m_Controls.lineEditTissueName->text().toStdString(); std::string binaryPath = m_Controls.labelBinarypath->text().toStdString(); long numberOfPhotons = m_Controls.spinboxNumberPhotons->value() * 1000L; auto batchParameters = mitk::pa::SimulationBatchGeneratorParameters::New(); batchParameters->SetBinaryPath(binaryPath); batchParameters->SetNrrdFilePath(nrrdFilePath); batchParameters->SetNumberOfPhotons(numberOfPhotons); batchParameters->SetTissueName(tissueName); batchParameters->SetVolumeIndex(volumeIndex); batchParameters->SetYOffsetLowerThresholdInCentimeters(m_Controls.spinboxFromValue->value()); batchParameters->SetYOffsetUpperThresholdInCentimeters(m_Controls.spinboxToValue->value()); batchParameters->SetYOffsetStepInCentimeters(m_Controls.spinboxStepValue->value()); mitk::pa::SimulationBatchGenerator::WriteBatchFileAndSaveTissueVolume(batchParameters, tissueVolume); } else { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetData(tissueVolume); dataNode->SetName(m_Controls.lineEditTissueName->text().toStdString()); this->GetDataStorage()->Add(dataNode); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(this->GetDataStorage()); } } } -void PASimulator::ClickedGaussBox() -{ - if (m_Controls.checkBoxGauss->isChecked()) - { - m_Controls.spinboxSigma->setEnabled(true); - m_Controls.labelSigma->setEnabled(true); - } - else - { - m_Controls.spinboxSigma->setEnabled(false); - m_Controls.labelSigma->setEnabled(false); - } -} - void PASimulator::OpenFolder() { m_Controls.label_NrrdFilePath->setText(QFileDialog::getExistingDirectory().append("/")); } void PASimulator::OpenBinary() { m_Controls.labelBinarypath->setText(QFileDialog::getOpenFileName()); } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.h b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.h index b002562b30..d6f8492faa 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulator.h @@ -1,77 +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 PASimulator_h #define PASimulator_h #include #include #include "ui_PASimulatorControls.h" #include "mitkPATissueGenerator.h" #include "mitkPATissueGeneratorParameters.h" #include "mitkPAInSilicoTissueVolume.h" #include "mitkPAPropertyCalculator.h" #include "mitkPASimulationBatchGenerator.h" /** \brief PASimulator \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkAbstractView \ingroup ${plugin_target}_internal */ class PASimulator : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; protected slots: /// \brief Called when the user clicks the GUI button void DoImageProcessing(); - void ClickedGaussBox(); void ClickedCheckboxFixedSeed(); void ClickedRandomizePhysicalParameters(); void OpenFolder(); void OpenBinary(); void UpdateVisibilityOfBatchCreation(); void UpdateParametersAccordingToWavelength(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; Ui::PASimulatorControls m_Controls; mitk::pa::PropertyCalculator::Pointer m_PhotoacousticPropertyCalculator; private: mitk::pa::TissueGeneratorParameters::Pointer GetParametersFromUIInput(); }; #endif // PASimulator_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulatorControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulatorControls.ui index 8e0876504b..4187e1e967 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulatorControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/PASimulatorControls.ui @@ -1,4793 +1,4728 @@ PASimulatorControls 0 0 437 655 0 0 Ubuntu Qt::NoContextMenu QmitkTemplate :/org.mitk.gui.qt.photoacousticsimulation/resources/icon.xpm:/org.mitk.gui.qt.photoacousticsimulation/resources/icon.xpm 0 0 415 600 Ubuntu 0 Generator 10 10 391 581 0 0 391 581 0 0 0 0 75 true Volume parameters 0 0 0 25 16777215 25 Tissue name: 0 0 0 25 16777215 25 Size x: 0 0 0 25 16777215 25 50 false Spacing: 0 0 0 25 16777215 25 PhotoacousticTissue 0 0 0 25 16777215 25 1 9999 - 140 + 35 0 0 0 25 16777215 25 y: 0 0 0 25 16777215 25 9999 - 200 + 50 0 0 0 25 16777215 25 z: 0 0 0 25 16777215 25 9999 - 200 + 50 0 0 0 25 16777215 25 voxels Qt::Horizontal 40 20 0 0 0 25 16777215 25 - 2 + 5 0.010000000000000 - 0.030000000000000 + 0.120000000000000 0 0 0 25 16777215 25 cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 Randomize: - + 0 0 0 25 16777215 25 - Partial volume effects: + Custom seed: - + 0 0 0 25 16777215 25 - Custom seed: + Partial volume effects: + + + + + + + Generate batch file output: 0 0 0 25 16777215 25 false - + true 0 0 0 25 16777215 25 - false + true - + true 0 0 0 25 16777215 25 + + true + + + + + + + + + + false + 0 0 0 25 16777215 25 sigma: 0 0 0 25 16777215 25 0 100.000000000000000 0.010000000000000 2.000000000000000 0 0 0 25 16777215 25 % Qt::Horizontal 40 20 - - - - - - 0 - 0 - - - - - 0 - 25 - - - - - 16777215 - 25 - - - - sigma: - - - + - + 0 0 0 25 16777215 25 - 10.000000000000000 - - - 0.100000000000000 + 999999999 - 1.000000000000000 + 1337 - - - - 0 - 0 - - - - - 0 - 25 - - - - - 16777215 - 25 - - - - voxels - - - - - + Qt::Horizontal 40 20 - + - - - - 0 - 0 - - - - - 0 - 25 - + + + Qt::Horizontal - + - 16777215 - 25 + 40 + 20 - - 999999999 - - - 170704057 - - + + + + + - + Qt::Horizontal 40 20 - - - - - - Generate batch file output: - - - - - - - - - - false - - - - - Number of volumes to generate: 1 9999999 1 Qt::Horizontal 40 20 Save generated tissue path: 0 0 50 0 50 16777215 open Path to MitkMcxyz binary: 0 0 50 0 50 16777215 open From (cm): 0 0 0 25 16777215 25 -100000.000000000000000 100000.000000000000000 0.100000000000000 -1.800000000000000 To (cm): 0 0 0 25 16777215 25 -10000.000000000000000 10000.000000000000000 0.100000000000000 1.800000000000000 Step: 0 0 0 25 16777215 25 -10000.000000000000000 10000.000000000000000 0.010000000000000 0.120000000000000 Number of Photons (x1000): 0 999999999 1 100000 0 0 Generate Tissue Qt::Vertical 20 40 Tissue 10 10 391 581 0 0 391 581 0 0 0 0 0 0 0 25 16777215 25 11 75 false true false Air Parameters 0 0 0 25 16777215 25 50 false Thickness: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 false true false Background Parameters 0 0 0 25 16777215 25 Absorption coefficient: 0 0 0 25 16777215 25 Scattering coefficient: 0 0 0 25 16777215 25 Anisotropy facor: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 false true false Skin Parameters 0 0 0 25 16777215 25 Thickness: 0 0 0 25 16777215 25 Absorption coefficient: 0 0 0 25 16777215 25 Scattering coefficient: 0 0 0 25 16777215 25 Anisotropy facor: 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 11 75 true 0 0 0 25 16777215 25 999.990000000000009 0.100000000000000 12.000000000000000 0 0 0 25 16777215 25 mm Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 true 0 0 0 25 16777215 25 5 0.010000000000000 0.100000000000000 0.100000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 5 0.010000000000000 1000.000000000000000 0.500000000000000 15.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 5 0.010000000000000 1.000000000000000 0.010000000000000 0.900000000000000 Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true 0 0 0 25 16777215 25 75 true 0 0 0 25 16777215 25 0.100000000000000 0.000000000000000 0 0 0 25 16777215 25 mm Qt::Horizontal 40 20 0 0 0 25 16777215 25 5 0.010000000000000 0.100000000000000 3.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 5 0.010000000000000 1000.000000000000000 0.500000000000000 20.000000000000000 0 0 0 25 16777215 25 per cm Qt::Horizontal 40 20 0 0 0 25 16777215 25 5 0.010000000000000 1.000000000000000 0.010000000000000 0.900000000000000 Qt::Horizontal 40 20 0 0 0 10 16777215 10 11 75 true Qt::Vertical 20 40 Vessels 10 10 391 581 0 0 391 581 0 0 0 0 75 true Vessel Parameters 0 25 16777215 25 The number of bloos vessels to generate Count: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0 25 16777215 25 The radius of the blood vessels in mm Radius: 0 25 16777215 25 the absorption coefficient refers to the number of absorption events per centimeter. Absorption: 0 25 16777215 25 The reduced scattering coefficient. It refers to the amount of scattering events per centimeter. Scattering: 0 25 16777215 25 The anisotropy factor is the probability of a photon to not change its direction after a scattering event. Anisotropy factor: 0 25 16777215 25 The bifurcation frequency determines how often the vessel should bifurcate. The vessel will bifurcate after meandering a mean of the specified amount of voxels. When given a value of 0, the vessel will never bifurcate. Bifurcation frequency: 0 25 16777215 25 The curvedness it a setting to determine how much the vessel is allowed to bend during creation. A value of 0 refers to no bending at all and a value of 5 is the maximum. Curvedness: 0 25 16777215 25 The spawn depth defines the depth range in which the vessels enter the volume. Spawn depth: 0 25 16777215 25 The minimum number of blood vessels 0 1 0 25 16777215 25 to 0 25 16777215 25 The maximum number of blood vessels 1 0 25 16777215 25 Vessels Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum radius 5 2.250000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum radius 5 4.050000000000000 0 25 16777215 25 mm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum absorption coefficient 5 0.010000000000000 2.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum absorption coefficient 5 0.010000000000000 8.000000000000000 0 25 16777215 25 per cm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum scattering 5 0.010000000000000 999.000000000000000 1.000000000000000 15.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The minimum scattering 5 0.010000000000000 999.000000000000000 1.000000000000000 15.000000000000000 0 25 16777215 25 per cm Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum anisotropy factor 5 0.010000000000000 1.000000000000000 0.100000000000000 0.900000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximum anisotropy factor 5 0.010000000000000 1.000000000000000 0.100000000000000 0.900000000000000 Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The bifurcation frequency determines how often the vessel should bifurcate. The vessel will bifurcate after meandering a mean of the specified amount of voxels. When given a value of 0, the vessel will never bifurcate. 0 1.000000000000000 999999999.000000000000000 5.000000000000000 50.000000000000000 0 25 16777215 25 voxels Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimal curvedness of the vessel. A value of 0 refers to no bending at all and a value of 5 is the maximum. 5.000000000000000 0.000000000000000 0 25 16777215 25 to 0 25 16777215 25 The maximal curvedness of the vessel. A value of 0 refers to no bending at all and a value of 5 is the maximum. 5.000000000000000 0.010000000000000 0.200000000000000 0 25 16777215 25 A.U. Qt::Horizontal QSizePolicy::Expanding 60 20 0 25 16777215 25 The minimum spawn depth 5 0.010000000000000 2.200000000000000 0 25 16777215 25 to 0 25 16777215 25 the maximum spawn depth 5 0.010000000000000 4.200000000000000 0 25 16777215 25 cm Qt::Horizontal QSizePolicy::Expanding 60 20 Qt::Vertical 20 40 Monte Carlo 10 10 391 581 0 0 391 581 0 0 0 0 75 true Monte Carlo Parameters 0 25 16777215 25 50 false General: 0 0 0 25 16777215 25 Mcflag: 0 0 0 25 16777215 25 Launchflag: 0 0 0 25 16777215 25 Boundaryflag: 0 0 0 25 16777215 25 1 4 Qt::Horizontal 40 20 0 0 0 25 16777215 25 0 0 Qt::Horizontal 40 20 0 0 0 25 16777215 25 1 2 Qt::Horizontal 40 20 0 25 16777215 25 50 false Initial launch point: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 Qt::Horizontal 40 20 0 25 16777215 25 50 false Focus point: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 Qt::Horizontal 40 20 0 25 16777215 25 50 false Trajectory vector: 0 25 16777215 25 x 0 25 16777215 25 4 1000000.000000000000000 0.000000000000000 0 25 16777215 25 y 0 25 16777215 25 4 1000000.000000000000000 0.342000000000000 0 25 16777215 25 z 0 25 16777215 25 4 1000000.000000000000000 0.939700000000000 Qt::Horizontal 40 20 radius: waist: 4 1000.000000000000000 0.500000000000000 Qt::Horizontal 40 20 4 1000.000000000000000 0.010000000000000 Qt::Horizontal 40 20 Qt::Vertical 20 40 Wavelength 10 10 391 581 0 0 391 581 Qt::NoContextMenu 0 0 0 0 75 true Adjust physical properties by wavelength false 16777215 250 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size: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:11pt;">This widget enables the adjustment of the physical properties of the tissue according to a selected wavelength of the light and the oxygen saturation of the blood.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">The algorithm and measurements were provided by the publication </span><span style=" font-size:11pt; font-weight:600;">Optical properties of biological tissues: a review </span><span style=" font-size:11pt;">by Steve L. Jacques.</span></p></body></html> 0 0 0 25 16777215 25 Wavelength: 0 0 0 25 16777215 25 Vessel oxygen saturation: 0 0 0 25 16777215 25 0 300.000000000000000 1000.000000000000000 650.000000000000000 Qt::Horizontal 40 20 0 0 0 25 16777215 25 0 100.000000000000000 75.000000000000000 0 0 0 25 16777215 25 % Qt::Horizontal 40 20 Adjust tissue properties Qt::Vertical 20 40 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.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp index 1307b4045e..99ef6fcaf9 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp @@ -1,114 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // render window manager plugin #include "QmitkRenderWindowManagerView.h" // blueberry #include #include // mitk core #include #include +// org.mitk.gui.qt.common +#include + const std::string QmitkRenderWindowManagerView::VIEW_ID = "org.mitk.views.renderwindowmanager"; void QmitkRenderWindowManagerView::SetFocus() { // nothing here } void QmitkRenderWindowManagerView::CreateQtPartControl(QWidget* parent) { + m_Parent = parent; // create GUI widgets m_Controls.setupUi(parent); // add custom render window manager UI widget to the 'renderWindowManagerTab' m_RenderWindowManipulatorWidget = new QmitkRenderWindowManipulatorWidget(GetDataStorage(), parent); m_RenderWindowManipulatorWidget->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); m_Controls.verticalLayout->addWidget(m_RenderWindowManipulatorWidget); SetControlledRenderer(); for (const auto& renderer : m_ControlledRenderer) { m_Controls.comboBoxRenderWindowSelection->addItem(renderer->GetName()); } + SetUpConnections(); + OnRenderWindowSelectionChanged(m_Controls.comboBoxRenderWindowSelection->itemText(0)); +} +void QmitkRenderWindowManagerView::SetUpConnections() +{ connect(m_Controls.comboBoxRenderWindowSelection, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnRenderWindowSelectionChanged(const QString&))); connect(m_RenderWindowManipulatorWidget, SIGNAL(AddLayerButtonClicked()), this, SLOT(OnAddLayerButtonClicked())); + + m_ModelViewSelectionConnector = std::make_unique(); + try + { + m_ModelViewSelectionConnector->SetView(m_RenderWindowManipulatorWidget->GetLayerStackTableView()); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector = std::make_unique(); } void QmitkRenderWindowManagerView::SetControlledRenderer() { const mitk::RenderingManager::RenderWindowVector allRegisteredRenderWindows = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); mitk::BaseRenderer* baseRenderer = nullptr; for (const auto &renderWindow : allRegisteredRenderWindows) { baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); if (nullptr != baseRenderer) { m_ControlledRenderer.push_back(baseRenderer); } } m_RenderWindowManipulatorWidget->SetControlledRenderer(m_ControlledRenderer); } void QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged(const QString &renderWindowId) { m_RenderWindowManipulatorWidget->SetActiveRenderWindow(renderWindowId); } void QmitkRenderWindowManagerView::OnAddLayerButtonClicked() { - QList nodes = GetDataManagerSelection(); - for (mitk::DataNode* dataNode : nodes) + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(m_Parent, "Select nodes to add to the render window", ""); + dialog->SetDataStorage(GetDataStorage()); + dialog->SetSelectOnlyVisibleNodes(true); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + + if (QDialog::Accepted == dialog->exec()) { - if (nullptr != dataNode) + auto nodes = dialog->GetSelectedNodes(); + for (mitk::DataNode* dataNode : nodes) { - m_RenderWindowManipulatorWidget->AddLayer(dataNode); - - // get child nodes of the current node - mitk::DataStorage::SetOfObjects::ConstPointer derivedNodes = GetDataStorage()->GetDerivations(dataNode, nullptr, false); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = derivedNodes->Begin(); it != derivedNodes->End(); ++it) + if (nullptr != dataNode) { - m_RenderWindowManipulatorWidget->AddLayer(it->Value()); + m_RenderWindowManipulatorWidget->AddLayer(dataNode); + + // get child nodes of the current node + mitk::DataStorage::SetOfObjects::ConstPointer derivedNodes = GetDataStorage()->GetDerivations(dataNode, nullptr, false); + for (mitk::DataStorage::SetOfObjects::ConstIterator it = derivedNodes->Begin(); it != derivedNodes->End(); ++it) + { + m_RenderWindowManipulatorWidget->AddLayer(it->Value()); + } } } } + + delete dialog; +} + +void QmitkRenderWindowManagerView::SetSelectionProvider() +{ + m_SelectionProvider = QmitkDataNodeSelectionProvider::Pointer(new QmitkDataNodeSelectionProvider); + m_SelectionProvider->SetItemSelectionModel(m_RenderWindowManipulatorWidget->GetLayerStackTableView()->selectionModel()); + GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(m_SelectionProvider)); + + // This function is called during the creation of the GUI. It is overridden in this class to create a custom selection provider. + // This view is used as a selection provider (not used as a selection listener) + m_SelectionServiceConnector->SetAsSelectionProvider(m_SelectionProvider.GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } void QmitkRenderWindowManagerView::NodeAdded(const mitk::DataNode* node) { bool global = false; node->GetBoolProperty("globalObject_RWM", global); if (global) { // initially insert new point set node into the node list of all render windows // the node object of a new point set won't be visible due to its "helper object" property set to true m_RenderWindowManipulatorWidget->AddLayerToAllRenderer(const_cast(node)); } else { // initially set new node as invisible in all render windows // this way, each single renderer overwrites the common renderer and the node is invisible // until it is inserted into the node list of a render windows m_RenderWindowManipulatorWidget->HideDataNodeInAllRenderer(node); } } diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h index ba9743fb77..3d3968f752 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h @@ -1,82 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWMANAGERVIEW_H #define QMITKRENDERWINDOWMANAGERVIEW_H // render window manager plugin #include "ui_QmitkRenderWindowManagerControls.h" // render window manager UI module #include // blueberry #include -// qt +// mitk gui qt common plugin #include +#include "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" /** * @brief RenderWindowManager */ class QmitkRenderWindowManagerView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: /** * @brief Called when the user changes the render window selection in the combo box. * * @param renderWindowId The text inside the combo box. */ void OnRenderWindowSelectionChanged(const QString &renderWindowId); /** * @brief Called when the 'AddLayer'-button of he render window manipulator widget has been pushed. */ void OnAddLayerButtonClicked(); private: + void SetUpConnections(); void SetControlledRenderer(); + /** + * @brief see QmitkAbstractView + */ + void SetSelectionProvider() override; /** * @brief Reacts to a node that has been added to the data storage. * 1. Insert new node into the node list of all render windows, if it is an "globalObject_RWM"-node. * or else * 2. Set data node invisible in all render windows, as soon as the node is added to the data storage. */ void NodeAdded(const mitk::DataNode* node) override; // the Qt parent of our GUI QWidget* m_Parent; Ui::QmitkRenderWindowManagerControls m_Controls; QmitkRenderWindowManipulatorWidget* m_RenderWindowManipulatorWidget; + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; + QmitkDataNodeSelectionProvider::Pointer m_SelectionProvider; + RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; }; #endif // QMITKRENDERWINDOWMANAGERVIEW_H 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 )