diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt index b7c6977fda..887f5c0d30 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt @@ -1,339 +1,339 @@ cmake_minimum_required(VERSION 3.14.5 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 2018.04.99 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) 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 macOS 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 #----------------------------------------------------------------------------- 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 ) + catch ( const 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/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index f7d9d76817..fe69ff85fe 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,660 +1,661 @@ ################################################################## # # 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) # this would turn on unused parameter warnings, but unfortunately MSVC cannot # distinguish yet between internal and external headers so this would be triggered # a lot by external code. There is support for it on the way so this line could be # reactivated after https://gitlab.kitware.com/cmake/cmake/issues/17904 has been fixed. # mitkFunctionCheckCAndCXXCompilerFlags("/w34100" 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=class-memaccess" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-copy" module_c_flags module_cxx_flags) + mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" 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}) # 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/CMakeLists.txt b/CMakeLists.txt index 47d68ca752..71a90251b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1458 +1,1458 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.14.5) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.14/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2018.04.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") set(MITK_DIR_PLUS_EXTENSION_DIRS ${MITK_SOURCE_DIR} ${MITK_EXTENSION_DIRS}) #----------------------------------------------------------------------------- # 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) include(mitkFunctionAddLibrarySearchPaths) 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 macOS version #----------------------------------------------------------------------------- # The minimum supported macOS version is 10.13. If you use a version less than 10.13, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE macos_version) if (macos_version VERSION_LESS "10.13") message(WARNING "Detected macOS version \"${macos_version}\" is not supported anymore. Minimum required macOS version is at least 10.13.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.13) message(WARNING "Detected macOS deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required macOS version is at least 10.13.") 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 2017 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) message(FATAL_ERROR "Microsoft Visual Studio 2017 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) #----------------------------------------------------------------------------- # ----------------------------------------- # 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) option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) 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 option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION 5.11.1) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) list(APPEND MITK_QT5_COMPONENTS DBus) elseif(UNIX) list(APPEND MITK_QT5_COMPONENTS X11Extras) endif() # Hint at default install locations of Qt if(NOT Qt5_DIR) if(MSVC) set(_dir_candidates "C:/Qt") if(CMAKE_GENERATOR MATCHES "^Visual Studio [0-9]+ ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") elseif(CMAKE_GENERATOR MATCHES "Ninja") include(mitkFunctionGetMSVCVersion) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_PRODUCT_NAME MATCHES "^Visual Studio ([0-9]+)") set(_compilers "msvc${CMAKE_MATCH_1}") endif() endif() if(_compilers MATCHES "[0-9]+") if (CMAKE_MATCH_0 EQUAL 2019) list(APPEND _compilers "msvc2017") # Binary compatible to 2019 endif() endif() else() set(_dir_candidates ~/Qt) if(APPLE) set(_compilers clang) else() list(APPEND _dir_candidates /opt/Qt) set(_compilers gcc) endif() endif() if(CMAKE_SIZEOF_VOID_P EQUAL 8) foreach(_compiler ${_compilers}) list(APPEND _compilers64 "${_compiler}_64") endforeach() set(_compilers ${_compilers64}) endif() foreach(_dir_candidate ${_dir_candidates}) get_filename_component(_dir_candidate ${_dir_candidate} REALPATH) foreach(_compiler ${_compilers}) set(_glob_expression "${_dir_candidate}/5.*/${_compiler}") file(GLOB _hints ${_glob_expression}) list(SORT _hints) list(APPEND MITK_QT5_HINTS ${_hints}) endforeach() endforeach() endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED HINTS ${MITK_QT5_HINTS}) 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 option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) option(MITK_USE_OpenMP "Use OpenMP" OFF) option(MITK_USE_Python3 "Use Python 3" 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() foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) file(GLOB _extBuildConfigFiles ${MITK_EXTENSION_DIR}/CMake/BuildConfigurations/*.cmake) foreach(_extBuildConfigFile ${_extBuildConfigFiles}) get_filename_component(_extBuildConfigFile ${_extBuildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_extBuildConfigFile}) endforeach() list(REMOVE_DUPLICATES _buildConfigs) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) # ----------------------------------------- # Custom dependency logic option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") if(MITK_USE_cpprestsdk) find_package(OpenSSL QUIET) if(NOT OpenSSL_FOUND) set(openssl_message "Could not find OpenSSL (dependency of C++ REST SDK).\n") if(UNIX) if(APPLE) set(openssl_message "${openssl_message}Please install it using your favorite package management " "system (i.e. Homebrew or MacPorts).\n") else() set(openssl_message "${openssl_message}Please install the dev package of OpenSSL (i.e. libssl-dev).\n") endif() else() set(openssl_message "${openssl_message}Please install Win32 OpenSSL:\n" " https://slproweb.com/products/Win32OpenSSL.html\n") endif() set(openssl_message "${openssl_message}If it still cannot be found, you can hint CMake to find OpenSSL by " "adding/setting the OPENSSL_ROOT_DIR variable to the root directory of an " "OpenSSL installation. Make sure to clear variables of partly found " "versions of OpenSSL before, or they will be mixed up.") message(FATAL_ERROR ${openssl_message}) endif() list(APPEND MITK_USE_Boost_LIBRARIES date_time regex system) if(UNIX) list(APPEND MITK_USE_Boost_LIBRARIES atomic chrono filesystem random thread) endif() list(REMOVE_DUPLICATES MITK_USE_Boost_LIBRARIES) set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "A semi-colon separated list of required Boost libraries" FORCE) endif() if(MITK_USE_Python3) set(MITK_USE_ZLIB ON CACHE BOOL "" FORCE) if(APPLE AND CMAKE_FRAMEWORK_PATH AND CMAKE_FRAMEWORK_PATH MATCHES "python3\\.?([0-9]+)") find_package(Python3 3.${CMAKE_MATCH_1} EXACT REQUIRED COMPONENTS Interpreter Development NumPy) else() find_package(Python3 REQUIRED COMPONENTS Interpreter Development NumPy) endif() if(WIN32) string(REPLACE "\\" "/" Python3_STDARCH "${Python3_STDARCH}") string(REPLACE "\\" "/" Python3_STDLIB "${Python3_STDLIB}") string(REPLACE "\\" "/" Python3_SITELIB "${Python3_SITELIB}") endif() 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-Diffusion MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionTestPlugin) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- # Required and enabled C++14 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # Configure pixel types used for ITK image access multiplexing mitkMacroConfigureItkPixelTypes() # Configure module naming conventions set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$") set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$") set(MITK_DEFAULT_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1) #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) # MITK_VERSION set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on macOS all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/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() 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 ) if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -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 mitkFunctionCheckCompilerFlags("/wd4251" MITK_CXX_FLAGS) # warning C4251: 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2' endif() if(APPLE) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -DGL_SILENCE_DEPRECATION") # Apple deprecated OpenGL in macOS 10.14 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-error=deprecated-copy -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) set(MITK_CXX_FLAGS_RELEASE "-U_FORTIFY_SOURCES -D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake/PackageDepends) get_filename_component(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) endif() endforeach() if(NOT MITK_USE_SYSTEM_Boost) set(Boost_NO_SYSTEM_PATHS 1) endif() set(Boost_USE_MULTITHREADED 1) set(Boost_USE_STATIC_LIBS 0) set(Boost_USE_STATIC_RUNTIME 0) set(Boost_ADDITIONAL_VERSIONS 1.68 1.68.0) # We need this later for a DCMTK workaround set(_dcmtk_dir_orig ${DCMTK_DIR}) # This property is populated at the top half of this file get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(MITK_USE_${ep} AND _package) if(_components) find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG) else() # Prefer config mode first because it finds external # Config.cmake files pointed at by _DIR variables. # Otherwise, existing Find.cmake files could fail. 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() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() if(MITK_USE_OpenMP) find_package(OpenMP REQUIRED COMPONENTS CXX) else() find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) elseif(APPLE AND OpenMP_libomp_LIBRARY AND NOT OpenMP_CXX_LIB_NAMES) set(OpenMP_CXX_LIB_NAMES libomp CACHE STRING "" FORCE) get_filename_component(openmp_lib_dir "${OpenMP_libomp_LIBRARY}" DIRECTORY) set(openmp_include_dir "${openmp_lib_dir}/../include") if(EXISTS "${openmp_include_dir}") get_filename_component(openmp_include_dir "${openmp_include_dir}" REALPATH) set(OpenMP_CXX_FLAGS "-Xpreprocessor -fopenmp -I${openmp_include_dir}" CACHE STRING "" FORCE) find_package(OpenMP QUIET COMPONENTS CXX) if(OpenMP_FOUND) set(MITK_USE_OpenMP ON CACHE BOOL "" FORCE) endif() endif() endif() 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 ) + catch ( const 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 set(mitk_apps_fullpath "") foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/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 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${MITK_APPLICATIONS_EXTENSION_DIR}/${directory_name}^^${option_name}") endif() endforeach() 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) set(ALL_MITK_APPS "") set(activated_apps_no 0) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) set(MITK_APPS "") include(${MITK_APPLICATIONS_EXTENSION_DIR}/AppList.cmake) foreach(mitk_app ${MITK_APPS}) 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) list(GET target_info_list 2 executable_name) list(APPEND ALL_MITK_APPS "${MITK_EXTENSION_DIR}/Applications/${directory_name}^^${option_name}^^${executable_name}") if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() endif() endforeach() list(LENGTH ALL_MITK_APPS app_count) 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 ${ALL_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 "${target_dir}/CPackOptions.cmake") include("${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${target_dir}/CPackConfig.cmake") configure_file(${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() # 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() foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Applications) get_filename_component(MITK_APPLICATIONS_EXTENSION_DIR ${MITK_APPLICATIONS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_APPLICATIONS_EXTENSION_DIR}/CMakeLists.txt) add_subdirectory(${MITK_APPLICATIONS_EXTENSION_DIR} Applications) endif() endforeach() #----------------------------------------------------------------------------- # 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/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp index cac1f9ec8b..84d07e1133 100644 --- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureSerializer.cpp @@ -1,63 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkExampleDataStructureSerializer.h" #include "mitkExampleDataStructure.h" #include "mitkIOUtil.h" #include MITK_REGISTER_SERIALIZER(ExampleDataStructureSerializer) mitk::ExampleDataStructureSerializer::ExampleDataStructureSerializer() { } mitk::ExampleDataStructureSerializer::~ExampleDataStructureSerializer() { } std::string mitk::ExampleDataStructureSerializer::Serialize() { const ExampleDataStructure *exData = dynamic_cast(m_Data.GetPointer()); if (exData == nullptr) { MITK_ERROR << " Object at " << (const void *)this->m_Data << " is not an mitk::ExampleDataStructure. Cannot serialize as ExampleDataStructure."; return ""; } std::string filename(this->GetUniqueFilenameInWorkingDirectory()); filename += "_"; filename += m_FilenameHint; filename += ".txt"; std::string fullname(m_WorkingDirectory); fullname += "/"; fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str()); try { mitk::IOUtil::Save(exData, fullname); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_ERROR << " Error serializing object at " << (const void *)this->m_Data << " to " << fullname << ": " << e.what(); return ""; } return filename; } diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp index b34ebe246c..12b7575b44 100644 --- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureWriterService.cpp @@ -1,97 +1,97 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkExampleDataStructureWriterService.h" // itk includes #include "itksys/SystemTools.hxx" // mitk includes #include "mitkExampleIOMimeTypes.h" mitk::ExampleDataStructureWriterService::ExampleDataStructureWriterService() : AbstractFileWriter(mitk::ExampleDataStructure::GetStaticNameOfClass(), CustomMimeType(mitk::ExampleIOMimeTypes::EXAMPLE_MIMETYPE()), "Default writer for the example data structure") { RegisterService(); } mitk::ExampleDataStructureWriterService::ExampleDataStructureWriterService( const mitk::ExampleDataStructureWriterService &other) : AbstractFileWriter(other) { } mitk::ExampleDataStructureWriterService::~ExampleDataStructureWriterService() { } mitk::ExampleDataStructureWriterService *mitk::ExampleDataStructureWriterService::Clone() const { return new ExampleDataStructureWriterService(*this); } void mitk::ExampleDataStructureWriterService::Write() { MITK_INFO << "Writing ExampleDataStructure"; InputType::ConstPointer input = dynamic_cast(this->GetInput()); if (input.IsNull()) { MITK_ERROR << "Sorry, input to ExampleDataStructureWriterService is nullptr!"; return; } if (this->GetOutputLocation().empty()) { MITK_ERROR << "Sorry, filename has not been set!"; return; } std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetOutputLocation()); ext = itksys::SystemTools::LowerCase(ext); // default extension is .txt if (ext == "") { ext = ".txt"; this->SetOutputLocation(this->GetOutputLocation() + ext); } try { std::ofstream file(this->GetOutputLocation()); if (file.is_open()) { file << input->GetData(); } else { mitkThrow() << "Could not open file " << this->GetOutputLocation() << " for writing."; } MITK_INFO << "Example Data Structure has been written"; } - catch (mitk::Exception e) + catch (const mitk::Exception& e) { MITK_ERROR << e.GetDescription(); } catch (...) { MITK_ERROR << "Unknown error occurred while trying to write file."; } } diff --git a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp index c758617786..a5c0dc36cf 100644 --- a/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp +++ b/Examples/Plugins/org.mitk.example.gui.imaging/src/internal/colourimageprocessing/mitkColourImageProcessor.cpp @@ -1,995 +1,995 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkColourImageProcessor.h" #include #include #include #include namespace mitk { mitkColourImageProcessor::mitkColourImageProcessor() {} mitkColourImageProcessor::~mitkColourImageProcessor() {} template class ScalarToRGBAConverter { const T *dataPtr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; public: ScalarToRGBAConverter(const T *_dataPtr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf) { dataPtr = _dataPtr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarToRGBA(itk::Image *input, mitk::TransferFunction::Pointer tf) { const TType *inputData = input->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // Convert volume { ScalarToRGBAConverter strc(inputData, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertToRGBAImage(mitk::Image::Pointer mitkInput, mitk::TransferFunction::Pointer tf) { MITK_INFO << "convertToRGBAImage"; mitk::Image::Pointer mitkResult = mitk::Image::New(); if (mitkInput->GetPixelType().GetComponentType() == itk::ImageIOBase::CHAR) { // cast to itkImage itk::Image::Pointer itkInput; mitk::CastToItkImage(mitkInput, itkInput); mitkResult = ScalarToRGBA(itkInput, tf); } else if (mitkInput->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { // cast to itkImage itk::Image::Pointer itkInput; mitk::CastToItkImage(mitkInput, itkInput); mitkResult = ScalarToRGBA(itkInput, tf); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitkResult->SetClonedGeometry(mitkInput->GetGeometry()); return mitkResult; } template class ScalarBinaryToRGBAConverter { const T *dataPtr; const B *data2Ptr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; public: ScalarBinaryToRGBAConverter(const T *_dataPtr, const B *_data2Ptr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf) { dataPtr = _dataPtr; data2Ptr = _data2Ptr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline bool sampleBinary(int x, int y, int z) { return data2Ptr[x + y * sizeX + z * sizeXY]; } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { if (sampleBinary(x, y, z)) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); } else { int doff = x + y * sizeX + z * sizeXY; tmpPtr[doff * 4 + 0] = 0; tmpPtr[doff * 4 + 1] = 0; tmpPtr[doff * 4 + 2] = 0; tmpPtr[doff * 4 + 3] = 0; } } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarAndBinaryToRGBA(itk::Image *input, itk::Image *input2, mitk::TransferFunction::Pointer tf) { const TType *inputData = input->GetBufferPointer(); const BType *input2Data = input2->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // for(int i=0;i strc( inputData, input2Data, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertWithBinaryToRGBAImage(mitk::Image::Pointer input1, mitk::Image::Pointer input2, mitk::TransferFunction::Pointer tf) { MITK_INFO << "convertWithBinaryToRGBAImage"; itk::Image::Pointer inputCT; itk::Image::Pointer inputBinary; if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { mitk::CastToItkImage(input1, inputBinary); mitk::CastToItkImage(input2, inputCT); } else if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::CastToItkImage(input1, inputCT); mitk::CastToItkImage(input2, inputBinary); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitk::Image::Pointer resultImage = ScalarAndBinaryToRGBA(inputCT, inputBinary, tf); resultImage->SetClonedGeometry(input1->GetGeometry()); return resultImage; } ////////////////////////////////////////// template class ScalarBinaryColorToRGBAConverter { const T *dataPtr; const B *data2Ptr; unsigned char *tmpPtr; int sizeX; int sizeY; int sizeZ; int sizeXY; int sizeXm1; int sizeYm1; int sizeZm1; mitk::TransferFunction::Pointer tf; int *color; public: ScalarBinaryColorToRGBAConverter(const T *_dataPtr, const B *_data2Ptr, unsigned char *_tmpPtr, int _sizeX, int _sizeY, int _sizeZ, mitk::TransferFunction::Pointer _tf, int *_color) { dataPtr = _dataPtr; data2Ptr = _data2Ptr; tmpPtr = _tmpPtr; sizeX = _sizeX; sizeY = _sizeY; sizeZ = _sizeZ; sizeXY = sizeX * sizeY; sizeXm1 = sizeX - 1; sizeYm1 = sizeY - 1; sizeZm1 = sizeZ - 1; tf = _tf; color = _color; } inline float sample(int x, int y, int z) { return float(dataPtr[x + y * sizeX + z * sizeXY]); } inline bool sampleBinary(int x, int y, int z) { return data2Ptr[x + y * sizeX + z * sizeXY]; } inline int clamp(int x) { if (x < 0) x = 0; else if (x > 255) x = 255; return x; } inline void write(int x, int y, int z, float grayValue, float gx, float gy, float gz) { if (sampleBinary(x, y, z)) { /* gx /= aspect[0]; gy /= aspect[1]; gz /= aspect[2]; */ // Compute the gradient magnitude float t = sqrtf(gx * gx + gy * gy + gz * gz); int doff = x + y * sizeX + z * sizeXY; vtkPiecewiseFunction *opacityTransferFunction = tf->GetScalarOpacityFunction(); vtkPiecewiseFunction *gradientTransferFunction = tf->GetGradientOpacityFunction(); vtkColorTransferFunction *colorTransferFunction = tf->GetColorTransferFunction(); double rgb[3]; colorTransferFunction->GetColor(double(grayValue), rgb); double opacity = opacityTransferFunction->GetValue(double(grayValue)); opacity *= gradientTransferFunction->GetValue(double(0.5f * t)); tmpPtr[doff * 4 + 0] = int(rgb[0] * 255 + 0.5); tmpPtr[doff * 4 + 1] = int(rgb[1] * 255 + 0.5); tmpPtr[doff * 4 + 2] = int(rgb[2] * 255 + 0.5); tmpPtr[doff * 4 + 3] = int(opacity * 255 + 0.5); tmpPtr[doff * 4 + 0] = color[0]; tmpPtr[doff * 4 + 1] = color[1]; tmpPtr[doff * 4 + 2] = color[2]; } else { int doff = x + y * sizeX + z * sizeXY; tmpPtr[doff * 4 + 0] = 0; tmpPtr[doff * 4 + 1] = 0; tmpPtr[doff * 4 + 2] = 0; tmpPtr[doff * 4 + 3] = 0; } } inline void compute(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; gx = sample(x + 1, y, z) - sample(x - 1, y, z); gy = sample(x, y + 1, z) - sample(x, y - 1, z); gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void computeClamp(int x, int y, int z) { float grayValue = sample(x, y, z); float gx, gy, gz; if (x == 0) gx = 2.0f * (sample(x + 1, y, z) - grayValue); else if (x == sizeXm1) gx = 2.0f * (grayValue - sample(x - 1, y, z)); else gx = sample(x + 1, y, z) - sample(x - 1, y, z); if (y == 0) gy = 2.0f * (sample(x, y + 1, z) - grayValue); else if (y == sizeYm1) gy = 2.0f * (grayValue - sample(x, y - 1, z)); else gy = sample(x, y + 1, z) - sample(x, y - 1, z); if (z == 0) gz = 2.0f * (sample(x, y, z + 1) - grayValue); else if (z == sizeZm1) gz = 2.0f * (grayValue - sample(x, y, z - 1)); else gz = sample(x, y, z + 1) - sample(x, y, z - 1); write(x, y, z, grayValue, gx, gy, gz); } inline void compute1D(int y, int z) { int x; x = 0; computeClamp(x, y, z); x++; while (x < sizeX - 1) { compute(x, y, z); x++; } if (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp1D(int y, int z) { int x; x = 0; while (x < sizeX) { computeClamp(x, y, z); x++; } } inline void computeClamp2D(int z) { int y; y = 0; while (y < sizeY) { computeClamp1D(y, z); y++; } } inline void compute2D(int z) { int y; y = 0; computeClamp1D(y, z); y++; while (y < sizeY - 1) { compute1D(y, z); y++; } if (y < sizeY) { computeClamp1D(y, z); y++; } } inline void fillSlices() { int z; for (z = 0; z < sizeZ; z++) { if (z == 0 || z == sizeZ - 1) computeClamp2D(z); else compute2D(z); } } }; template mitk::Image::Pointer mitkColourImageProcessor::ScalarAndBinaryAndColorToRGBA(itk::Image *input, itk::Image *input2, mitk::TransferFunction::Pointer tf, int *color) { const TType *inputData = input->GetBufferPointer(); const BType *input2Data = input2->GetBufferPointer(); typename itk::Image::SizeType ioSize = input->GetLargestPossibleRegion().GetSize(); MITK_INFO << "size input image: " << ioSize[0] << ", " << ioSize[1] << ", " << ioSize[2]; MITK_INFO << "size voxel: " << ioSize[0] * ioSize[1] * ioSize[2]; int voxel = ioSize[0] * ioSize[1] * ioSize[2]; auto RGBABuffer = new unsigned char[4 * voxel]; // for(int i=0;i strc( inputData, input2Data, RGBABuffer, ioSize[0], ioSize[1], ioSize[2], tf, color); strc.fillSlices(); } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = ioSize[0]; dimensions[1] = ioSize[1]; dimensions[2] = ioSize[2]; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); // image->GetGeometry()->SetSpacing(input->GetSpacing()); // image->GetGeometry()->SetOrigin(input->GetOrigin()); return image; } } mitk::Image::Pointer mitkColourImageProcessor::convertWithBinaryAndColorToRGBAImage( mitk::Image::Pointer input1, mitk::Image::Pointer input2, mitk::TransferFunction::Pointer tf, int *color) { MITK_INFO << "convertWithBinaryToRGBAImage"; itk::Image::Pointer inputCT; itk::Image::Pointer inputBinary; if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT) { mitk::CastToItkImage(input1, inputBinary); mitk::CastToItkImage(input2, inputCT); } else if (input1->GetPixelType().GetComponentType() == itk::ImageIOBase::SHORT && input2->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) { mitk::CastToItkImage(input1, inputCT); mitk::CastToItkImage(input2, inputBinary); } else { MITK_ERROR << "unsupported pixel type"; return nullptr; } mitk::Image::Pointer resultImage = ScalarAndBinaryAndColorToRGBA(inputCT, inputBinary, tf, color); resultImage->SetClonedGeometry(input1->GetGeometry()); return resultImage; } mitk::Image::Pointer mitkColourImageProcessor::CombineRGBAImage( const unsigned char *input, const unsigned char *input2, int sizeX, int sizeY, int sizeZ) { int voxel = sizeX * sizeY * sizeZ; auto RGBABuffer = new unsigned char[4 * voxel]; // Convert volume { for (int r = 0; r < voxel; r++) { int rgbaInput1[4]; int rgbaInput2[4]; rgbaInput1[0] = input[r * 4 + 0]; rgbaInput1[1] = input[r * 4 + 1]; rgbaInput1[2] = input[r * 4 + 2]; rgbaInput1[3] = input[r * 4 + 3]; rgbaInput2[0] = input2[r * 4 + 0]; rgbaInput2[1] = input2[r * 4 + 1]; rgbaInput2[2] = input2[r * 4 + 2]; rgbaInput2[3] = input2[r * 4 + 3]; int result[4]; /* float fac1 = rgbaInput1[3]/255.0f; float fac2 = rgbaInput2[3]/255.0f; float sum = fac1+fac2; float cor = 1.0f; if(sum > 1.0f) cor = 1.0f/sum; fac1 *= cor; fac2 *= cor; result[0]= clamp(int(fac1 * rgbaInput1[0] + fac2 * rgbaInput2[0] + 0.5f)); result[1]= clamp(int(fac1 * rgbaInput1[1] + fac2 * rgbaInput2[1] + 0.5f)); result[2]= clamp(int(fac1 * rgbaInput1[2] + fac2 * rgbaInput2[2] + 0.5f)); result[3]= clamp(int(fac1 * rgbaInput1[3] + fac2 * rgbaInput2[3] + 0.5f)); */ if (rgbaInput1[3]) { result[0] = rgbaInput1[0]; result[1] = rgbaInput1[1]; result[2] = rgbaInput1[2]; result[3] = rgbaInput1[3]; } else { result[0] = rgbaInput2[0]; result[1] = rgbaInput2[1]; result[2] = rgbaInput2[2]; result[3] = rgbaInput2[3]; } RGBABuffer[r * 4 + 0] = result[0]; RGBABuffer[r * 4 + 1] = result[1]; RGBABuffer[r * 4 + 2] = result[2]; RGBABuffer[r * 4 + 3] = result[3]; } } // Create MITK Image out of the raw data { mitk::Image::Pointer image = mitk::Image::New(); unsigned int dimensions[3]; dimensions[0] = sizeX; dimensions[1] = sizeY; dimensions[2] = sizeZ; mitk::PixelType pixelType(MakePixelType()); image->Initialize(pixelType, 3, dimensions); image->SetImportChannel(RGBABuffer, 0, Image::ManageMemory); return image; } } mitk::Image::Pointer mitkColourImageProcessor::combineRGBAImage(mitk::Image::Pointer input1, mitk::Image::Pointer input2) { // Order access to a whole Image object try { mitk::ImageReadAccessor img1(input1); const unsigned char *data1 = (const unsigned char *)img1.GetData(); mitk::ImageReadAccessor img2(input2); const unsigned char *data2 = (const unsigned char *)img2.GetData(); unsigned int *dim = input1->GetDimensions(); return CombineRGBAImage(data1, data2, dim[0], dim[1], dim[2]); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << "mitkColourImageProcessor::combineRGBAImage - No access to image data possible." << e.what(); return nullptr; } } } // end namespace mitk diff --git a/Modules/BasicImageProcessing/MiniApps/ImageAndValueArithmetic.cpp b/Modules/BasicImageProcessing/MiniApps/ImageAndValueArithmetic.cpp index d338646ed5..2cc01e421d 100644 --- a/Modules/BasicImageProcessing/MiniApps/ImageAndValueArithmetic.cpp +++ b/Modules/BasicImageProcessing/MiniApps/ImageAndValueArithmetic.cpp @@ -1,148 +1,148 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("File Converter"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("image", "i", mitkCommandLineParser::File, "Input file:", "Input File",us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("value", "v", mitkCommandLineParser::Float, "Input Value:", "Input Value", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output file", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result as double", "Result as double image type", false, true); parser.addArgument("image-right", "right", mitkCommandLineParser::Bool, "Image right (for example Value - Image)", "Image right (for example Value - Image)", false, true); parser.addArgument("add", "add", mitkCommandLineParser::Bool, "Add Left Image and Right Image", "Add Left Image and Right Image", us::Any(false), true); parser.addArgument("subtract", "sub", mitkCommandLineParser::Bool, "Subtract right image from left image", "Subtract right image from left image", us::Any(false), true); parser.addArgument("multiply", "multi", mitkCommandLineParser::Bool, "Multiply Left Image and Right Image", "Multiply Left Image and Right Image", us::Any(false), true); parser.addArgument("divide", "div", mitkCommandLineParser::Bool, "Divide Left Image by Right Image", "Divide Left Image by Right Image", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename = us::any_cast(parsedArgs["image"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); auto nodes = mitk::IOUtil::Load(inputFilename); if (nodes.size() == 0) { MITK_INFO << "No Image Loaded"; return 0; } mitk::Image::Pointer image = dynamic_cast(nodes[0].GetPointer()); if (image.IsNull()) { MITK_INFO << "Loaded data is not of type image"; return 0; } double value = us::any_cast(parsedArgs["value"]); bool resultAsDouble = ConvertToBool(parsedArgs, "as-double"); MITK_INFO << "Output image as double: " << resultAsDouble; mitk::Image::Pointer tmpImage = image->Clone(); if (ConvertToBool(parsedArgs, "image-right")) { if (ConvertToBool(parsedArgs, "add")) { MITK_INFO << " Start Doing Operation: ADD()"; tmpImage = mitk::ArithmeticOperation::Add(value, tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "subtract")) { MITK_INFO << " Start Doing Operation: SUB()"; tmpImage = mitk::ArithmeticOperation::Subtract(value, tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "multiply")) { MITK_INFO << " Start Doing Operation: MULT()"; tmpImage = mitk::ArithmeticOperation::Multiply(value, tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "divide")) { MITK_INFO << " Start Doing Operation: DIV()"; tmpImage = mitk::ArithmeticOperation::Divide(value, tmpImage, resultAsDouble); } } else { if (ConvertToBool(parsedArgs, "add")) { MITK_INFO << " Start Doing Operation: ADD()"; tmpImage = mitk::ArithmeticOperation::Add(tmpImage, value, resultAsDouble); } if (ConvertToBool(parsedArgs, "subtract")) { MITK_INFO << " Start Doing Operation: SUB()"; tmpImage = mitk::ArithmeticOperation::Subtract(tmpImage, value, resultAsDouble); } if (ConvertToBool(parsedArgs, "multiply")) { MITK_INFO << " Start Doing Operation: MULT()"; tmpImage = mitk::ArithmeticOperation::Multiply(tmpImage, value, resultAsDouble); } if (ConvertToBool(parsedArgs, "divide")) { MITK_INFO << " Start Doing Operation: DIV()"; tmpImage = mitk::ArithmeticOperation::Divide(tmpImage, value, resultAsDouble); } } mitk::IOUtil::Save(tmpImage, outputFilename); return EXIT_SUCCESS; } diff --git a/Modules/BasicImageProcessing/MiniApps/LaplacianOfGaussian.cpp b/Modules/BasicImageProcessing/MiniApps/LaplacianOfGaussian.cpp index a04ccfe4bf..febe74d880 100644 --- a/Modules/BasicImageProcessing/MiniApps/LaplacianOfGaussian.cpp +++ b/Modules/BasicImageProcessing/MiniApps/LaplacianOfGaussian.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. ===================================================================*/ #include "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Laplacian of Gaussian"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); // Add command line argument names parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("image", "i", mitkCommandLineParser::File, "Input image:", "Input Image", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output Mask", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("sigma", "s", mitkCommandLineParser::Float, "Sigma for Gaussian", "Sigma for Gaussian", us::Any(), false); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result Image as Type Double", "Result Image as Type Double", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size() == 0) return EXIT_FAILURE; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename = us::any_cast(parsedArgs["image"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); auto nodes = mitk::IOUtil::Load(inputFilename); if (nodes.size() == 0) { MITK_INFO << "No Image Loaded"; return 0; } mitk::Image::Pointer image = dynamic_cast(nodes[0].GetPointer()); if (image.IsNull()) { MITK_INFO << "Loaded data (image) is not of type image"; return 0; } double sigma = us::any_cast(parsedArgs["sigma"]); bool asDouble = ConvertToBool(parsedArgs, "as-double"); mitk::Image::Pointer tmpImage = mitk::TransformationOperation::LaplacianOfGaussian(image, sigma, asDouble); mitk::IOUtil::Save(tmpImage, outputFilename); return EXIT_SUCCESS; } diff --git a/Modules/BasicImageProcessing/MiniApps/MultiResolutionPyramid.cpp b/Modules/BasicImageProcessing/MiniApps/MultiResolutionPyramid.cpp index 804bdde168..863f51d3c8 100644 --- a/Modules/BasicImageProcessing/MiniApps/MultiResolutionPyramid.cpp +++ b/Modules/BasicImageProcessing/MiniApps/MultiResolutionPyramid.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 "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Multi-Resolution Pyramid"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); // Add command line argument names parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("image", "i", mitkCommandLineParser::File, "Input image:", "Input Image", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output Mask", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("output-extension", "e", mitkCommandLineParser::File, "Output file:", "Output Mask", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("number-of-levels", "levels", mitkCommandLineParser::Int, "Numbers of pyramid levels", "Number of pyramid levels", us::Any(), false); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result Image as Type Double", "Result Image as Type Double", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size() == 0) return EXIT_FAILURE; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename = us::any_cast(parsedArgs["image"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); std::string outputExtension = us::any_cast(parsedArgs["output-extension"]); auto nodes = mitk::IOUtil::Load(inputFilename); if (nodes.size() == 0) { MITK_INFO << "No Image Loaded"; return 0; } mitk::Image::Pointer image = dynamic_cast(nodes[0].GetPointer()); if (image.IsNull()) { MITK_INFO << "Loaded data (image) is not of type image"; return 0; } int levels = us::any_cast(parsedArgs["number-of-levels"]); bool asDouble = ConvertToBool(parsedArgs, "as-double"); std::vector results = mitk::TransformationOperation::MultiResolution(image, levels, asDouble); unsigned int level = 1; for (auto image : results) { std::string name = outputFilename + us::Any(levels - level).ToString() + outputExtension; mitk::IOUtil::Save(image, name); ++level; } return EXIT_SUCCESS; } diff --git a/Modules/BasicImageProcessing/MiniApps/ResampleImage.cpp b/Modules/BasicImageProcessing/MiniApps/ResampleImage.cpp index f34805daff..710147e5f5 100644 --- a/Modules/BasicImageProcessing/MiniApps/ResampleImage.cpp +++ b/Modules/BasicImageProcessing/MiniApps/ResampleImage.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 "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Mask Outlier filtering"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--", "-"); // Add command line argument names parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("image", "i", mitkCommandLineParser::File, "Input image:", "Input Image", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output Mask", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("spacing-x", "x", mitkCommandLineParser::Float, "Spacing in x direction", "Spacing in x direction", us::Any(), false); parser.addArgument("spacing-y", "y", mitkCommandLineParser::Float, "Spacing in y direction", "Spacing in y direction", us::Any(), false); parser.addArgument("spacing-z", "z", mitkCommandLineParser::Float, "Spacing in z direction", "Spacing in z direction", us::Any(), false); parser.addArgument("mapping-type", "mapping", mitkCommandLineParser::Int, "0: Origin aligned, 1: Center aligned, 3: Same size", "0: Origin aligned, 1: Center aligned, 3: Same size", us::Any(), true); parser.addArgument("interpolator-type", "interpolator", mitkCommandLineParser::Int, "0: Linear, 1: BSpline 3, 2: Nearest Neighbour, 3: WSinc Hamming, 4: WSinc Welch", "0: Linear, 1: BSpline 3, 2: Nearest Neighbour, 3: WSinc Hamming, 4: WSinc Welch", us::Any(), true); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result Image as Type Double", "Result Image as Type Double", us::Any(false), true); parser.addArgument("round", "round", mitkCommandLineParser::Bool, "Round output", "round output", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size() == 0) return EXIT_FAILURE; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename = us::any_cast(parsedArgs["image"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); auto nodes = mitk::IOUtil::Load(inputFilename); if (nodes.size() == 0) { MITK_INFO << "No Image Loaded"; return 0; } mitk::Image::Pointer image = dynamic_cast(nodes[0].GetPointer()); if (image.IsNull()) { MITK_INFO << "Loaded data (image) is not of type image"; return 0; } mitk::Vector3D spacing; spacing[0] = us::any_cast(parsedArgs["spacing-x"]); spacing[1] = us::any_cast(parsedArgs["spacing-y"]); spacing[2] = us::any_cast(parsedArgs["spacing-z"]); int interpolator = 0; if (parsedArgs.count("interpolator-type")) { interpolator = us::any_cast(parsedArgs["interpolator-type"]); } mitk::ImageMappingInterpolator::Type interpolatorType; switch (interpolator) { case 0: interpolatorType = mitk::ImageMappingInterpolator::Linear; break; case 1: interpolatorType = mitk::ImageMappingInterpolator::BSpline_3; break; case 2: interpolatorType = mitk::ImageMappingInterpolator::NearestNeighbor; break; case 3: interpolatorType = mitk::ImageMappingInterpolator::WSinc_Hamming; break; case 4: interpolatorType = mitk::ImageMappingInterpolator::WSinc_Welch; break; default: interpolatorType = mitk::ImageMappingInterpolator::Linear; } int position = 0; if (parsedArgs.count("mapping-type")) { position = us::any_cast(parsedArgs["mapping-type"]); } mitk::GridInterpolationPositionType gridPosition; switch (position) { case 0: gridPosition = mitk::GridInterpolationPositionType::OriginAligned; break; case 1: gridPosition = mitk::GridInterpolationPositionType::CenterAligned; break; case 2: gridPosition = mitk::GridInterpolationPositionType::SameSize; break; default: gridPosition = mitk::GridInterpolationPositionType::OriginAligned; } bool asDouble = ConvertToBool(parsedArgs, "as-double"); bool round = ConvertToBool(parsedArgs, "round"); mitk::Image::Pointer tmpImage = mitk::TransformationOperation::ResampleImage(image, spacing, interpolatorType, gridPosition, asDouble, round); mitk::IOUtil::Save(tmpImage, outputFilename); return EXIT_SUCCESS; } diff --git a/Modules/BasicImageProcessing/MiniApps/SingleImageArithmetic.cpp b/Modules/BasicImageProcessing/MiniApps/SingleImageArithmetic.cpp index 0d9fd5e674..72a916b5c2 100644 --- a/Modules/BasicImageProcessing/MiniApps/SingleImageArithmetic.cpp +++ b/Modules/BasicImageProcessing/MiniApps/SingleImageArithmetic.cpp @@ -1,168 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("File Converter"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("input", "i", mitkCommandLineParser::File, "Input file:", "Input File",us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output file", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result as double", "Result as double image type", false, true); parser.addArgument("tan", "tan", mitkCommandLineParser::Bool, "Calculate tan operation", "Calculate tan operation", us::Any(false), true); parser.addArgument("atan", "atan", mitkCommandLineParser::Bool, "Calculate atan operation", "Calculate atan operation", us::Any(false), true); parser.addArgument("cos", "cos", mitkCommandLineParser::Bool, "Calculate cos operation", "Calculate cos operation", us::Any(false), true); parser.addArgument("acos", "acos", mitkCommandLineParser::Bool, "Calculate acos operation", "Calculate acos operation", us::Any(false), true); parser.addArgument("sin", "sin", mitkCommandLineParser::Bool, "Calculate sin operation", "Calculate sin operation", us::Any(false), true); parser.addArgument("asin", "asin", mitkCommandLineParser::Bool, "Calculate asin operation", "Calculate asin operation", us::Any(false), true); parser.addArgument("square", "square", mitkCommandLineParser::Bool, "Calculate square operation", "Calculate square operation", us::Any(false), true); parser.addArgument("sqrt", "sqrt", mitkCommandLineParser::Bool, "Calculate sqrt operation", "Calculate sqrt operation", us::Any(false), true); parser.addArgument("abs", "abs", mitkCommandLineParser::Bool, "Calculate abs operation", "Calculate abs operation", us::Any(false), true); parser.addArgument("exp", "exp", mitkCommandLineParser::Bool, "Calculate exp operation", "Calculate exp operation", us::Any(false), true); parser.addArgument("expneg", "expneg", mitkCommandLineParser::Bool, "Calculate expneg operation", "Calculate expneg operation", us::Any(false), true); parser.addArgument("log10", "log10", mitkCommandLineParser::Bool, "Calculate log10 operation", "Calculate log10 operation", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename = us::any_cast(parsedArgs["input"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); auto nodes = mitk::IOUtil::Load(inputFilename); if (nodes.size() == 0) { MITK_INFO << "No Image Loaded"; return 0; } mitk::Image::Pointer image = dynamic_cast(nodes[0].GetPointer()); if (image.IsNull()) { MITK_INFO << "Loaded data is not of type image"; return 0; } bool resultAsDouble = ConvertToBool(parsedArgs, "as-double"); MITK_INFO << "Output image as double: " << resultAsDouble; mitk::Image::Pointer tmpImage = image->Clone(); if (ConvertToBool(parsedArgs, "tan")) { MITK_INFO << " Start Doing Operation: TAN()"; tmpImage = mitk::ArithmeticOperation::Tan(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "atan")) { MITK_INFO << " Start Doing Operation: ATAN()"; tmpImage = mitk::ArithmeticOperation::Atan(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "cos")) { MITK_INFO << " Start Doing Operation: COS()"; tmpImage = mitk::ArithmeticOperation::Cos(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "acos")) { MITK_INFO << " Start Doing Operation: ACOS()"; tmpImage = mitk::ArithmeticOperation::Acos(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "sin")) { MITK_INFO << " Start Doing Operation: SIN()"; tmpImage = mitk::ArithmeticOperation::Sin(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "asin")) { MITK_INFO << " Start Doing Operation: ASIN()"; tmpImage = mitk::ArithmeticOperation::Asin(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "square")) { MITK_INFO << " Start Doing Operation: SQUARE()"; tmpImage = mitk::ArithmeticOperation::Square(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "sqrt")) { MITK_INFO << " Start Doing Operation: SQRT()"; tmpImage = mitk::ArithmeticOperation::Sqrt(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "abs")) { MITK_INFO << " Start Doing Operation: ABS()"; tmpImage = mitk::ArithmeticOperation::Abs(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "exp")) { MITK_INFO << " Start Doing Operation: EXP()"; tmpImage = mitk::ArithmeticOperation::Exp(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "expneg")) { MITK_INFO << " Start Doing Operation: EXPNEG()"; tmpImage = mitk::ArithmeticOperation::ExpNeg(tmpImage, resultAsDouble); } if (ConvertToBool(parsedArgs, "log10")) { MITK_INFO << " Start Doing Operation: LOG10()"; tmpImage = mitk::ArithmeticOperation::Log10(tmpImage, resultAsDouble); } mitk::IOUtil::Save(tmpImage, outputFilename); return EXIT_SUCCESS; } diff --git a/Modules/BasicImageProcessing/MiniApps/TwoImageArithmetic.cpp b/Modules/BasicImageProcessing/MiniApps/TwoImageArithmetic.cpp index f995bf8dce..80f9a8735f 100644 --- a/Modules/BasicImageProcessing/MiniApps/TwoImageArithmetic.cpp +++ b/Modules/BasicImageProcessing/MiniApps/TwoImageArithmetic.cpp @@ -1,134 +1,134 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include static bool ConvertToBool(std::map &data, std::string name) { if (!data.count(name)) { return false; } try { return us::any_cast(data[name]); } - catch (us::BadAnyCastException &) + catch ( const us::BadAnyCastException & ) { return false; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("File Converter"); parser.setCategory("Basic Image Processing"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("--","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("input-left", "i1", mitkCommandLineParser::File, "Input file:", "Input File",us::Any(),false, false, false, mitkCommandLineParser::Input); parser.addArgument("input-right", "i2", mitkCommandLineParser::File, "Input file:", "Input File", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file:", "Output file", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.addArgument("as-double", "double", mitkCommandLineParser::Bool, "Result as double", "Result as double image type", false, true); parser.addArgument("add", "add", mitkCommandLineParser::Bool, "Add Left Image and Right Image", "Add Left Image and Right Image", us::Any(false), true); parser.addArgument("subtract", "sub", mitkCommandLineParser::Bool, "Subtract right image from left image", "Subtract right image from left image", us::Any(false), true); parser.addArgument("multiply", "multi", mitkCommandLineParser::Bool, "Multiply Left Image and Right Image", "Multiply Left Image and Right Image", us::Any(false), true); parser.addArgument("divide", "div", mitkCommandLineParser::Bool, "Divide Left Image by Right Image", "Divide Left Image by Right Image", us::Any(false), true); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputFilename1 = us::any_cast(parsedArgs["input-left"]); std::string inputFilename2 = us::any_cast(parsedArgs["input-right"]); std::string outputFilename = us::any_cast(parsedArgs["output"]); auto nodes1 = mitk::IOUtil::Load(inputFilename1); auto nodes2 = mitk::IOUtil::Load(inputFilename2); if (nodes1.size() == 0) { MITK_INFO << "No Image (left) Loaded"; return 0; } if (nodes2.size() == 0) { MITK_INFO << "No Image (right) Loaded"; return 0; } mitk::Image::Pointer image1 = dynamic_cast(nodes1[0].GetPointer()); mitk::Image::Pointer image2 = dynamic_cast(nodes2[0].GetPointer()); if (image1.IsNull()) { MITK_INFO << "Loaded data (left) is not of type image"; return 0; } if (image2.IsNull()) { MITK_INFO << "Loaded data (right) is not of type image"; return 0; } bool resultAsDouble = ConvertToBool(parsedArgs, "as-double"); MITK_INFO << "Output image as double: " << resultAsDouble; mitk::Image::Pointer tmpImage = image1->Clone(); if (ConvertToBool(parsedArgs, "add")) { MITK_INFO << " Start Doing Operation: ADD()"; tmpImage = mitk::ArithmeticOperation::Add(tmpImage, image2, resultAsDouble); } if (ConvertToBool(parsedArgs, "subtract")) { MITK_INFO << " Start Doing Operation: SUB()"; tmpImage = mitk::ArithmeticOperation::Subtract(tmpImage, image2, resultAsDouble); } if (ConvertToBool(parsedArgs, "multiply")) { MITK_INFO << " Start Doing Operation: MULT()"; tmpImage = mitk::ArithmeticOperation::Multiply(tmpImage, image2, resultAsDouble); } if (ConvertToBool(parsedArgs, "divide")) { MITK_INFO << " Start Doing Operation: DIV()"; tmpImage = mitk::ArithmeticOperation::Divide(tmpImage, image2, resultAsDouble); } mitk::IOUtil::Save(tmpImage, outputFilename); return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLMiniApps/CLMultiForestPrediction.cpp b/Modules/Classification/CLMiniApps/CLMultiForestPrediction.cpp index 2958e02732..5f3709a6f8 100644 --- a/Modules/Classification/CLMiniApps/CLMultiForestPrediction.cpp +++ b/Modules/Classification/CLMiniApps/CLMultiForestPrediction.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. ===================================================================*/ #ifndef mitkForest_cpp #define mitkForest_cpp #include "time.h" #include #include #include #include #include #include #include #include #include #include #include // ----------------------- Forest Handling ---------------------- #include int main(int argc, char* argv[]) { MITK_INFO << "Starting MITK_Forest Mini-App"; ////////////////////////////////////////////////////////////////////////////// // Read Console Input Parameter ////////////////////////////////////////////////////////////////////////////// ConfigFileReader allConfig(argv[1]); bool readFile = true; std::stringstream ss; for (int i = 0; i < argc; ++i ) { MITK_INFO << "-----"<< argv[i]<<"------"; if (readFile) { if (argv[i][0] == '+') { readFile = false; continue; } else { try { allConfig.ReadFile(argv[i]); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_INFO << e.what(); } } } else { std::string input = argv[i]; std::replace(input.begin(), input.end(),'_',' '); ss << input << std::endl; } } allConfig.ReadStream(ss); try { ////////////////////////////////////////////////////////////////////////////// // General ////////////////////////////////////////////////////////////////////////////// int currentRun = allConfig.IntValue("General","Run",0); //int doTraining = allConfig.IntValue("General","Do Training",1); std::string forestPath = allConfig.Value("General","Forest Path"); std::string trainingCollectionPath = allConfig.Value("General","Patient Collection"); std::string testCollectionPath = allConfig.Value("General", "Patient Test Collection", trainingCollectionPath); ////////////////////////////////////////////////////////////////////////////// // Read Default Classification ////////////////////////////////////////////////////////////////////////////// std::vector trainPatients = allConfig.Vector("Training Group",currentRun); std::vector testPatients = allConfig.Vector("Test Group",currentRun); std::vector modalities = allConfig.Vector("Modalities", 0); std::vector outputFilter = allConfig.Vector("Output Filter", 0); std::string trainMask = allConfig.Value("Data","Training Mask"); std::string completeTrainMask = allConfig.Value("Data","Complete Training Mask"); std::string testMask = allConfig.Value("Data","Test Mask"); std::string resultMask = allConfig.Value("Data", "Result Mask"); std::string resultProb = allConfig.Value("Data", "Result Propability"); std::string outputFolder = allConfig.Value("General","Output Folder"); std::string writeDataFilePath = allConfig.Value("Forest","File to write data to"); ////////////////////////////////////////////////////////////////////////////// // Read Data Forest Parameter ////////////////////////////////////////////////////////////////////////////// int testSingleDataset = allConfig.IntValue("Data", "Test Single Dataset",0); std::string singleDatasetName = allConfig.Value("Data", "Single Dataset Name", "none"); std::vector forestVector = allConfig.Vector("Forests", 0); ////////////////////////////////////////////////////////////////////////////// // Read Statistic Parameter ////////////////////////////////////////////////////////////////////////////// std::string statisticFilePath = allConfig.Value("Evaluation", "Statistic output file"); std::string statisticShortFilePath = allConfig.Value("Evaluation", "Statistic short output file"); std::string statisticShortFileLabel = allConfig.Value("Evaluation", "Index for short file"); std::string statisticGoldStandard = allConfig.Value("Evaluation", "Gold Standard Name","GTV"); //bool statisticWithHeader = allConfig.IntValue("Evaluation", "Write header in short file",0); std::vector labelGroupA = allConfig.Vector("LabelsA",0); std::vector labelGroupB = allConfig.Vector("LabelsB",0); std::ofstream timingFile; timingFile.open((statisticFilePath + ".timing").c_str(), std::ios::app); timingFile << statisticShortFileLabel << ";"; std::time_t lastTimePoint; time(&lastTimePoint); ////////////////////////////////////////////////////////////////////////////// // Read Images ////////////////////////////////////////////////////////////////////////////// std::vector usedModalities; for (std::size_t i = 0; i < modalities.size(); ++i) { usedModalities.push_back(modalities[i]); } usedModalities.push_back(trainMask); usedModalities.push_back(completeTrainMask); usedModalities.push_back(testMask); usedModalities.push_back(statisticGoldStandard); // vtkSmartPointer colReader = vtkSmartPointer::New(); mitk::CollectionReader* colReader = new mitk::CollectionReader(); colReader->AddDataElementIds(trainPatients); colReader->SetDataItemNames(usedModalities); if (testSingleDataset > 0) { testPatients.clear(); testPatients.push_back(singleDatasetName); } colReader->ClearDataElementIds(); colReader->AddDataElementIds(testPatients); mitk::DataCollection::Pointer testCollection = colReader->LoadCollection(testCollectionPath); std::time_t now; time(&now); double seconds = std::difftime(now, lastTimePoint); timingFile << seconds << ";"; time(&lastTimePoint); mitk::VigraRandomForestClassifier::Pointer forest = mitk::VigraRandomForestClassifier::New(); MITK_INFO << "Convert Test data"; auto testDataX = mitk::DCUtilities::DC3dDToMatrixXd(testCollection, modalities, testMask); for (std::size_t i = 0; i < forestVector.size(); ++i) { forest = mitk::IOUtil::Load(forestVector[i]); time(&now); seconds = std::difftime(now, lastTimePoint); MITK_INFO << "Duration for Training: " << seconds; timingFile << seconds << ";"; time(&lastTimePoint); MITK_INFO << "Predict Test Data"; auto testDataNewY = forest->Predict(testDataX); auto testDataNewProb = forest->GetPointWiseProbabilities(); auto maxClassValue = testDataNewProb.cols(); std::vector names; for (int j = 0; j < maxClassValue; ++j) { std::string name = resultProb + std::to_string(j); names.push_back(name); } mitk::DCUtilities::MatrixToDC3d(testDataNewY, testCollection, resultMask, testMask); mitk::DCUtilities::MatrixToDC3d(testDataNewProb, testCollection, names, testMask); MITK_INFO << "Converted predicted data"; time(&now); seconds = std::difftime(now, lastTimePoint); timingFile << seconds << ";"; time(&lastTimePoint); ////////////////////////////////////////////////////////////////////////////// // Save results to folder ////////////////////////////////////////////////////////////////////////////// MITK_INFO << "Write Result to HDD"; mitk::CollectionWriter::ExportCollectionToFolder(testCollection, outputFolder + "/result_collection.xml", outputFilter); MITK_INFO << "Calculate Statistic...."; ////////////////////////////////////////////////////////////////////////////// // Calculate and Print Statistic ////////////////////////////////////////////////////////////////////////////// std::ofstream statisticFile; statisticFile.open(statisticFilePath.c_str(), std::ios::app); std::ofstream sstatisticFile; sstatisticFile.open(statisticShortFilePath.c_str(), std::ios::app); mitk::CollectionStatistic stat; stat.SetCollection(testCollection); stat.SetClassCount(5); stat.SetGoldName(statisticGoldStandard); stat.SetTestName(resultMask); stat.SetMaskName(testMask); mitk::BinaryValueminusOneToIndexMapper mapper; stat.SetGroundTruthValueToIndexMapper(&mapper); stat.SetTestValueToIndexMapper(&mapper); stat.Update(); //stat.Print(statisticFile,sstatisticFile,statisticWithHeader, statisticShortFileLabel); stat.Print(statisticFile, sstatisticFile, true, statisticShortFileLabel + "_"+std::to_string(i)); statisticFile.close(); time(&now); seconds = std::difftime(now, lastTimePoint); timingFile << seconds << std::endl; time(&lastTimePoint); timingFile.close(); } } catch (std::string s) { MITK_INFO << s; return 0; } catch (char* s) { MITK_INFO << s; } return 0; } #endif diff --git a/Modules/Classification/CLMiniApps/CLVoxelClassification.cpp b/Modules/Classification/CLMiniApps/CLVoxelClassification.cpp index 94eed48ec4..ab6d52024b 100644 --- a/Modules/Classification/CLMiniApps/CLVoxelClassification.cpp +++ b/Modules/Classification/CLMiniApps/CLVoxelClassification.cpp @@ -1,480 +1,480 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 mitkForest_cpp #define mitkForest_cpp #include "time.h" #include #include #include #include #include #include #include #include #include #include #include // ----------------------- Forest Handling ---------------------- //#include #include //#include //#include //#include //#include // ----------------------- Point weighting ---------------------- //#include //#include //#include #include //#include //#include //#include //#include int main(int argc, char* argv[]) { MITK_INFO << "Starting MITK_Forest Mini-App"; ////////////////////////////////////////////////////////////////////////////// // Read Console Input Parameter ////////////////////////////////////////////////////////////////////////////// ConfigFileReader allConfig(argv[1]); bool readFile = true; std::stringstream ss; for (int i = 0; i < argc; ++i ) { MITK_INFO << "-----"<< argv[i]<<"------"; if (readFile) { if (argv[i][0] == '+') { readFile = false; continue; } else { try { allConfig.ReadFile(argv[i]); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_INFO << e.what(); } } } else { std::string input = argv[i]; std::replace(input.begin(), input.end(),'_',' '); ss << input << std::endl; } } allConfig.ReadStream(ss); try { ////////////////////////////////////////////////////////////////////////////// // General ////////////////////////////////////////////////////////////////////////////// int currentRun = allConfig.IntValue("General","Run",0); int doTraining = allConfig.IntValue("General","Do Training",1); std::string forestPath = allConfig.Value("General","Forest Path"); std::string trainingCollectionPath = allConfig.Value("General","Patient Collection"); std::string testCollectionPath = allConfig.Value("General", "Patient Test Collection", trainingCollectionPath); ////////////////////////////////////////////////////////////////////////////// // Read Default Classification ////////////////////////////////////////////////////////////////////////////// std::vector trainPatients = allConfig.Vector("Training Group",currentRun); std::vector testPatients = allConfig.Vector("Test Group",currentRun); std::vector modalities = allConfig.Vector("Modalities", 0); std::vector outputFilter = allConfig.Vector("Output Filter", 0); std::string trainMask = allConfig.Value("Data","Training Mask"); std::string completeTrainMask = allConfig.Value("Data","Complete Training Mask"); std::string testMask = allConfig.Value("Data","Test Mask"); std::string resultMask = allConfig.Value("Data", "Result Mask"); std::string resultProb = allConfig.Value("Data", "Result Propability"); std::string outputFolder = allConfig.Value("General","Output Folder"); std::string writeDataFilePath = allConfig.Value("Forest","File to write data to"); ////////////////////////////////////////////////////////////////////////////// // Read Data Forest Parameter ////////////////////////////////////////////////////////////////////////////// int testSingleDataset = allConfig.IntValue("Data", "Test Single Dataset",0); std::string singleDatasetName = allConfig.Value("Data", "Single Dataset Name", "none"); int trainSingleDataset = allConfig.IntValue("Data", "Train Single Dataset", 0); std::string singleTrainDatasetName = allConfig.Value("Data", "Train Single Dataset Name", "none"); ////////////////////////////////////////////////////////////////////////////// // Read Forest Parameter ////////////////////////////////////////////////////////////////////////////// int minimumSplitNodeSize = allConfig.IntValue("Forest", "Minimum split node size",1); int numberOfTrees = allConfig.IntValue("Forest", "Number of Trees",255); double samplesPerTree = atof(allConfig.Value("Forest", "Samples per Tree").c_str()); if (samplesPerTree <= 0.0000001) { samplesPerTree = 1.0; } MITK_INFO << "Samples per Tree: " << samplesPerTree; int sampleWithReplacement = allConfig.IntValue("Forest", "Sample with replacement",1); double trainPrecision = atof(allConfig.Value("Forest", "Precision").c_str()); if (trainPrecision <= 0.0000000001) { trainPrecision = 0.0; } double weightLambda = atof(allConfig.Value("Forest", "Weight Lambda").c_str()); if (weightLambda <= 0.0000000001) { weightLambda = 0.0; } int maximumTreeDepth = allConfig.IntValue("Forest", "Maximum Tree Depth",10000); // TODO int randomSplit = allConfig.IntValue("Forest","Use RandomSplit",0); ////////////////////////////////////////////////////////////////////////////// // Read Statistic Parameter ////////////////////////////////////////////////////////////////////////////// std::string statisticFilePath = allConfig.Value("Evaluation", "Statistic output file"); std::string statisticShortFilePath = allConfig.Value("Evaluation", "Statistic short output file"); std::string statisticShortFileLabel = allConfig.Value("Evaluation", "Index for short file"); std::string statisticGoldStandard = allConfig.Value("Evaluation", "Gold Standard Name","GTV"); // TODO bool statisticWithHeader = allConfig.IntValue("Evaluation", "Write header in short file",0); std::vector labelGroupA = allConfig.Vector("LabelsA",0); std::vector labelGroupB = allConfig.Vector("LabelsB",0); ////////////////////////////////////////////////////////////////////////////// // Read Special Parameter ////////////////////////////////////////////////////////////////////////////// bool useWeightedPoints = allConfig.IntValue("Forest", "Use point-based weighting",0); // TODO bool writePointsToFile = allConfig.IntValue("Forest", "Write points to file",0); // TODO int importanceWeightAlgorithm = allConfig.IntValue("Forest","Importance weight Algorithm",0); std::string importanceWeightName = allConfig.Value("Forest","Importance weight name",""); std::ofstream timingFile; timingFile.open((statisticFilePath + ".timing").c_str(), std::ios::app); timingFile << statisticShortFileLabel << ";"; std::time_t lastTimePoint; time(&lastTimePoint); ////////////////////////////////////////////////////////////////////////////// // Read Images ////////////////////////////////////////////////////////////////////////////// std::vector usedModalities; for (std::size_t i = 0; i < modalities.size(); ++i) { usedModalities.push_back(modalities[i]); } usedModalities.push_back(trainMask); usedModalities.push_back(completeTrainMask); usedModalities.push_back(testMask); usedModalities.push_back(statisticGoldStandard); usedModalities.push_back(importanceWeightName); if (trainSingleDataset > 0) { trainPatients.clear(); trainPatients.push_back(singleTrainDatasetName); } mitk::CollectionReader* colReader = new mitk::CollectionReader(); colReader->AddDataElementIds(trainPatients); colReader->SetDataItemNames(usedModalities); //colReader->SetNames(usedModalities); mitk::DataCollection::Pointer trainCollection; if (doTraining) { trainCollection = colReader->LoadCollection(trainingCollectionPath); } if (testSingleDataset > 0) { testPatients.clear(); testPatients.push_back(singleDatasetName); } colReader->ClearDataElementIds(); colReader->AddDataElementIds(testPatients); mitk::DataCollection::Pointer testCollection = colReader->LoadCollection(testCollectionPath); std::time_t now; time(&now); double seconds = std::difftime(now, lastTimePoint); timingFile << seconds << ";"; time(&lastTimePoint); /* if (writePointsToFile) { MITK_INFO << "Use external weights..."; mitk::ExternalWeighting weightReader; weightReader.SetModalities(modalities); weightReader.SetTestCollection(testCollection); weightReader.SetTrainCollection(trainCollection); weightReader.SetTestMask(testMask); weightReader.SetTrainMask(trainMask); weightReader.SetWeightsName("weights"); weightReader.SetCorrectionFactor(1.0); weightReader.SetWeightFileName(writeDataFilePath); weightReader.WriteData(); return 0; }*/ ////////////////////////////////////////////////////////////////////////////// // If required do Training.... ////////////////////////////////////////////////////////////////////////////// //mitk::DecisionForest forest; mitk::VigraRandomForestClassifier::Pointer forest = mitk::VigraRandomForestClassifier::New(); forest->SetSamplesPerTree(samplesPerTree); forest->SetMinimumSplitNodeSize(minimumSplitNodeSize); forest->SetTreeCount(numberOfTrees); forest->UseSampleWithReplacement(sampleWithReplacement); forest->SetPrecision(trainPrecision); forest->SetMaximumTreeDepth(maximumTreeDepth); forest->SetWeightLambda(weightLambda); // TODO forest.UseRandomSplit(randomSplit); if (doTraining) { // 0 = LR-Estimation // 1 = KNN-Estimation // 2 = Kliep // 3 = Extern Image // 4 = Zadrozny // 5 = Spectral // 6 = uLSIF auto trainDataX = mitk::DCUtilities::DC3dDToMatrixXd(trainCollection, modalities, trainMask); auto trainDataY = mitk::DCUtilities::DC3dDToMatrixXi(trainCollection, trainMask, trainMask); if (useWeightedPoints) //if (false) { MITK_INFO << "Activated Point-based weighting..."; //forest.UseWeightedPoints(true); forest->UsePointWiseWeight(true); //forest.SetWeightName("calculated_weight"); /*if (importanceWeightAlgorithm == 1) { mitk::KNNDensityEstimation est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } else if (importanceWeightAlgorithm == 2) { mitk::KliepDensityEstimation est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } else if (importanceWeightAlgorithm == 3) { forest.SetWeightName(importanceWeightName); } else if (importanceWeightAlgorithm == 4) { mitk::ZadroznyWeighting est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } else if (importanceWeightAlgorithm == 5) { mitk::SpectralDensityEstimation est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } else if (importanceWeightAlgorithm == 6) { mitk::ULSIFDensityEstimation est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } else*/ { mitk::LRDensityEstimation est; est.SetCollection(trainCollection); est.SetTrainMask(trainMask); est.SetTestMask(testMask); est.SetModalities(modalities); est.SetWeightName("calculated_weight"); est.Update(); } auto trainDataW = mitk::DCUtilities::DC3dDToMatrixXd(trainCollection, "calculated_weight", trainMask); forest->SetPointWiseWeight(trainDataW); forest->UsePointWiseWeight(true); } MITK_INFO << "Start training the forest"; forest->Train(trainDataX, trainDataY); MITK_INFO << "Save Forest"; mitk::IOUtil::Save(forest, forestPath); } else { forest = mitk::IOUtil::Load(forestPath);// TODO forest.Load(forestPath); } time(&now); seconds = std::difftime(now, lastTimePoint); MITK_INFO << "Duration for Training: " << seconds; timingFile << seconds << ";"; time(&lastTimePoint); ////////////////////////////////////////////////////////////////////////////// // If required do Save Forest.... ////////////////////////////////////////////////////////////////////////////// //writer.// (forest); /* auto w = forest->GetTreeWeights(); w(0,0) = 10; forest->SetTreeWeights(w);*/ ////////////////////////////////////////////////////////////////////////////// // If required do test ////////////////////////////////////////////////////////////////////////////// MITK_INFO << "Convert Test data"; auto testDataX = mitk::DCUtilities::DC3dDToMatrixXd(testCollection,modalities, testMask); MITK_INFO << "Predict Test Data"; auto testDataNewY = forest->Predict(testDataX); auto testDataNewProb = forest->GetPointWiseProbabilities(); //MITK_INFO << testDataNewY; auto maxClassValue = testDataNewProb.cols(); std::vector names; for (int i = 0; i < maxClassValue; ++i) { std::string name = resultProb + std::to_string(i); MITK_INFO << name; names.push_back(name); } //names.push_back("prob-1"); //names.push_back("prob-2"); mitk::DCUtilities::MatrixToDC3d(testDataNewY, testCollection, resultMask, testMask); mitk::DCUtilities::MatrixToDC3d(testDataNewProb, testCollection, names, testMask); MITK_INFO << "Converted predicted data"; //forest.SetMaskName(testMask); //forest.SetCollection(testCollection); //forest.Test(); //forest.PrintTree(0); time(&now); seconds = std::difftime(now, lastTimePoint); timingFile << seconds << ";"; time(&lastTimePoint); ////////////////////////////////////////////////////////////////////////////// // Cost-based analysis ////////////////////////////////////////////////////////////////////////////// // TODO Reactivate //MITK_INFO << "Calculate Cost-based Statistic "; //mitk::CostingStatistic costStat; //costStat.SetCollection(testCollection); //costStat.SetCombinedA("combinedHealty"); //costStat.SetCombinedB("combinedTumor"); //costStat.SetCombinedLabel("combinedLabel"); //costStat.SetMaskName(testMask); ////std::vector labelHealthy; ////labelHealthy.push_back("result_prop_Class-0"); ////labelHealthy.push_back("result_prop_Class-4"); ////std::vector labelTumor; ////labelTumor.push_back("result_prop_Class-1"); ////labelTumor.push_back("result_prop_Class-2"); ////labelTumor.push_back("result_prop_Class-3"); //costStat.SetProbabilitiesA(labelGroupA); //costStat.SetProbabilitiesB(labelGroupB); //std::ofstream costStatisticFile; //costStatisticFile.open((statisticFilePath + ".cost").c_str(), std::ios::app); //std::ofstream lcostStatisticFile; //lcostStatisticFile.open((statisticFilePath + ".longcost").c_str(), std::ios::app); //costStat.WriteStatistic(lcostStatisticFile,costStatisticFile,2.5,statisticShortFileLabel); //costStatisticFile.close(); //costStat.CalculateClass(50); ////////////////////////////////////////////////////////////////////////////// // Save results to folder ////////////////////////////////////////////////////////////////////////////// ////std::vector outputFilter; //outputFilter.push_back(resultMask); //std::vector propNames = forest.GetListOfProbabilityNames(); //outputFilter.insert(outputFilter.begin(), propNames.begin(), propNames.end()); MITK_INFO << "Write Result to HDD"; mitk::CollectionWriter::ExportCollectionToFolder(testCollection, outputFolder + "/result_collection.xml", outputFilter); MITK_INFO << "Calculate Statistic...." ; ////////////////////////////////////////////////////////////////////////////// // Calculate and Print Statistic ////////////////////////////////////////////////////////////////////////////// std::ofstream statisticFile; statisticFile.open(statisticFilePath.c_str(), std::ios::app); std::ofstream sstatisticFile; sstatisticFile.open(statisticShortFilePath.c_str(), std::ios::app); mitk::CollectionStatistic stat; stat.SetCollection(testCollection); stat.SetClassCount(5); stat.SetGoldName(statisticGoldStandard); stat.SetTestName(resultMask); stat.SetMaskName(testMask); mitk::BinaryValueminusOneToIndexMapper mapper; stat.SetGroundTruthValueToIndexMapper(&mapper); stat.SetTestValueToIndexMapper(&mapper); stat.Update(); //stat.Print(statisticFile,sstatisticFile,statisticWithHeader, statisticShortFileLabel); stat.Print(statisticFile,sstatisticFile,true, statisticShortFileLabel); statisticFile.close(); time(&now); seconds = std::difftime(now, lastTimePoint); timingFile << seconds << std::endl; time(&lastTimePoint); timingFile.close(); } - catch (std::string s) + catch ( const std::string s ) { MITK_INFO << s; return 0; } catch (char* s) { MITK_INFO << s; } return 0; } #endif diff --git a/Modules/Classification/CLVigraRandomForest/src/IO/mitkVigraRandomForestClassifierSerializer.cpp b/Modules/Classification/CLVigraRandomForest/src/IO/mitkVigraRandomForestClassifierSerializer.cpp index 8a61de3cd2..c4014cc568 100644 --- a/Modules/Classification/CLVigraRandomForest/src/IO/mitkVigraRandomForestClassifierSerializer.cpp +++ b/Modules/Classification/CLVigraRandomForest/src/IO/mitkVigraRandomForestClassifierSerializer.cpp @@ -1,68 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVigraRandomForestClassifierSerializer.h" #include "mitkIOUtil.h" #include "mitkVigraRandomForestClassifier.h" #include MITK_REGISTER_SERIALIZER(VigraRandomForestClassifierSerializer) mitk::VigraRandomForestClassifierSerializer::VigraRandomForestClassifierSerializer() { } mitk::VigraRandomForestClassifierSerializer::~VigraRandomForestClassifierSerializer() { } std::string mitk::VigraRandomForestClassifierSerializer::Serialize() { const mitk::VigraRandomForestClassifier* data = dynamic_cast( m_Data.GetPointer() ); if (!data) { MITK_ERROR << " Object at " << (const void*) this->m_Data << " is not an mitk::ContourModelSet. Cannot serialize as contour model set."; return ""; } std::string filename( this->GetUniqueFilenameInWorkingDirectory() ); filename += "_"; filename += m_FilenameHint; filename += ".hdf5"; std::string fullname(m_WorkingDirectory); fullname += "/"; fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str()); try { mitk::IOUtil::Save(const_cast( data ),fullname); } - catch (std::exception& e) + catch ( const std::exception& e ) { MITK_ERROR << " Error serializing object at " << (const void*) this->m_Data << " to " << fullname << ": " << e.what(); return ""; } return filename; } diff --git a/Modules/Classification/CLVigraRandomForest/test/mitkVigraRandomForestTest.cpp b/Modules/Classification/CLVigraRandomForest/test/mitkVigraRandomForestTest.cpp index cd8b36e7c8..53d3414929 100644 --- a/Modules/Classification/CLVigraRandomForest/test/mitkVigraRandomForestTest.cpp +++ b/Modules/Classification/CLVigraRandomForest/test/mitkVigraRandomForestTest.cpp @@ -1,327 +1,327 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkIOUtil.h" #include "itkArray2D.h" #include #include #include #include #include #include #include class mitkVigraRandomForestTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkVigraRandomForestTestSuite ); // MITK_TEST(Load_RandomForestBaseDataUsingIOUtil_shouldReturnTrue); // MITK_TEST(Save_RandomForestBaseDataUsingIOUtil_shouldReturnTrue); // MITK_TEST(LoadWithMitkOptions_RandomForestBaseDataUsingIOUtil_shouldReturnTrue); // MITK_TEST(SaveWithMitkOptions_RandomForestBaseDataUsingIOUtil_shouldReturnTrue); MITK_TEST(TrainThreadedDecisionForest_MatlabDataSet_shouldReturnTrue); MITK_TEST(PredictWeightedDecisionForest_SetWeightsToZero_shouldReturnTrue); MITK_TEST(TrainThreadedDecisionForest_BreastCancerDataSet_shouldReturnTrue); CPPUNIT_TEST_SUITE_END(); private: typedef Eigen::Matrix MatrixDoubleType; typedef Eigen::Matrix MatrixIntType; std::pair FeatureData_Cancer; std::pair LabelData_Cancer; std::pair FeatureData_Matlab; std::pair LabelData_Matlab; mitk::VigraRandomForestClassifier::Pointer classifier; public: // ------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------ void setUp() override { FeatureData_Cancer = convertCSVToMatrix(GetTestDataFilePath("Classification/FeaturematrixBreastcancer.csv"),';',0.5,true); LabelData_Cancer = convertCSVToMatrix(GetTestDataFilePath("Classification/LabelmatrixBreastcancer.csv"),';',0.5,false); FeatureData_Matlab = convertCSVToMatrix(GetTestDataFilePath("Classification/FeaturematrixMatlab.csv"),';',0.5,true); LabelData_Matlab = convertCSVToMatrix(GetTestDataFilePath("Classification/LabelmatrixMatlab.csv"),';',0.5,false); classifier = mitk::VigraRandomForestClassifier::New(); } void tearDown() override { classifier = nullptr; } // ------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------ /* Train the classifier with an exampledataset of mattlab. Note: The included data are gauan normaldistributed. */ void TrainThreadedDecisionForest_MatlabDataSet_shouldReturnTrue() { auto & Features_Training = FeatureData_Matlab.first; auto & Labels_Training = LabelData_Matlab.first; auto & Features_Testing = FeatureData_Matlab.second; auto & Labels_Testing = LabelData_Matlab.second; /* Train the classifier, by giving trainingdataset for the labels and features. The result in an colunmvector of the labels.*/ classifier->Train(Features_Training,Labels_Training); Eigen::MatrixXi classes = classifier->Predict(Features_Testing); /* Testing the matching between the calculated colunmvector and the result of the RandomForest */ unsigned int testmatrix_rows = classes.rows(); unsigned int correctly_classified_rows = 0; for(unsigned int i= 0; i < testmatrix_rows; i++){ if(classes(i,0) == Labels_Testing(i,0)){ correctly_classified_rows++; } } MITK_TEST_CONDITION(correctly_classified_rows == testmatrix_rows, "Matlab Data correctly classified"); } // ------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------ /* Train the classifier with the dataset of breastcancer patients from the LibSVM Libary */ void TrainThreadedDecisionForest_BreastCancerDataSet_shouldReturnTrue() { auto & Features_Training = FeatureData_Cancer.first; auto & Features_Testing = FeatureData_Cancer.second; auto & Labels_Training = LabelData_Cancer.first; auto & Labels_Testing = LabelData_Cancer.second; /* Train the classifier, by giving trainingdataset for the labels and features. The result in an colunmvector of the labels.*/ classifier->Train(Features_Training,Labels_Training); Eigen::MatrixXi classes = classifier->Predict(Features_Testing); /* Testing the matching between the calculated colunmvector and the result of the RandomForest */ unsigned int maxrows = classes.rows(); int count = 0; for(unsigned int i= 0; i < maxrows; i++){ if(classes(i,0) == Labels_Testing(i,0)){ count++; } } MITK_TEST_CONDITION(isIntervall(Labels_Testing,classes,98,99),"Testvalue of cancer data set is in range."); } // ------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------ void PredictWeightedDecisionForest_SetWeightsToZero_shouldReturnTrue() { auto & Features_Training = FeatureData_Matlab.first; auto & Features_Testing = FeatureData_Matlab.second; auto & Labels_Training = LabelData_Matlab.first; // auto & Labels_Testing = LabelData_Matlab.second; classifier->Train(Features_Training,Labels_Training); // get weights type resize it and set all weights to zero auto weights = classifier->GetTreeWeights(); weights.resize(classifier->GetRandomForest().tree_count(),1); weights.fill(0); classifier->SetTreeWeights(weights); // if all wieghts zero the missclassification rate mus be high Eigen::MatrixXi classes = classifier->PredictWeighted(Features_Testing); /* Testing the matching between the calculated colunmvector and the result of the RandomForest */ unsigned int maxrows = classes.rows(); unsigned int count = 0; // check if all predictions are of class 1 for(unsigned int i= 0; i < maxrows; i++) if(classes(i,0) == 1) count++; MITK_TEST_CONDITION( (count == maxrows) ,"Weighted prediction - weights applied (all weights = 0)."); } // ------------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------------ /*Reading an file, which includes the trainingdataset and the testdataset, and convert the content of the file into an 2dim matrixpair. There are an delimiter, which separates the matrix into an trainingmatrix and testmatrix */ template std::pair,Eigen::Matrix >convertCSVToMatrix(const std::string &path, char delimiter,double range, bool isXMatrix) { typename itk::CSVArray2DFileReader::Pointer fr = itk::CSVArray2DFileReader::New(); fr->SetFileName(path); fr->SetFieldDelimiterCharacter(delimiter); fr->HasColumnHeadersOff(); fr->HasRowHeadersOff(); fr->Parse(); try{ fr->Update(); - }catch(itk::ExceptionObject& ex){ + }catch ( const itk::ExceptionObject& ex ){ cout << "Exception caught!" << std::endl; - cout << ex << std::endl; + cout << ex.GetDescription() << std::endl; } typename itk::CSVArray2DDataObject::Pointer p = fr->GetOutput(); unsigned int maxrowrange = p->GetMatrix().rows(); unsigned int c = p->GetMatrix().cols(); unsigned int percentRange = (unsigned int)(maxrowrange*range); if(isXMatrix == true){ Eigen::Matrix trainMatrixX(percentRange,c); Eigen::Matrix testMatrixXPredict(maxrowrange-percentRange,c); for(unsigned int row = 0; row < percentRange; row++){ for(unsigned int col = 0; col < c; col++){ trainMatrixX(row,col) = p->GetData(row,col); } } for(unsigned int row = percentRange; row < maxrowrange; row++){ for(unsigned int col = 0; col < c; col++){ testMatrixXPredict(row-percentRange,col) = p->GetData(row,col); } } return std::make_pair(trainMatrixX,testMatrixXPredict); } else{ Eigen::Matrix trainLabelMatrixY(percentRange,c); Eigen::Matrix testMatrixYPredict(maxrowrange-percentRange,c); for(unsigned int row = 0; row < percentRange; row++){ for(unsigned int col = 0; col < c; col++){ trainLabelMatrixY(row,col) = p->GetData(row,col); } } for(unsigned int row = percentRange; row < maxrowrange; row++){ for(unsigned int col = 0; col < c; col++){ testMatrixYPredict(row-percentRange,col) = p->GetData(row,col); } } return std::make_pair(trainLabelMatrixY,testMatrixYPredict); } } /* Reading an csv-data and transfer the included datas into an matrix. */ template Eigen::Matrix readCsvData(const std::string &path, char delimiter) { typename itk::CSVArray2DFileReader::Pointer fr = itk::CSVArray2DFileReader::New(); fr->SetFileName(path); fr->SetFieldDelimiterCharacter(delimiter); fr->HasColumnHeadersOff(); fr->HasRowHeadersOff(); fr->Parse(); try{ fr->Update(); - }catch(itk::ExceptionObject& ex){ + }catch ( const itk::ExceptionObject& ex ){ cout << "Exception caught!" << std::endl; - cout << ex << std::endl; + cout << ex.GetDescription() << std::endl; } typename itk::CSVArray2DDataObject::Pointer p = fr->GetOutput(); unsigned int maxrowrange = p->GetMatrix().rows(); unsigned int maxcols = p->GetMatrix().cols(); Eigen::Matrix matrix(maxrowrange,maxcols); for(unsigned int rows = 0; rows < maxrowrange; rows++){ for(unsigned int cols = 0; cols < maxcols; cols++ ){ matrix(rows,cols) = p->GetData(rows,cols); } } return matrix; } /* Write the content of the array into an own csv-data in the following sequence: root.csv: 1 2 3 0 0 4 writen.csv: 1 1:2 2:3 3:0 4:0 5:4 */ template void writeMatrixToCsv(Eigen::Matrix paramMatrix,const std::string &path) { std::ofstream outputstream (path,std::ofstream::out); // 682 if(outputstream.is_open()){ for(int i = 0; i < paramMatrix.rows(); i++){ outputstream << paramMatrix(i,0); for(int j = 1; j < 11; j++){ outputstream << " " << j << ":" << paramMatrix(i,j); } outputstream << endl; } outputstream.close(); } else{ cout << "Unable to write into CSV" << endl; } } // Method for intervalltesting template bool isIntervall(Eigen::Matrix expected, Eigen::Matrix actual, double lowrange, double toprange) { bool isInIntervall = false; int count = 0; unsigned int rowRange = expected.rows(); unsigned int colRange = expected.cols(); for(unsigned int i = 0; i < rowRange; i++){ for(unsigned int j = 0; j < colRange; j++){ if(expected(i,j) == actual(i,j)){ count++; } } double valueOfMatch = 100*count/(double)(rowRange); if((lowrange <= valueOfMatch) && (toprange >= valueOfMatch)){ isInIntervall = true; } } return isInIntervall; } }; MITK_TEST_SUITE_REGISTRATION(mitkVigraRandomForest) diff --git a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp index 626cc40e3c..4536f08c74 100755 --- a/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp +++ b/Modules/Classification/DataCollection/ReaderWriter/mitkCollectionWriter.cpp @@ -1,420 +1,420 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 _MSC_VER # pragma warning (disable : 4996) #endif #include "mitkCollectionWriter.h" #include #include "mitkImageCast.h" #include "itkNrrdImageIO.h" #include "itkImageFileWriter.h" #include "mitkCoreObjectFactory.h" #include #include #include //XML StateMachine Tags // Objects const std::string COLLECTION = "col"; const std::string SUBCOLLECTION = "subcol"; const std::string DATA = "data"; const std::string ITEM = "item"; // Properties const std::string NAME = "name"; const std::string ID = "id"; const std::string FILEPATH = "filepath"; const std::string LINK = "link"; static std::string GetName(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) return fileName.substr(0,fileName.length() -suffix.length()-11); // 10 = date length else return fileName.substr(0,fileName.length() -suffix.length()-9); // 8 = date length } static std::string GetDate(std::string fileName,std::string suffix, bool longName = false) { fileName = QFileInfo(QString::fromStdString(fileName)).fileName().toStdString(); if (longName) fileName = fileName.substr(fileName.length() - suffix.length()-10,10); // 8 = date length else fileName = fileName.substr(fileName.length() - suffix.length()-8,8); // 8 = date length if (!longName) { fileName.insert(6,"-"); fileName.insert(4,"-"); } return fileName; } bool mitk::CollectionWriter::ExportCollectionToFolder(DataCollection *dataCollection, std::string xmlFile, std::vector filter) { // Quick and Dirty: Assumes three level DataCollection QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); baseFolder.mkpath(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == nullptr) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == nullptr) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } QString fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { fileName += ".nrrd"; Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); IOUtil::Save(image, fileName.toStdString()); } - catch( const std::exception& e) + catch ( const std::exception& e ) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename = baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::ExportCollectionToFolder(mitk::DataCollection *dataCollection, std::string xmlFile) { std::vector mods; return ExportCollectionToFolder(dataCollection,xmlFile, mods); } bool mitk::CollectionWriter::SaveCollection(mitk::DataCollection *dataCollection, std::vector filter, std::string xmlFile) { QDir origFilename = QFileInfo(dataCollection->GetXMLFile().c_str()).absoluteDir(); QString originalFolder = origFilename.path() + QDir::separator(); if (xmlFile == "") xmlFile = dataCollection->GetXMLFile(); QDir fileName = QFileInfo(xmlFile.c_str()).absoluteDir(); std::string outputFolder = fileName.path().toStdString() + QDir::separator().toLatin1(); QDir baseFolder(outputFolder.c_str()); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << dataCollection->GetName() << "\" >\n"; unsigned int subColId = 0; unsigned int dataId = 0; QDir dir(QString::fromStdString(outputFolder)); for (size_t i = 0 ; i < dataCollection->Size(); ++i) { // Write Subcollection tag xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << dataCollection->IndexToName(i) << "\" " << FILEPATH << "=\"" << dataCollection->GetDataFilePath(i) << "\" id=\"Col" << subColId << "\" >\n"; // Create Sub-Folder dir.mkpath(QString::fromStdString(dataCollection->IndexToName(i))); // Herein create data folders DataCollection* subCollections = dynamic_cast (dataCollection->GetData(i).GetPointer()); if (subCollections == nullptr) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t d = 0; d < subCollections->Size(); d++ ) { // Create Sub Paths QString subPath = QString::fromStdString(dataCollection->IndexToName(i))+"/"+QString::fromStdString(subCollections->IndexToName(d)); dir.mkpath(subPath); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << subCollections->IndexToName(d) << "\" " << FILEPATH << "=\"" << subCollections->GetDataFilePath(d) << "\" id=\"Data" << dataId << "\" >\n"; DataCollection* itemCollections = dynamic_cast (subCollections->GetData(d).GetPointer()); if (itemCollections == nullptr) { MITK_ERROR<< "mitk::CollectionWriter::SaveCollectionToFolder: Container is illformed. Aborting"; return false; } for (size_t s = 0; s < itemCollections->Size(); s++) { if (filter.size() > 0) { bool isSelected = false; for (size_t f = 0; f < filter.size(); f++) { if (filter.at(f) == itemCollections->IndexToName(s) ) { isSelected = true; break; } } if (isSelected == false) continue; } QString fileName; bool fullName = false; if (itemCollections->GetDataFilePath(s) != "") { fileName = originalFolder + QString::fromStdString(itemCollections->GetDataFilePath(s)); fullName = true; MITK_INFO << "original path: " << itemCollections->GetDataFilePath(s) ; } else fileName = dir.path() + dir.separator() + subPath + dir.separator() + QString::fromStdString(dataCollection->IndexToName(i)) + "_" + QString::fromStdString(subCollections->IndexToName(d)) + "_" + QString::fromStdString(itemCollections->IndexToName(s)); try { if (!fullName) fileName += ".nrrd"; Image::Pointer image = itemCollections->GetMitkImage(s).GetPointer(); IOUtil::Save(image,fileName.toStdString()); } - catch( const std::exception& e) + catch ( const std::exception& e ) { MITK_ERROR << "Caught exception: " << e.what(); } std::string relativeFilename =baseFolder.relativeFilePath(fileName).toStdString(); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" <IndexToName(s) << "\" " << FILEPATH << "=\"" << "\" " << LINK << "=\"" << relativeFilename << "\" />\n"; } xmlFileStream << " \n"; dataId++; } xmlFileStream << " \n"; subColId++; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::FolderToXml(std::string folder, std::string collectionType, std::string xmlFile, std::vector filter, std::vector seriesNames) { // 1) Parse for folders QDir parseDir; parseDir.setFilter( QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot); parseDir.setPath(QString::fromStdString(folder)); QFileInfoList qFileList = parseDir.entryInfoList(); std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // now populate lists with files names, non-existing files will be marked with an empty string for (int i = 0; i < qFileList.size(); ++i) { // 2) For Each sub folder construct collectionType sub-folder std::string baseFolder = qFileList.at(i).absoluteFilePath().toStdString() + QDir::separator().toLatin1() + collectionType; MITK_INFO << "Processing : " << baseFolder; if (!QFileInfo(QString::fromStdString(baseFolder)).isDir()) { MITK_WARN << "Not a valid folder, skipping."; continue; } // 3) Parse each sub folder and extend XML file // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(baseFolder, filter,true)); if (fileList.size() <= 0 || fileList.at(0).size() <= 0) continue; // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0)); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << i << "\" >\n"; for (unsigned int k=0; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0)); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } xmlFileStream << " \n" ; } xmlFileStream << " \n"; } xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } bool mitk::CollectionWriter::SingleFolderToXml(std::string folder, std::string xmlFile, std::vector filter, std::vector seriesNames, bool longDate, int skipUntil, float months) { std::ofstream xmlFileStream; xmlFileStream.open (xmlFile.c_str()); xmlFileStream << " \n"; xmlFileStream << "<" << COLLECTION << " " << NAME << "=\"" << "GEN" << "\" >\n"; unsigned int dataId = 0; // 1) // Parse folder and look up all data, // after sanitation only fully available groups are included (that is all suffixes are found) CollectionReader::FileListType fileList = CollectionReader::SanitizeFileList(CollectionReader::GenerateFileLists(folder, filter,true)); // Write Subcollection tag // try to extract date out of filename std::string name = GetName(fileList.at(0).at(0),filter.at(0),longDate); xmlFileStream << " <" << SUBCOLLECTION << " " << NAME << "=\"" << name << "\" " << FILEPATH << "=\"\" id=\"Col" << 0 << "\" >\n"; for (unsigned int k=skipUntil; k < fileList.at(0).size(); ++k) // all groups have the same amount of items, so looking at 0 is ok. { std::string strDate = GetDate(fileList.at(0).at(k),filter.at(0),true); xmlFileStream << " <" << DATA << " " << NAME << "=\"" << strDate << "\" " << " id=\"Data" << dataId << "\" >\n"; dataId++; for (unsigned int i=0; i< filter.size(); ++i) { std::string fileName = fileList.at(i).at(k); xmlFileStream << " <" << ITEM << " " << NAME << "=\"" << seriesNames.at(i) << "\" " << LINK << "=\"" << fileName << "\" />\n"; } // size_t ind = GetIndexForinXMonths(fileList,months,k,filter); // xmlFileStream << " <" << ITEM << " " << NAME << "=\"TARGET\" " << LINK << "=\"" << fileList.at(filter.size()-1).at(ind) << "\" />\n"; xmlFileStream << " \n" ; // check if target still exists for next step if (GetIndexForinXMonths(fileList,months,k+1,filter)== 0) break; } xmlFileStream << " \n"; xmlFileStream << "\n"; xmlFileStream.flush(); xmlFileStream.close(); return true; } size_t mitk::CollectionWriter::GetIndexForinXMonths(mitk::CollectionReader::FileListType fileList,float months, size_t curIndex,std::vector filter) { std::string strDate0 = GetDate(fileList.at(0).at(curIndex),filter.at(0),true); int year0 =std::atoi(strDate0.substr(0,4).c_str()); int month0 =std::atoi(strDate0.substr(5,2).c_str()); int day0 = std::atoi(strDate0.substr(8,2).c_str()); size_t bestIndex = 0; int bestFit = 1e5; for (size_t i=curIndex+1; i < fileList.at(0).size(); ++i) { std::string strDate = GetDate(fileList.at(0).at(i),filter.at(0),true); int year =std::atoi(strDate.substr(0,4).c_str()); int month =std::atoi(strDate.substr(5,2).c_str()); int day = std::atoi(strDate.substr(8,2).c_str()); int fit = std::fabs((months * 30 ) - (((year-year0)*360) +((month-month0)*30) + (day-day0))); // days difference from x months if (fit < bestFit) { bestFit = fit; bestIndex = i; } } return bestIndex; } diff --git a/Modules/ContourModel/IO/mitkContourModelSerializer.cpp b/Modules/ContourModel/IO/mitkContourModelSerializer.cpp index b7bd32a8e3..ee2d586324 100644 --- a/Modules/ContourModel/IO/mitkContourModelSerializer.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSerializer.cpp @@ -1,66 +1,66 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSerializer.h" #include "mitkContourModelWriter.h" #include MITK_REGISTER_SERIALIZER(ContourModelSerializer) mitk::ContourModelSerializer::ContourModelSerializer() { } mitk::ContourModelSerializer::~ContourModelSerializer() { } std::string mitk::ContourModelSerializer::Serialize() { const auto *contour = dynamic_cast(m_Data.GetPointer()); if (!contour) { MITK_ERROR << " Object at " << (const void *)this->m_Data << " is not an mitk::ContourModel. Cannot serialize as contour model."; return ""; } std::string filename(this->GetUniqueFilenameInWorkingDirectory()); filename += "_"; filename += m_FilenameHint; filename += ".cnt"; std::string fullname(m_WorkingDirectory); fullname += "/"; fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str()); try { ContourModelWriter writer; writer.SetOutputLocation(fullname); writer.SetInput(contour); writer.Write(); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_ERROR << " Error serializing object at " << (const void *)this->m_Data << " to " << fullname << ": " << e.what(); return ""; } return filename; } diff --git a/Modules/ContourModel/IO/mitkContourModelSetSerializer.cpp b/Modules/ContourModel/IO/mitkContourModelSetSerializer.cpp index 8f041e8824..57494d5ea6 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetSerializer.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSetSerializer.cpp @@ -1,66 +1,66 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkContourModelSetSerializer.h" #include "mitkContourModelSetWriter.h" #include MITK_REGISTER_SERIALIZER(ContourModelSetSerializer) mitk::ContourModelSetSerializer::ContourModelSetSerializer() { } mitk::ContourModelSetSerializer::~ContourModelSetSerializer() { } std::string mitk::ContourModelSetSerializer::Serialize() { const auto *contourSet = dynamic_cast(m_Data.GetPointer()); if (!contourSet) { MITK_ERROR << " Object at " << (const void *)this->m_Data << " is not an mitk::ContourModelSet. Cannot serialize as contour model set."; return ""; } std::string filename(this->GetUniqueFilenameInWorkingDirectory()); filename += "_"; filename += m_FilenameHint; filename += ".cnt_set"; std::string fullname(m_WorkingDirectory); fullname += "/"; fullname += itksys::SystemTools::ConvertToOutputPath(filename.c_str()); try { ContourModelSetWriter writer; writer.SetOutputLocation(fullname); writer.SetInput(contourSet); writer.Write(); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_ERROR << " Error serializing object at " << (const void *)this->m_Data << " to " << fullname << ": " << e.what(); return ""; } return filename; } diff --git a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp index ee741976fb..0b75af32f4 100644 --- a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.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. ===================================================================*/ // VTK #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include // include gl to read out properties #include #include #if defined _MSC_VER #if _MSC_VER >= 1700 #define RESIZE_WORKAROUND #endif #endif #ifdef RESIZE_WORKAROUND #include "vtkWin32OpenGLRenderWindow.h" #endif // VTK Testing to compare the rendered image pixel-wise against a reference screen shot #include "vtkTesting.h" mitk::RenderingTestHelper::RenderingTestHelper(int width, int height, mitk::BaseRenderer::RenderingMode::Type renderingMode) : m_AutomaticallyCloseRenderWindow(true) { this->Initialize(width, height, renderingMode); } mitk::RenderingTestHelper::RenderingTestHelper( int width, int height, int argc, char *argv[], mitk::BaseRenderer::RenderingMode::Type renderingMode) : m_AutomaticallyCloseRenderWindow(true) { this->Initialize(width, height, renderingMode); this->SetInputFileNames(argc, argv); } void mitk::RenderingTestHelper::Initialize(int width, int height, mitk::BaseRenderer::RenderingMode::Type renderingMode) { mitk::UIDGenerator uidGen = mitk::UIDGenerator("UnnamedRenderer_", 8); m_RenderWindow = mitk::RenderWindow::New(nullptr, uidGen.GetUID().c_str(), nullptr, renderingMode); m_DataStorage = mitk::StandaloneDataStorage::New(); m_RenderWindow->GetRenderer()->SetDataStorage(m_DataStorage); this->SetMapperIDToRender2D(); this->GetVtkRenderWindow()->SetSize(width, height); if (!IsAdvancedOpenGL()) { mitkThrowException(mitk::TestNotRunException) << "Insufficient OpenGL version"; } #ifdef RESIZE_WORKAROUND HWND hWnd = static_cast(this->GetVtkRenderWindow())->GetWindowId(); RECT r; r.left = 10; r.top = 10; r.right = r.left + width; r.bottom = r.top + height; LONG style = GetWindowLong(hWnd, GWL_STYLE); AdjustWindowRect(&r, style, FALSE); MITK_INFO << "WANTED:"; MITK_INFO << r.right - r.left; MITK_INFO << r.bottom - r.top; RECT rect; if (GetWindowRect(hWnd, &rect)) { int width = rect.right - rect.left; int height = rect.bottom - rect.top; MITK_INFO << "ACTUAL:"; MITK_INFO << width; MITK_INFO << height; } SetWindowPos(hWnd, HWND_TOP, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOZORDER); GetWindowRect(hWnd, &rect); int width2 = rect.right - rect.left; int height2 = rect.bottom - rect.top; MITK_INFO << "ACTUAL2:"; MITK_INFO << width2; MITK_INFO << height2; SetWindowPos(hWnd, HWND_TOP, 0, 0, 2 * (r.right - r.left) - width2, 2 * (r.bottom - r.top) - height2, SWP_NOZORDER); #endif m_RenderWindow->GetRenderer()->Resize(width, height); // Prints the glinfo after creation of the vtkrenderwindow, we always want to do this for debugging. this->PrintGLInfo(); } mitk::RenderingTestHelper::~RenderingTestHelper() { } bool mitk::RenderingTestHelper::IsAdvancedOpenGL() { const GLubyte *version = glGetString(GL_VERSION); if (!version) return false; return *version >= '2'; } void mitk::RenderingTestHelper::PrintGLInfo() { GLint maxTextureSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); ; //MITK_INFO << "OpenGL Render Context Information: \n" // << "- GL_VENDOR: " << glGetString(GL_VENDOR) << "\n" // << "- GL_RENDERER: " << glGetString(GL_RENDERER) << "\n" // << "- GL_VERSION: " << glGetString(GL_VERSION) << "\n" // << "- GL_MAX_TEXTURE_SIZE: " << maxTextureSize << "\n" // << "- GL_EXTENSIONS: " << glGetString(GL_EXTENSIONS); } void mitk::RenderingTestHelper::SetMapperID(mitk::BaseRenderer::StandardMapperSlot id) { m_RenderWindow->GetRenderer()->SetMapperID(id); } void mitk::RenderingTestHelper::SetMapperIDToRender3D() { this->SetMapperID(mitk::BaseRenderer::Standard3D); mitk::RenderingManager::GetInstance()->InitializeViews( this->GetDataStorage()->ComputeBoundingGeometry3D(this->GetDataStorage()->GetAll())); } void mitk::RenderingTestHelper::SetMapperIDToRender2D() { this->SetMapperID(mitk::BaseRenderer::Standard2D); } void mitk::RenderingTestHelper::Render() { // if the datastorage is initialized and at least 1 image is loaded render it if (m_DataStorage.IsNotNull() || m_DataStorage->GetAll()->Size() >= 1) { // Prepare the VTK camera before rendering. m_RenderWindow->GetRenderer()->PrepareRender(); this->GetVtkRenderWindow()->Render(); this->GetVtkRenderWindow()->WaitForCompletion(); if (m_AutomaticallyCloseRenderWindow == false) { // Use interaction to stop the test this->GetVtkRenderWindow()->GetInteractor()->Start(); } } else { MITK_ERROR << "No images loaded in data storage!"; } } mitk::DataStorage::Pointer mitk::RenderingTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::RenderingTestHelper::SetInputFileNames(int argc, char *argv[]) { // i is set 1, because 0 is the testname as string // parse parameters for (int i = 1; i < argc; ++i) { // add everything to a list but -T and -V std::string tmp = argv[i]; if ((tmp.compare("-T")) && (tmp.compare("-V"))) { this->AddToStorage(tmp); } else { break; } } } void mitk::RenderingTestHelper::SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow()) ->GetSliceNavigationController() ->SetDefaultViewDirection(viewDirection); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } void mitk::RenderingTestHelper::ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation) { mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController(); sliceNavigationController->ReorientSlices(origin, rotation); } vtkRenderer *mitk::RenderingTestHelper::GetVtkRenderer() { return m_RenderWindow->GetRenderer()->GetVtkRenderer(); } void mitk::RenderingTestHelper::SetImageProperty(const char *propertyKey, mitk::BaseProperty *property) { this->m_DataStorage->GetNode(mitk::NodePredicateDataType::New("Image"))->SetProperty(propertyKey, property); } vtkRenderWindow *mitk::RenderingTestHelper::GetVtkRenderWindow() { return m_RenderWindow->GetVtkRenderWindow(); } bool mitk::RenderingTestHelper::CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold) { this->Render(); // retVal meanings: (see VTK/Rendering/vtkTesting.h) // 0 = test failed // 1 = test passed // 2 = test not run // 3 = something with vtkInteraction if (vtkTesting::Test(argc, argv, this->GetVtkRenderWindow(), threshold) == 1) return true; else return false; } // method to save a screenshot of the renderwindow (e.g. create a reference screenshot) void mitk::RenderingTestHelper::SaveAsPNG(std::string fileName) { vtkSmartPointer renderer = this->GetVtkRenderer(); bool doubleBuffering(renderer->GetRenderWindow()->GetDoubleBuffer()); renderer->GetRenderWindow()->DoubleBufferOff(); vtkSmartPointer magnifier = vtkSmartPointer::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(1); vtkSmartPointer fileWriter = vtkSmartPointer::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.c_str()); fileWriter->Write(); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void mitk::RenderingTestHelper::SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow) { m_AutomaticallyCloseRenderWindow = automaticallyCloseRenderWindow; } void mitk::RenderingTestHelper::SaveReferenceScreenShot(std::string fileName) { this->SaveAsPNG(fileName); } void mitk::RenderingTestHelper::AddToStorage(const std::string &filename) { try { mitk::IOUtil::Load(filename, *m_DataStorage.GetPointer()); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } - catch (itk::ExceptionObject &e) + catch ( const itk::ExceptionObject &e ) { MITK_ERROR << "Failed loading test data '" << filename << "': " << e.what(); } } void mitk::RenderingTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } diff --git a/Modules/Core/src/DataManagement/mitkDataStorage.cpp b/Modules/Core/src/DataManagement/mitkDataStorage.cpp index 6f0f32f2ad..7db3374a9d 100644 --- a/Modules/Core/src/DataManagement/mitkDataStorage.cpp +++ b/Modules/Core/src/DataManagement/mitkDataStorage.cpp @@ -1,588 +1,588 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDataStorage.h" #include "itkCommand.h" #include "itkMutexLockHolder.h" #include "mitkDataNode.h" #include "mitkGroupTagProperty.h" #include "mitkImage.h" #include "mitkNodePredicateBase.h" #include "mitkNodePredicateProperty.h" #include "mitkProperties.h" #include "mitkArbitraryTimeGeometry.h" mitk::DataStorage::DataStorage() : itk::Object(), m_BlockNodeModifiedEvents(false) { } mitk::DataStorage::~DataStorage() { ///// we can not call GetAll() in destructor, because it is implemented in a subclass // SetOfObjects::ConstPointer all = this->GetAll(); // for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) // this->RemoveListeners(it->Value()); // m_NodeModifiedObserverTags.clear(); // m_NodeDeleteObserverTags.clear(); } void mitk::DataStorage::Add(DataNode *node, DataNode *parent) { DataStorage::SetOfObjects::Pointer parents = DataStorage::SetOfObjects::New(); if (parent != nullptr) //< Return empty set if parent is null parents->InsertElement(0, parent); this->Add(node, parents); } void mitk::DataStorage::Remove(const DataStorage::SetOfObjects *nodes) { if (nodes == nullptr) return; for (DataStorage::SetOfObjects::ConstIterator it = nodes->Begin(); it != nodes->End(); it++) this->Remove(it.Value()); } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::GetSubset(const NodePredicateBase *condition) const { DataStorage::SetOfObjects::ConstPointer result = this->FilterSetOfObjects(this->GetAll(), condition); return result; } mitk::DataNode *mitk::DataStorage::GetNamedNode(const char *name) const { if (name == nullptr) return nullptr; StringProperty::Pointer s(StringProperty::New(name)); NodePredicateProperty::Pointer p = NodePredicateProperty::New("name", s); DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(p); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } mitk::DataNode *mitk::DataStorage::GetNode(const NodePredicateBase *condition) const { if (condition == nullptr) return nullptr; DataStorage::SetOfObjects::ConstPointer rs = this->GetSubset(condition); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } mitk::DataNode *mitk::DataStorage::GetNamedDerivedNode(const char *name, const DataNode *sourceNode, bool onlyDirectDerivations) const { if (name == nullptr) return nullptr; StringProperty::Pointer s(StringProperty::New(name)); NodePredicateProperty::Pointer p = NodePredicateProperty::New("name", s); DataStorage::SetOfObjects::ConstPointer rs = this->GetDerivations(sourceNode, p, onlyDirectDerivations); if (rs->Size() >= 1) return rs->GetElement(0); else return nullptr; } void mitk::DataStorage::PrintSelf(std::ostream &os, itk::Indent indent) const { // Superclass::PrintSelf(os, indent); DataStorage::SetOfObjects::ConstPointer all = this->GetAll(); os << indent << "DataStorage " << this << " is managing " << all->Size() << " objects. List of objects:" << std::endl; for (DataStorage::SetOfObjects::ConstIterator allIt = all->Begin(); allIt != all->End(); allIt++) { std::string name; allIt.Value()->GetName(name); std::string datatype; if (allIt.Value()->GetData() != nullptr) datatype = allIt.Value()->GetData()->GetNameOfClass(); os << indent << " " << allIt.Value().GetPointer() << "<" << datatype << ">: " << name << std::endl; DataStorage::SetOfObjects::ConstPointer parents = this->GetSources(allIt.Value()); if (parents->Size() > 0) { os << indent << " Direct sources: "; for (DataStorage::SetOfObjects::ConstIterator parentIt = parents->Begin(); parentIt != parents->End(); parentIt++) os << parentIt.Value().GetPointer() << ", "; os << std::endl; } DataStorage::SetOfObjects::ConstPointer derivations = this->GetDerivations(allIt.Value()); if (derivations->Size() > 0) { os << indent << " Direct derivations: "; for (DataStorage::SetOfObjects::ConstIterator derivationIt = derivations->Begin(); derivationIt != derivations->End(); derivationIt++) os << derivationIt.Value().GetPointer() << ", "; os << std::endl; } } os << std::endl; } mitk::DataStorage::SetOfObjects::ConstPointer mitk::DataStorage::FilterSetOfObjects(const SetOfObjects *set, const NodePredicateBase *condition) const { if (set == nullptr) return nullptr; DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); for (DataStorage::SetOfObjects::ConstIterator it = set->Begin(); it != set->End(); it++) if (condition == nullptr || condition->CheckNode(it.Value()) == true) // alway copy the set, otherwise the iterator in DataStorage::Remove() will crash result->InsertElement(result->Size(), it.Value()); return DataStorage::SetOfObjects::ConstPointer(result); } const mitk::DataNode::GroupTagList mitk::DataStorage::GetGroupTags() const { DataNode::GroupTagList result; SetOfObjects::ConstPointer all = this->GetAll(); if (all.IsNull()) return result; for (DataStorage::SetOfObjects::ConstIterator nodeIt = all->Begin(); nodeIt != all->End(); nodeIt++) // for each node { PropertyList *pl = nodeIt.Value()->GetPropertyList(); for (auto propIt = pl->GetMap()->begin(); propIt != pl->GetMap()->end(); ++propIt) if (dynamic_cast(propIt->second.GetPointer()) != nullptr) result.insert(propIt->first); } return result; } void mitk::DataStorage::EmitAddNodeEvent(const DataNode *node) { AddNodeEvent.Send(node); } void mitk::DataStorage::EmitRemoveNodeEvent(const DataNode *node) { RemoveNodeEvent.Send(node); } void mitk::DataStorage::OnNodeInteractorChanged(itk::Object *caller, const itk::EventObject &) { const auto *_Node = dynamic_cast(caller); if (_Node) { InteractorChangedNodeEvent.Send(_Node); } } void mitk::DataStorage::OnNodeModifiedOrDeleted(const itk::Object *caller, const itk::EventObject &event) { if (m_BlockNodeModifiedEvents) return; const auto *_Node = dynamic_cast(caller); if (_Node) { const auto *modEvent = dynamic_cast(&event); if (modEvent) ChangedNodeEvent.Send(_Node); else DeleteNodeEvent.Send(_Node); } } void mitk::DataStorage::AddListeners(const DataNode *_Node) { itk::MutexLockHolder locked(m_MutexOne); // node must not be 0 and must not be yet registered auto *NonConstNode = const_cast(_Node); if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) == m_NodeModifiedObserverTags.end()) { itk::MemberCommand::Pointer nodeModifiedCommand = itk::MemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this, &DataStorage::OnNodeModifiedOrDeleted); m_NodeModifiedObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); itk::MemberCommand::Pointer interactorChangedCommand = itk::MemberCommand::New(); interactorChangedCommand->SetCallbackFunction(this, &DataStorage::OnNodeInteractorChanged); m_NodeInteractorChangedObserverTags[NonConstNode] = NonConstNode->AddObserver(DataNode::InteractorChangedEvent(), interactorChangedCommand); // add itk delete listener on datastorage itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &DataStorage::OnNodeModifiedOrDeleted); // add observer m_NodeDeleteObserverTags[NonConstNode] = NonConstNode->AddObserver(itk::DeleteEvent(), deleteCommand); } } void mitk::DataStorage::RemoveListeners(const DataNode *_Node) { itk::MutexLockHolder locked(m_MutexOne); // node must not be 0 and must be registered auto *NonConstNode = const_cast(_Node); if (_Node && m_NodeModifiedObserverTags.find(NonConstNode) != m_NodeModifiedObserverTags.end()) { // const cast is bad! but sometimes it is necessary. removing an observer does not really // touch the internal state NonConstNode->RemoveObserver(m_NodeModifiedObserverTags.find(NonConstNode)->second); NonConstNode->RemoveObserver(m_NodeDeleteObserverTags.find(NonConstNode)->second); NonConstNode->RemoveObserver(m_NodeInteractorChangedObserverTags.find(NonConstNode)->second); m_NodeModifiedObserverTags.erase(NonConstNode); m_NodeDeleteObserverTags.erase(NonConstNode); m_NodeInteractorChangedObserverTags.erase(NonConstNode); } } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeBoundingGeometry3D(const SetOfObjects *input, const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) const { if (input == nullptr) throw std::invalid_argument("DataStorage: input is invalid"); BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid = 0; Point3D point; Vector3D minSpacing; minSpacing.Fill(itk::NumericTraits::max()); ScalarType stmax = itk::NumericTraits::max(); ScalarType stmin = itk::NumericTraits::NonpositiveMin(); std::set existingTimePoints; ScalarType maximalTime = 0; // Needed for check of zero bounding boxes ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); for (SetOfObjects::ConstIterator it = input->Begin(); it != input->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *timeGeometry = node->GetData()->GetUpdatedTimeGeometry(); if (timeGeometry != nullptr) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = timeGeometry->GetBoundingBoxInWorld()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for (i = 0; i < 8; ++i) { point = timeGeometry->GetCornerPointInWorld(i); if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large) pointscontainer->InsertElement(pointid++, point); else { itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node); } } try { // time bounds // iterate over all time steps // Attention: Objects with zero bounding box are not respected in time bound calculation for (TimeStepType i = 0; i < timeGeometry->CountTimeSteps(); i++) { // We must not use 'node->GetData()->GetGeometry(i)->GetSpacing()' here, as it returns the spacing // in its original space, which, in case of an image geometry, can have the values in different // order than in world space. For the further calculations, we need to have the spacing values // in world coordinate order (sag-cor-ax). Vector3D spacing; spacing.Fill(1.0); node->GetData()->GetGeometry(i)->IndexToWorld(spacing, spacing); for (int axis = 0; axis < 3; ++ axis) { ScalarType space = std::abs(spacing[axis]); if (space < minSpacing[axis]) { minSpacing[axis] = space; } } const auto curTimeBounds = timeGeometry->GetTimeBounds(i); if ((curTimeBounds[0] > stmin) && (curTimeBounds[0] < stmax)) { existingTimePoints.insert(curTimeBounds[0]); } if ((curTimeBounds[1] > maximalTime) && (curTimeBounds[1] < stmax)) { maximalTime = curTimeBounds[1]; } } } - catch (itk::ExceptionObject &e) + catch ( const itk::ExceptionObject &e ) { - MITK_ERROR << e << std::endl; + MITK_ERROR << e.GetDescription() << std::endl; } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); // compute the number of time steps if (existingTimePoints.empty()) // make sure that there is at least one time sliced geometry in the data storage { existingTimePoints.insert(0.0); maximalTime = 1.0; } ArbitraryTimeGeometry::Pointer timeGeometry = nullptr; if (result->GetPoints()->Size() > 0) { // Initialize a geometry of a single time step Geometry3D::Pointer geometry = Geometry3D::New(); geometry->Initialize(); // correct bounding-box (is now in mm, should be in index-coordinates) // according to spacing BoundingBox::BoundsArrayType bounds = result->GetBounds(); AffineTransform3D::OutputVectorType offset; for (int i = 0; i < 3; ++i) { offset[i] = bounds[i * 2]; bounds[i * 2] = 0.0; bounds[i * 2 + 1] = (bounds[i * 2 + 1] - offset[i]) / minSpacing[i]; } geometry->GetIndexToWorldTransform()->SetOffset(offset); geometry->SetBounds(bounds); geometry->SetSpacing(minSpacing); // Initialize the time sliced geometry auto tsIterator = existingTimePoints.cbegin(); auto tsPredecessor = tsIterator++; auto tsEnd = existingTimePoints.cend(); timeGeometry = ArbitraryTimeGeometry::New(); for (; tsIterator != tsEnd; ++tsIterator, ++tsPredecessor) { timeGeometry->AppendNewTimeStep(geometry, *tsPredecessor, *tsIterator); } timeGeometry->AppendNewTimeStep(geometry, *tsPredecessor, maximalTime); timeGeometry->Update(); } return timeGeometry.GetPointer(); } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeBoundingGeometry3D(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) const { return this->ComputeBoundingGeometry3D(this->GetAll(), boolPropertyKey, renderer, boolPropertyKey2); } mitk::TimeGeometry::ConstPointer mitk::DataStorage::ComputeVisibleBoundingGeometry3D(const BaseRenderer *renderer, const char *boolPropertyKey) { return ComputeBoundingGeometry3D("visible", renderer, boolPropertyKey); } mitk::BoundingBox::Pointer mitk::DataStorage::ComputeBoundingBox(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) { BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); BoundingBox::PointIdentifier pointid = 0; Point3D point; // Needed for check of zero bounding boxes ScalarType nullpoint[] = {0, 0, 0, 0, 0, 0}; BoundingBox::BoundsArrayType itkBoundsZero(nullpoint); SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry(); if (geometry != nullptr) { // bounding box (only if non-zero) BoundingBox::BoundsArrayType itkBounds = geometry->GetBoundingBoxInWorld()->GetBounds(); if (itkBounds == itkBoundsZero) { continue; } unsigned char i; for (i = 0; i < 8; ++i) { point = geometry->GetCornerPointInWorld(i); if (point[0] * point[0] + point[1] * point[1] + point[2] * point[2] < large) pointscontainer->InsertElement(pointid++, point); else { itkGenericOutputMacro(<< "Unrealistically distant corner point encountered. Ignored. Node: " << node); } } } } } BoundingBox::Pointer result = BoundingBox::New(); result->SetPoints(pointscontainer); result->ComputeBoundingBox(); return result; } mitk::TimeBounds mitk::DataStorage::ComputeTimeBounds(const char *boolPropertyKey, const BaseRenderer *renderer, const char *boolPropertyKey2) { TimeBounds timeBounds; ScalarType stmin, stmax, cur; stmin = itk::NumericTraits::NonpositiveMin(); stmax = itk::NumericTraits::max(); timeBounds[0] = stmax; timeBounds[1] = stmin; SetOfObjects::ConstPointer all = this->GetAll(); for (SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) { DataNode::Pointer node = it->Value(); if ((node.IsNotNull()) && (node->GetData() != nullptr) && (node->GetData()->IsEmpty() == false) && node->IsOn(boolPropertyKey, renderer) && node->IsOn(boolPropertyKey2, renderer)) { const TimeGeometry *geometry = node->GetData()->GetUpdatedTimeGeometry(); if (geometry != nullptr) { const TimeBounds &curTimeBounds = geometry->GetTimeBounds(); cur = curTimeBounds[0]; // is it after -infinity, but before everything else that we found until now? if ((cur > stmin) && (cur < timeBounds[0])) timeBounds[0] = cur; cur = curTimeBounds[1]; // is it before infinity, but after everything else that we found until now? if ((cur < stmax) && (cur > timeBounds[1])) timeBounds[1] = cur; } } } if (!(timeBounds[0] < stmax)) { timeBounds[0] = stmin; timeBounds[1] = stmax; } return timeBounds; } void mitk::DataStorage::BlockNodeModifiedEvents(bool block) { m_BlockNodeModifiedEvents = block; } mitk::DataNode::Pointer mitk::FindTopmostVisibleNode(const DataStorage::SetOfObjects::ConstPointer nodes, const Point3D worldPosition, const TimePointType timePoint, const BaseRenderer* baseRender) { if (nodes.IsNull()) { return nullptr; } mitk::DataNode::Pointer topLayerNode = nullptr; int maxLayer = std::numeric_limits::min(); for (auto node : *nodes) { if (node.IsNull()) { continue; } bool isHelperObject = false; node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) { continue; } auto data = node->GetData(); if (nullptr == data) { continue; } auto geometry = data->GetGeometry(); if (nullptr == geometry || !geometry->IsInside(worldPosition)) { continue; } auto timeGeometry = data->GetUpdatedTimeGeometry(); if (nullptr == timeGeometry) { continue; } if (!timeGeometry->IsValidTimePoint(timePoint)) { continue; } int layer = 0; if (!node->GetIntProperty("layer", layer, baseRender)) { continue; } if (layer <= maxLayer) { continue; } if (!node->IsVisible(baseRender)) { continue; } topLayerNode = node; maxLayer = layer; } return topLayerNode; } diff --git a/Modules/Core/src/IO/mitkGeometry3DToXML.cpp b/Modules/Core/src/IO/mitkGeometry3DToXML.cpp index d0019ebddf..7ce7d9455c 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 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) + catch ( const 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) + catch ( const 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) + catch ( const 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 8925d6245c..aedb15397a 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 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) + catch ( const 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/IO/mitkRawImageFileReader.cpp b/Modules/Core/src/IO/mitkRawImageFileReader.cpp index a9823185ce..adc3972deb 100644 --- a/Modules/Core/src/IO/mitkRawImageFileReader.cpp +++ b/Modules/Core/src/IO/mitkRawImageFileReader.cpp @@ -1,202 +1,202 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRawImageFileReader.h" #include "mitkIOConstants.h" #include "mitkIOMimeTypes.h" #include "mitkITKImageImport.h" #include "mitkImageCast.h" #include #include #include mitk::RawImageFileReaderService::RawImageFileReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::RAW_MIMETYPE()), "ITK raw image reader") { Options defaultOptions; defaultOptions[IOConstants::PIXEL_TYPE()] = IOConstants::PIXEL_TYPE_USHORT(); std::vector pixelEnum; pixelEnum.push_back(IOConstants::PIXEL_TYPE_UCHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_CHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_USHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_SHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_UINT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_INT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_FLOAT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_DOUBLE()); defaultOptions[IOConstants::PIXEL_TYPE_ENUM()] = pixelEnum; defaultOptions[IOConstants::DIMENSION()] = std::string("3"); std::vector dimEnum; dimEnum.push_back("2"); dimEnum.push_back("3"); defaultOptions[IOConstants::DIMENSION_ENUM()] = dimEnum; defaultOptions[IOConstants::ENDIANNESS()] = IOConstants::ENDIANNESS_LITTLE(); std::vector endianEnum; endianEnum.push_back(IOConstants::ENDIANNESS_LITTLE()); endianEnum.push_back(IOConstants::ENDIANNESS_BIG()); defaultOptions[IOConstants::ENDIANNESS_ENUM()] = endianEnum; defaultOptions[IOConstants::SIZE_X()] = 0; defaultOptions[IOConstants::SIZE_Y()] = 0; defaultOptions[IOConstants::SIZE_Z()] = 0; // defaultOptions[IOConstants::SIZE_T()] = 0; this->SetDefaultOptions(defaultOptions); this->RegisterService(); } mitk::RawImageFileReaderService::RawImageFileReaderService(const mitk::RawImageFileReaderService &other) : AbstractFileReader(other) { } std::vector> mitk::RawImageFileReaderService::Read() { std::vector result; const std::string path = this->GetLocalFileName(); const Options options = this->GetOptions(); const std::string dimensionality = options.find(IOConstants::DIMENSION())->second.ToString(); const std::string pixelType = options.find(IOConstants::PIXEL_TYPE())->second.ToString(); EndianityType endianity = options.find(IOConstants::ENDIANNESS())->second.ToString() == IOConstants::ENDIANNESS_LITTLE() ? LITTLE : BIG; int dimensions[4]; dimensions[0] = us::any_cast(options.find(IOConstants::SIZE_X())->second); dimensions[1] = us::any_cast(options.find(IOConstants::SIZE_Y())->second); dimensions[2] = us::any_cast(options.find(IOConstants::SIZE_Z())->second); dimensions[3] = 0; // us::any_cast(options.find(IOConstants::SIZE_T())->second); // check file dimensionality and pixel type and perform reading according to it if (dimensionality == "2") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE()) result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else if (dimensionality == "3") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE()) result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else { MITK_INFO << "Error while reading raw file: Dimensionality not supported" << std::endl; } return result; } template mitk::BaseData::Pointer mitk::RawImageFileReaderService::TypedRead(const std::string &path, EndianityType endianity, int *size) { typedef itk::Image ImageType; typedef itk::ImageFileReader ReaderType; typedef itk::RawImageIO IOType; typename ReaderType::Pointer reader = ReaderType::New(); typename IOType::Pointer io = IOType::New(); io->SetFileDimensionality(VImageDimensions); for (unsigned short int dim = 0; dim < VImageDimensions; ++dim) { io->SetDimensions(dim, size[dim]); } if (endianity == LITTLE) { io->SetByteOrderToLittleEndian(); } else if (endianity == BIG) { io->SetByteOrderToBigEndian(); } else { MITK_INFO << "Warning: endianity not properly set. Resulting image might be incorrect"; } reader->SetImageIO(io); reader->SetFileName(path); try { reader->Update(); } - catch (itk::ExceptionObject &err) + catch ( const itk::ExceptionObject &err ) { MITK_ERROR << "An error occurred during the raw image reading process: "; - MITK_INFO << err << std::endl; + MITK_INFO << err.GetDescription() << std::endl; } mitk::Image::Pointer image = mitk::Image::New(); mitk::CastToMitkImage(reader->GetOutput(), image); image->SetVolume(reader->GetOutput()->GetBufferPointer()); return image.GetPointer(); } mitk::RawImageFileReaderService *mitk::RawImageFileReaderService::Clone() const { return new RawImageFileReaderService(*this); } diff --git a/Modules/Core/src/mitkCoreObjectFactory.cpp b/Modules/Core/src/mitkCoreObjectFactory.cpp index 5ee3a790aa..4a382c7819 100644 --- a/Modules/Core/src/mitkCoreObjectFactory.cpp +++ b/Modules/Core/src/mitkCoreObjectFactory.cpp @@ -1,458 +1,458 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCoreObjectFactory.h" #include "mitkConfig.h" #include "mitkColorProperty.h" #include "mitkDataNode.h" #include "mitkEnumerationProperty.h" #include "mitkGeometry3D.h" #include "mitkGeometryData.h" #include "mitkImage.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkPlaneGeometry.h" #include "mitkPlaneGeometryData.h" #include "mitkPlaneGeometryDataMapper2D.h" #include "mitkPlaneGeometryDataVtkMapper3D.h" #include "mitkPointSet.h" #include "mitkPointSetVtkMapper2D.h" #include "mitkPointSetVtkMapper3D.h" #include "mitkProperties.h" #include "mitkPropertyList.h" #include "mitkSlicedGeometry3D.h" #include "mitkSmartPointerProperty.h" #include "mitkStringProperty.h" #include "mitkSurface.h" #include "mitkSurface.h" #include "mitkSurfaceVtkMapper2D.h" #include "mitkSurfaceVtkMapper3D.h" #include "mitkTimeGeometry.h" #include "mitkTransferFunctionProperty.h" #include "mitkVtkInterpolationProperty.h" #include "mitkVtkRepresentationProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include // Legacy Support: #include #include #include void mitk::CoreObjectFactory::RegisterExtraFactory(CoreObjectFactoryBase *factory) { MITK_DEBUG << "CoreObjectFactory: registering extra factory of type " << factory->GetNameOfClass(); m_ExtraFactories.insert(CoreObjectFactoryBase::Pointer(factory)); // Register Legacy Reader and Writer this->RegisterLegacyReaders(factory); this->RegisterLegacyWriters(factory); } void mitk::CoreObjectFactory::UnRegisterExtraFactory(CoreObjectFactoryBase *factory) { MITK_DEBUG << "CoreObjectFactory: un-registering extra factory of type " << factory->GetNameOfClass(); this->UnRegisterLegacyWriters(factory); this->UnRegisterLegacyReaders(factory); try { m_ExtraFactories.erase(factory); } - catch (std::exception const &e) + catch ( const std::exception &e ) { MITK_ERROR << "Caugt exception while unregistering: " << e.what(); } } mitk::CoreObjectFactory::Pointer mitk::CoreObjectFactory::GetInstance() { static mitk::CoreObjectFactory::Pointer instance; if (instance.IsNull()) { instance = mitk::CoreObjectFactory::New(); } return instance; } mitk::CoreObjectFactory::~CoreObjectFactory() { for (auto iter = m_LegacyReaders.begin(); iter != m_LegacyReaders.end(); ++iter) { for (auto &elem : iter->second) { delete elem; } } for (auto iter = m_LegacyWriters.begin(); iter != m_LegacyWriters.end(); ++iter) { for (auto &elem : iter->second) { delete elem; } } } void mitk::CoreObjectFactory::SetDefaultProperties(mitk::DataNode *node) { if (node == nullptr) return; mitk::DataNode::Pointer nodePointer = node; mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { mitk::ImageVtkMapper2D::SetDefaultProperties(node); } mitk::PlaneGeometryData::Pointer planeGeometry = dynamic_cast(node->GetData()); if (planeGeometry.IsNotNull()) { mitk::PlaneGeometryDataMapper2D::SetDefaultProperties(node); } mitk::Surface::Pointer surface = dynamic_cast(node->GetData()); if (surface.IsNotNull()) { mitk::SurfaceVtkMapper2D::SetDefaultProperties(node); mitk::SurfaceVtkMapper3D::SetDefaultProperties(node); } mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNotNull()) { mitk::PointSetVtkMapper2D::SetDefaultProperties(node); mitk::PointSetVtkMapper3D::SetDefaultProperties(node); } for (auto it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); ++it) { (*it)->SetDefaultProperties(node); } } mitk::CoreObjectFactory::CoreObjectFactory() { static bool alreadyDone = false; if (!alreadyDone) { CreateFileExtensionsMap(); // RegisterLegacyReaders(this); // RegisterLegacyWriters(this); alreadyDone = true; } } mitk::Mapper::Pointer mitk::CoreObjectFactory::CreateMapper(mitk::DataNode *node, MapperSlotId id) { mitk::Mapper::Pointer newMapper = nullptr; mitk::Mapper::Pointer tmpMapper = nullptr; // check whether extra factories provide mapper for (auto it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); ++it) { tmpMapper = (*it)->CreateMapper(node, id); if (tmpMapper.IsNotNull()) newMapper = tmpMapper; } if (newMapper.IsNull()) { mitk::BaseData *data = node->GetData(); if (id == mitk::BaseRenderer::Standard2D) { if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::ImageVtkMapper2D::New(); newMapper->SetDataNode(node); } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::PlaneGeometryDataMapper2D::New(); newMapper->SetDataNode(node); } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::SurfaceVtkMapper2D::New(); // cast because SetDataNode is not virtual auto *castedMapper = dynamic_cast(newMapper.GetPointer()); castedMapper->SetDataNode(node); } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::PointSetVtkMapper2D::New(); newMapper->SetDataNode(node); } } else if (id == mitk::BaseRenderer::Standard3D) { if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::PlaneGeometryDataVtkMapper3D::New(); newMapper->SetDataNode(node); } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::SurfaceVtkMapper3D::New(); newMapper->SetDataNode(node); } else if ((dynamic_cast(data) != nullptr)) { newMapper = mitk::PointSetVtkMapper3D::New(); newMapper->SetDataNode(node); } } } return newMapper; } const char *mitk::CoreObjectFactory::GetFileExtensions() { MultimapType aMap; for (auto it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); ++it) { aMap = (*it)->GetFileExtensionsMap(); this->MergeFileExtensions(m_FileExtensionsMap, aMap); } this->CreateFileExtensions(m_FileExtensionsMap, m_FileExtensions); return m_FileExtensions.c_str(); } void mitk::CoreObjectFactory::MergeFileExtensions(MultimapType &fileExtensionsMap, MultimapType inputMap) { std::pair pairOfIter; for (auto it = inputMap.begin(); it != inputMap.end(); ++it) { bool duplicateFound = false; pairOfIter = fileExtensionsMap.equal_range((*it).first); for (auto it2 = pairOfIter.first; it2 != pairOfIter.second; ++it2) { // cout << " [" << (*it).first << ", " << (*it).second << "]" << endl; std::string aString = (*it2).second; if (aString.compare((*it).second) == 0) { // cout << " DUP!! [" << (*it).first << ", " << (*it).second << "]" << endl; duplicateFound = true; break; } } if (!duplicateFound) { fileExtensionsMap.insert(std::pair((*it).first, (*it).second)); } } } mitk::CoreObjectFactoryBase::MultimapType mitk::CoreObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } void mitk::CoreObjectFactory::CreateFileExtensionsMap() { /* m_FileExtensionsMap.insert(std::pair("*.dcm", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.DCM", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.dc3", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.DC3", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.gdcm", "DICOM files")); m_FileExtensionsMap.insert(std::pair("*.seq", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.seq.gz", "DKFZ Pic")); m_FileExtensionsMap.insert(std::pair("*.dcm", "Sets of 2D slices")); m_FileExtensionsMap.insert(std::pair("*.gdcm", "Sets of 2D slices")); */ } const char *mitk::CoreObjectFactory::GetSaveFileExtensions() { MultimapType aMap; for (auto it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); ++it) { aMap = (*it)->GetSaveFileExtensionsMap(); this->MergeFileExtensions(m_SaveFileExtensionsMap, aMap); } this->CreateFileExtensions(m_SaveFileExtensionsMap, m_SaveFileExtensions); return m_SaveFileExtensions.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::CoreObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } mitk::CoreObjectFactory::FileWriterList mitk::CoreObjectFactory::GetFileWriters() { FileWriterList allWriters = m_FileWriters; // sort to merge lists later on typedef std::set FileWriterSet; FileWriterSet fileWritersSet; fileWritersSet.insert(allWriters.begin(), allWriters.end()); // collect all extra factories for (auto it = m_ExtraFactories.begin(); it != m_ExtraFactories.end(); ++it) { FileWriterList list2 = (*it)->GetFileWriters(); // add them to the sorted set fileWritersSet.insert(list2.begin(), list2.end()); } // write back to allWriters to return a list allWriters.clear(); allWriters.insert(allWriters.end(), fileWritersSet.begin(), fileWritersSet.end()); return allWriters; } void mitk::CoreObjectFactory::MapEvent(const mitk::Event *, const int) { } std::string mitk::CoreObjectFactory::GetDescriptionForExtension(const std::string &extension) { std::multimap fileExtensionMap = GetSaveFileExtensionsMap(); for (auto it = fileExtensionMap.begin(); it != fileExtensionMap.end(); ++it) if (it->first == extension) return it->second; return ""; // If no matching extension was found, return emtpy string } void mitk::CoreObjectFactory::RegisterLegacyReaders(mitk::CoreObjectFactoryBase *factory) { // We are not really interested in the string, just call the method since // many readers initialize the map the first time when this method is called factory->GetFileExtensions(); std::map> extensionsByCategories; std::multimap fileExtensionMap = factory->GetFileExtensionsMap(); for (auto it = fileExtensionMap.begin(); it != fileExtensionMap.end(); ++it) { std::string extension = it->first; // remove "*." extension = extension.erase(0, 2); extensionsByCategories[it->second].push_back(extension); } for (auto &extensionsByCategorie : extensionsByCategories) { m_LegacyReaders[factory].push_back( new mitk::LegacyFileReaderService(extensionsByCategorie.second, extensionsByCategorie.first)); } } void mitk::CoreObjectFactory::UnRegisterLegacyReaders(mitk::CoreObjectFactoryBase *factory) { auto iter = m_LegacyReaders.find(factory); if (iter != m_LegacyReaders.end()) { for (auto &elem : iter->second) { delete elem; } m_LegacyReaders.erase(iter); } } void mitk::CoreObjectFactory::RegisterLegacyWriters(mitk::CoreObjectFactoryBase *factory) { // Get all external Writers mitk::CoreObjectFactory::FileWriterList writers = factory->GetFileWriters(); // We are not really interested in the string, just call the method since // many writers initialize the map the first time when this method is called factory->GetSaveFileExtensions(); MultimapType fileExtensionMap = factory->GetSaveFileExtensionsMap(); for (auto it = writers.begin(); it != writers.end(); ++it) { std::vector extensions = (*it)->GetPossibleFileExtensions(); if (extensions.empty()) continue; std::string description; for (auto ext = extensions.begin(); ext != extensions.end(); ++ext) { if (ext->empty()) continue; std::string extension = *ext; std::string extensionWithStar = extension; if (extension.find_first_of('*') == 0) { // remove "*." extension = extension.substr(0, extension.size() - 2); } else { extensionWithStar.insert(extensionWithStar.begin(), '*'); } for (auto fileExtensionIter = fileExtensionMap.begin(); fileExtensionIter != fileExtensionMap.end(); ++fileExtensionIter) { if (fileExtensionIter->first == extensionWithStar) { description = fileExtensionIter->second; break; } } if (!description.empty()) break; } if (description.empty()) { description = std::string("Legacy ") + (*it)->GetNameOfClass() + " Reader"; } mitk::FileWriter::Pointer fileWriter(it->GetPointer()); mitk::LegacyFileWriterService *lfws = new mitk::LegacyFileWriterService(fileWriter, description); m_LegacyWriters[factory].push_back(lfws); } } void mitk::CoreObjectFactory::UnRegisterLegacyWriters(mitk::CoreObjectFactoryBase *factory) { auto iter = m_LegacyWriters.find(factory); if (iter != m_LegacyWriters.end()) { for (auto &elem : iter->second) { delete elem; } m_LegacyWriters.erase(iter); } } diff --git a/Modules/Core/test/mitkGrabItkImageMemoryTest.cpp b/Modules/Core/test/mitkGrabItkImageMemoryTest.cpp index d2646230d6..7adb687145 100644 --- a/Modules/Core/test/mitkGrabItkImageMemoryTest.cpp +++ b/Modules/Core/test/mitkGrabItkImageMemoryTest.cpp @@ -1,124 +1,124 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkITKImageImport.h" #include "mitkTestingMacros.h" #include "mitkImagePixelReadAccessor.h" #include #include "mitkImageAccessByItk.h" /** * An ITK-based filter for thresholding. * * The filter represents the typical usage of ITK-like filters inside MITK. It is to be called for an mitk::Image * by using the AccessByItk macro. The filter executes the binary threshold filter and imports the result into the * output by using the ImportItkImage method. * * @param output mitk::Image to hold the result of the filter * @param th[] two double values to set the lower/upper threshold */ //! [ItkThresholdFilter] template static void ItkThresholdFilter(const itk::Image *image, mitk::Image::Pointer &output, const double th[]) { typedef itk::Image InputImageType; typedef itk::ThresholdImageFilter ThresholdFilterType; typename ThresholdFilterType::Pointer thresholder = ThresholdFilterType::New(); thresholder->SetInput(image); thresholder->ThresholdOutside(th[0], th[1]); thresholder->Update(); try { output = mitk::GrabItkImageMemory(thresholder->GetOutput()); } - catch (itk::ExceptionObject &) + catch ( const itk::ExceptionObject & ) { MITK_TEST_FAILED_MSG(<< "Thresholding computation failed"); } } //! [ItkThresholdFilter] /** * Creates an mitk::Image, executes the binary threshold filter through AccessByItk and * checks whether the image data was correctly imported back to an mitk::Image. */ template bool Assert_ItkImportWithinAccessByItkSucceded_ReturnsTrue() { // data for 3x3x3 image const unsigned int dimensions[3] = {3, 3, 3}; auto image_data = new TPixel[27]; // ground truth for result check auto ground_truth = new TPixel[27]; double threshold[2] = {90.0, 180.0}; // fill image for (unsigned int i = 0; i < 27; i++) { image_data[i] = static_cast(i * 10); ground_truth[i] = 0; if (image_data[i] >= threshold[0] && image_data[i] <= threshold[1]) ground_truth[i] = static_cast(i * 10); } mitk::Image::Pointer input = mitk::Image::New(); input->Initialize(mitk::MakeScalarPixelType(), 3, dimensions); input->SetImportVolume(image_data); //! [OutOfScopeCall] mitk::Image::Pointer output = mitk::Image::New(); AccessByItk_2(input, ItkThresholdFilter, output, threshold); //! [OutOfScopeCall] mitk::ImagePixelReadAccessor readAccessor(output); const TPixel *output_data = readAccessor.GetData(); bool equal = true; for (unsigned int i = 0; i < 27; i++) { equal &= (ground_truth[i] == output_data[i]); if (!equal) { MITK_INFO << " :: At position " << i << " : " << ground_truth[i] << " ? " << output_data[i] << "\n"; break; } } MITK_TEST_CONDITION(equal, " Imported output data equals the ground truth"); return equal; } int mitkGrabItkImageMemoryTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("mitkGrabItkImageMemoryTest") Assert_ItkImportWithinAccessByItkSucceded_ReturnsTrue(); // "Import successful on 3D short"); Assert_ItkImportWithinAccessByItkSucceded_ReturnsTrue(); // "Import succesfull on float"); Assert_ItkImportWithinAccessByItkSucceded_ReturnsTrue(); // "Import succesfull on uchar"); Assert_ItkImportWithinAccessByItkSucceded_ReturnsTrue(); // "Import succesfull on int"); MITK_TEST_END() } diff --git a/Modules/Core/test/mitkImageAccessorTest.cpp b/Modules/Core/test/mitkImageAccessorTest.cpp index 516d5245ba..be617bf5da 100644 --- a/Modules/Core/test/mitkImageAccessorTest.cpp +++ b/Modules/Core/test/mitkImageAccessorTest.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 "itkBarrier.h" #include "mitkIOUtil.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkImagePixelWriteAccessor.h" #include "mitkImageReadAccessor.h" #include "mitkImageTimeSelector.h" #include "mitkImageWriteAccessor.h" #include #include #include #include #include #include struct ThreadData { itk::Barrier::Pointer m_Barrier; // holds a pointer to the used barrier mitk::Image::Pointer data; // some random data int m_NoOfThreads; // holds the number of generated threads bool m_Successful; // to check if everything worked }; itk::SimpleFastMutexLock testMutex; ITK_THREAD_RETURN_TYPE ThreadMethod(void *data) { /* extract data pointer from Thread Info structure */ auto *pInfo = (struct itk::MultiThreader::ThreadInfoStruct *)data; // some data validity checking if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } // obtain user data for processing auto *threadData = (ThreadData *)pInfo->UserData; srand(pInfo->ThreadID); mitk::Image::Pointer im = threadData->data; int nrSlices = im->GetDimension(2); // Create randomly a PixelRead- or PixelWriteAccessor for a slice and access all pixels in it. try { if (rand() % 2) { testMutex.Lock(); mitk::ImageDataItem *iDi = im->GetSliceData(rand() % nrSlices); testMutex.Unlock(); while (!iDi->IsComplete()) { } // MITK_INFO << "pixeltype: " << im->GetPixelType().GetComponentTypeAsString(); if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3)) { // Use pixeltype&dimension specific read accessor int xlength = im->GetDimension(0); int ylength = im->GetDimension(1); mitk::ImagePixelReadAccessor readAccessor(im, iDi); itk::Index<2> idx; for (int i = 0; i < xlength; ++i) { for (int j = 0; j < ylength; ++j) { idx[0] = i; idx[1] = j; readAccessor.GetPixelByIndexSafe(idx); } } } else { // use general accessor mitk::ImageReadAccessor *iRA = new mitk::ImageReadAccessor(im, iDi); delete iRA; } } else { testMutex.Lock(); mitk::ImageDataItem *iDi = im->GetSliceData(rand() % nrSlices); testMutex.Unlock(); while (!iDi->IsComplete()) { } if ((im->GetPixelType().GetComponentTypeAsString() == "short") && (im->GetDimension() == 3)) { // Use pixeltype&dimension specific read accessor int xlength = im->GetDimension(0); int ylength = im->GetDimension(1); mitk::ImagePixelWriteAccessor writeAccessor(im, iDi); itk::Index<2> idx; for (int i = 0; i < xlength; ++i) { for (int j = 0; j < ylength; ++j) { idx[0] = i; idx[1] = j; short newVal = rand() % 16000; writeAccessor.SetPixelByIndexSafe(idx, newVal); short val = writeAccessor.GetPixelByIndexSafe(idx); if (val != newVal) { threadData->m_Successful = false; } } } } else { // use general accessor mitk::ImageWriteAccessor iB(im, iDi); void *pointer = iB.GetData(); *((char *)pointer) = 0; } } } - catch (mitk::MemoryIsLockedException &e) + catch ( const mitk::MemoryIsLockedException &e ) { threadData->m_Successful = false; e.Print(std::cout); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { threadData->m_Successful = false; e.Print(std::cout); } // data processing end! threadData->m_Barrier->Wait(); return ITK_THREAD_RETURN_VALUE; } int mitkImageAccessorTest(int argc, char *argv[]) { MITK_TEST_BEGIN("mitkImageAccessorTest"); std::cout << "Loading file: "; if (argc == 0) { std::cout << "no file specified [FAILED]" << std::endl; return EXIT_FAILURE; } mitk::Image::Pointer image = nullptr; try { image = mitk::IOUtil::Load(std::string(argv[1])); if (image.IsNull()) { MITK_TEST_FAILED_MSG(<< "file could not be loaded [FAILED]") } } - catch (itk::ExceptionObject &ex) + catch ( const itk::ExceptionObject &ex ) { - MITK_TEST_FAILED_MSG(<< "Exception: " << ex << "[FAILED]") + MITK_TEST_FAILED_MSG(<< "Exception: " << ex.GetDescription() << "[FAILED]") } // CHECK INAPPROPRIATE AND SPECIAL USAGE // recursive mutex lock MITK_TEST_OUTPUT(<< "Testing a recursive mutex lock attempt, should end in an exception ..."); MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception) mitk::ImageWriteAccessor first(image); mitk::ImageReadAccessor second(image); MITK_TEST_FOR_EXCEPTION_END(mitk::Exception) // ignore lock mechanism in read accessor try { mitk::ImageWriteAccessor first(image); mitk::ImageReadAccessor second(image, nullptr, mitk::ImageAccessorBase::IgnoreLock); MITK_TEST_CONDITION_REQUIRED(true, "Testing the option flag \"IgnoreLock\" in ReadAccessor"); } catch (const mitk::Exception & /*e*/) { MITK_TEST_CONDITION_REQUIRED(false, "Ignoring the lock mechanism leads to exception."); } // CREATE THREADS image->GetGeometry()->Initialize(); itk::MultiThreader::Pointer threader = itk::MultiThreader::New(); unsigned int noOfThreads = 100; // initialize barrier itk::Barrier::Pointer barrier = itk::Barrier::New(); barrier->Initialize(noOfThreads + 1); // add one for we stop the base thread when the worker threads are processing auto *threadData = new ThreadData; threadData->m_Barrier = barrier; threadData->m_NoOfThreads = noOfThreads; threadData->data = image; threadData->m_Successful = true; // spawn threads for (unsigned int i = 0; i < noOfThreads; ++i) { threader->SpawnThread(ThreadMethod, threadData); } // stop the base thread during worker thread execution barrier->Wait(); // terminate threads for (unsigned int j = 0; j < noOfThreads; ++j) { threader->TerminateThread(j); } bool TestSuccessful = threadData->m_Successful; delete threadData; MITK_TEST_CONDITION_REQUIRED(TestSuccessful, "Testing image access from multiple threads"); MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkImageSliceSelectorTest.cpp b/Modules/Core/test/mitkImageSliceSelectorTest.cpp index f0099ec45b..5e8a1a02e3 100644 --- a/Modules/Core/test/mitkImageSliceSelectorTest.cpp +++ b/Modules/Core/test/mitkImageSliceSelectorTest.cpp @@ -1,211 +1,211 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; 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 int mitkImageSliceSelectorTest(int argc, char *argv[]) { int slice_nr = 1; std::cout << "Loading file: "; if (argc == 0) { std::cout << "no file specified [FAILED]" << std::endl; return EXIT_FAILURE; } mitk::Image::Pointer image; try { image = mitk::IOUtil::Load(argv[1]); } catch (const mitk::Exception &) { std::cout << "file not an image - test will not be applied [PASSED]" << std::endl; std::cout << "[TEST DONE]" << std::endl; return EXIT_SUCCESS; } - catch (itk::ExceptionObject &ex) + catch ( const itk::ExceptionObject &ex ) { - std::cout << "Exception: " << ex << "[FAILED]" << std::endl; + std::cout << "Exception: " << ex.GetDescription() << "[FAILED]" << std::endl; return EXIT_FAILURE; } if (image->GetDimension(2) < 2) slice_nr = 0; // Take a slice mitk::ImageSliceSelector::Pointer slice = mitk::ImageSliceSelector::New(); slice->SetInput(image); slice->SetSliceNr(slice_nr); slice->Update(); std::cout << "Testing IsInitialized(): "; if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; /* deactivated because IpPic is not available any more (see bug 16662) if(itksys::SystemTools::LowerCase(itksys::SystemTools::GetFilenameExtension(argv[1])).find(".pic")!=std::string::npos) { std::cout << "Testing whether the slice is identical with a slice loaded by mitkIpPicGetSlice:"; mitkIpPicDescriptor *picslice = mitkIpPicGetSlice(argv[1], nullptr, (image->GetDimension(2)-1-slice_nr)+1); int i, size = _mitkIpPicSize(picslice); char * p1 = (char*)slice->GetPic()->data; char * p2 = (char*)picslice->data; //picslice->info->write_protect=mitkIpFalse; //mitkIpPicPut("C:\\1aaaaIPPIC.pic", picslice); //mitkIpPicPut("C:\\1aaaaSEL.pic", slice->GetPic()); for(i=0; iSetInput(image); //the output size of this filter is smaller than the of the input!! cyl2cart->SetTargetXSize( 64 ); //Use the same slice-selector again, this time to take a slice of the filtered image //which is smaller than the one of the old input!! slice->SetInput(cyl2cart->GetOutput()); slice->SetSliceNr(1); //The requested region is still the old one, //therefore the following results in most ITK versions //in an exception! slice->Update(); //If no exception occured, check that the requested region is now //the one of the smaller image if(cyl2cart->GetOutput()->GetLargestPossibleRegion().GetSize()[0]!=64) { std::cout<<"Part 1 [FAILED]"<GetOutput()->GetDimensions()[0]!=64) || (cyl2cart->GetOutput()->GetDimensions()[1]!=64)) { std::cout<<"Part 1b [FAILED]"<ResetPipeline(); } */ try { slice->UpdateLargestPossibleRegion(); } catch (const itk::ExceptionObject &) { std::cout << "Part 2 [FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "Part 2 [PASSED]" << std::endl; std::cout << "Testing IsInitialized(): "; if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; if (image->GetDimension(3) > 1) { int time = image->GetDimension(3) - 1; std::cout << "Testing 3D+t: Setting time to " << time << ": "; slice->SetTimeNr(time); if (slice->GetTimeNr() != time) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: Updating slice: "; slice->Update(); if (slice->GetOutput()->IsInitialized() == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: IsSliceSet(): "; if (slice->GetOutput()->IsSliceSet(0) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; std::cout << "Testing 3D+t: First slice in reader available: "; if (image->IsSliceSet(0, time) == false) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } std::cout << "[PASSED]" << std::endl; } std::cout << "[TEST DONE]" << std::endl; return EXIT_SUCCESS; } diff --git a/Modules/Core/test/mitkImageTest.cpp b/Modules/Core/test/mitkImageTest.cpp index f5b4215bcd..1a0186d048 100644 --- a/Modules/Core/test/mitkImageTest.cpp +++ b/Modules/Core/test/mitkImageTest.cpp @@ -1,556 +1,556 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 includes #include "mitkException.h" #include "mitkIOUtil.h" #include "mitkImageGenerator.h" #include "mitkImagePixelReadAccessor.h" #include "mitkImageReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include #include #include #include #include #include "mitkImageSliceSelector.h" // itk includes #include #include // stl includes #include // vtk includes #include // Checks if reference count is correct after using GetVtkImageData() bool ImageVtkDataReferenceCheck(const char *fname) { const std::string filename = std::string(fname); try { mitk::Image::Pointer image = mitk::IOUtil::Load(filename); MITK_TEST_CONDITION_REQUIRED(image.IsNotNull(), "Non-nullptr image") vtkImageData *vtk = image->GetVtkImageData(); if (vtk == nullptr) return false; } catch (...) { MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << filename); return false; } return true; } template void TestRandomPixelAccess(const mitk::PixelType /*ptype*/, mitk::Image::Pointer image, mitk::Point3D &point, mitk::ScalarType &value) { // generate a random point in world coordinates mitk::Point3D xMax, yMax, zMax, xMaxIndex, yMaxIndex, zMaxIndex; xMaxIndex.Fill(0.0f); yMaxIndex.Fill(0.0f); zMaxIndex.Fill(0.0f); xMaxIndex[0] = image->GetLargestPossibleRegion().GetSize()[0]; yMaxIndex[1] = image->GetLargestPossibleRegion().GetSize()[1]; zMaxIndex[2] = image->GetLargestPossibleRegion().GetSize()[2]; image->GetGeometry()->IndexToWorld(xMaxIndex, xMax); image->GetGeometry()->IndexToWorld(yMaxIndex, yMax); image->GetGeometry()->IndexToWorld(zMaxIndex, zMax); MITK_INFO << "Origin " << image->GetGeometry()->GetOrigin()[0] << " " << image->GetGeometry()->GetOrigin()[1] << " " << image->GetGeometry()->GetOrigin()[2] << ""; MITK_INFO << "MaxExtend " << xMax[0] << " " << yMax[1] << " " << zMax[2] << ""; itk::Statistics::MersenneTwisterRandomVariateGenerator::Pointer randomGenerator = itk::Statistics::MersenneTwisterRandomVariateGenerator::New(); randomGenerator->Initialize(std::rand()); // initialize with random value, to get sensible random points for the image point[0] = randomGenerator->GetUniformVariate(image->GetGeometry()->GetOrigin()[0], xMax[0]); point[1] = randomGenerator->GetUniformVariate(image->GetGeometry()->GetOrigin()[1], yMax[1]); point[2] = randomGenerator->GetUniformVariate(image->GetGeometry()->GetOrigin()[2], zMax[2]); MITK_INFO << "RandomPoint " << point[0] << " " << point[1] << " " << point[2] << ""; // test values and max/min mitk::ScalarType imageMin = image->GetStatistics()->GetScalarValueMin(); mitk::ScalarType imageMax = image->GetStatistics()->GetScalarValueMax(); // test accessing PixelValue with coordinate leading to a negative index const mitk::Point3D geom_origin = image->GetGeometry()->GetOrigin(); const mitk::Point3D geom_center = image->GetGeometry()->GetCenter(); // shift position from origin outside of the image ( in the opposite direction to [center-origin] vector which points // in the inside) mitk::Point3D position = geom_origin + (geom_origin - geom_center); MITK_INFO << "Testing access outside of the image"; unsigned int dim = image->GetDimension(); if (dim == 3 || dim == 4) { mitk::ImagePixelReadAccessor imAccess3(image, image->GetVolumeData(0)); // Comparison ?>=0 not needed since all position[i] and timestep are unsigned int // (position[0]>=0 && position[1] >=0 && position[2]>=0 && timestep>=0) // bug-11978 : we still need to catch index with negative values if (point[0] < 0 || point[1] < 0 || point[2] < 0) { MITK_WARN << "Given position (" << point << ") is out of image range, returning 0."; } else { value = static_cast(imAccess3.GetPixelByWorldCoordinates(point)); MITK_TEST_CONDITION((value >= imageMin && value <= imageMax), "Value returned is between max/min"); } itk::Index<3> itkIndex; image->GetGeometry()->WorldToIndex(position, itkIndex); MITK_TEST_FOR_EXCEPTION_BEGIN(mitk::Exception); imAccess3.GetPixelByIndexSafe(itkIndex); MITK_TEST_FOR_EXCEPTION_END(mitk::Exception); } MITK_INFO << imageMin << " " << imageMax << " " << value << ""; } class mitkImageTestClass { public: void SetClonedGeometry_None_ClonedEqualInput() { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateRandomImage(100, 100, 100, 1, 0.2, 0.3, 0.4); //----------------- // geometry information for image mitk::Point3D origin; mitk::Vector3D right, bottom; mitk::Vector3D spacing; mitk::FillVector3D(origin, 17.0, 19.92, 7.83); mitk::FillVector3D(right, 1.0, 2.0, 3.0); mitk::FillVector3D(bottom, 0.0, -3.0, 2.0); mitk::FillVector3D(spacing, 0.78, 0.91, 2.23); // InitializeStandardPlane(rightVector, downVector, spacing) mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(100, 100, right, bottom, &spacing); planegeometry->SetOrigin(origin); planegeometry->ChangeImageGeometryConsideringOriginOffset(true); image->SetClonedGeometry(planegeometry); mitk::BaseGeometry::Pointer imageGeometry = image->GetGeometry(); MITK_ASSERT_EQUAL(imageGeometry, planegeometry, "Matrix elements of cloned matrix equal original matrix"); } }; int mitkImageTest(int argc, char *argv[]) { MITK_TEST_BEGIN(mitkImageTest); mitkImageTestClass tester; tester.SetClonedGeometry_None_ClonedEqualInput(); // Create Image out of nowhere mitk::Image::Pointer imgMem = mitk::Image::New(); mitk::PixelType pt = mitk::MakeScalarPixelType(); unsigned int dim[] = {100, 100, 20}; MITK_TEST_CONDITION_REQUIRED(imgMem.IsNotNull(), "An image was created. "); // Initialize image imgMem->Initialize(pt, 3, dim); MITK_TEST_CONDITION_REQUIRED(imgMem->IsInitialized(), "Image::IsInitialized() ?"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetPixelType() == pt, "PixelType was set correctly."); int *p = nullptr; int *p2 = nullptr; try { mitk::ImageReadAccessor imgMemAcc(imgMem); p = (int *)imgMemAcc.GetData(); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } MITK_TEST_CONDITION(p != nullptr, "GetData() returned not-nullptr pointer."); // filling image const unsigned int size = dim[0] * dim[1] * dim[2]; for (unsigned int i = 0; i < size; ++i, ++p) *p = (signed int)i; // Getting it again and compare with filled values: try { mitk::ImageReadAccessor imgMemAcc(imgMem); p2 = (int *)imgMemAcc.GetData(); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } MITK_TEST_CONDITION(p2 != nullptr, "GetData() returned not-nullptr pointer."); bool isEqual = true; for (unsigned int i = 0; i < size; ++i, ++p2) { if (*p2 != (signed int)i) { isEqual = false; } } MITK_TEST_CONDITION(isEqual, "The values previously set as data are correct [pixelwise comparison]."); // Testing GetSliceData() and compare with filled values: try { mitk::ImageReadAccessor imgMemAcc(imgMem, imgMem->GetSliceData(dim[2] / 2)); p2 = (int *)imgMemAcc.GetData(); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } MITK_TEST_CONDITION_REQUIRED(p2 != nullptr, "Valid slice data returned"); unsigned int xy_size = dim[0] * dim[1]; unsigned int start_mid_slice = (dim[2] / 2) * xy_size; isEqual = true; for (unsigned int i = 0; i < xy_size; ++i, ++p2) { if (*p2 != (signed int)(i + start_mid_slice)) { isEqual = false; } } MITK_TEST_CONDITION(isEqual, "The SliceData are correct [pixelwise comparison]. "); imgMem = mitk::Image::New(); // testing re-initialization of test image mitk::PixelType pType = mitk::MakePixelType(); imgMem->Initialize(pType, 3, dim); MITK_TEST_CONDITION_REQUIRED(imgMem->GetDimension() == 3, "Testing initialization parameter dimension!"); MITK_TEST_CONDITION_REQUIRED(imgMem->GetPixelType() == pType, "Testing initialization parameter pixeltype!"); MITK_TEST_CONDITION_REQUIRED( imgMem->GetDimension(0) == dim[0] && imgMem->GetDimension(1) == dim[1] && imgMem->GetDimension(2) == dim[2], "Testing initialization of dimensions!"); MITK_TEST_CONDITION(imgMem->IsInitialized(), "Image is initialized."); // Setting volume again: try { mitk::ImageReadAccessor imgMemAcc(imgMem); imgMem->SetVolume(imgMemAcc.GetData()); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } //----------------- // geometry information for image mitk::Point3D origin; mitk::Vector3D right, bottom; mitk::Vector3D spacing; mitk::FillVector3D(origin, 17.0, 19.92, 7.83); mitk::FillVector3D(right, 1.0, 2.0, 3.0); mitk::FillVector3D(bottom, 0.0, -3.0, 2.0); mitk::FillVector3D(spacing, 0.78, 0.91, 2.23); // InitializeStandardPlane(rightVector, downVector, spacing) mitk::PlaneGeometry::Pointer planegeometry = mitk::PlaneGeometry::New(); planegeometry->InitializeStandardPlane(100, 100, right, bottom, &spacing); planegeometry->SetOrigin(origin); planegeometry->SetImageGeometry(true); // Testing Initialize(const mitk::PixelType& type, const mitk::Geometry3D& geometry, unsigned int slices) with // PlaneGeometry and GetData(): "; imgMem->Initialize(mitk::MakePixelType(), *planegeometry); MITK_TEST_CONDITION_REQUIRED( imgMem->GetGeometry()->GetOrigin() == static_cast(planegeometry)->GetOrigin(), "Testing correct setting of geometry via initialize!"); try { mitk::ImageReadAccessor imgMemAcc(imgMem); p = (int *)imgMemAcc.GetData(); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } MITK_TEST_CONDITION_REQUIRED(p != nullptr, "GetData() returned valid pointer."); // Testing Initialize(const mitk::PixelType& type, int sDim, const mitk::PlaneGeometry& geometry) and GetData(): "; imgMem->Initialize(mitk::MakePixelType(), 40, *planegeometry); try { mitk::ImageReadAccessor imgMemAcc(imgMem); p = (int *)imgMemAcc.GetData(); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } MITK_TEST_CONDITION_REQUIRED(p != nullptr, "GetData() returned valid pointer."); //----------------- // testing origin information and methods MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin), "Testing correctness of origin via GetGeometry()->GetOrigin(): "); // Setting origin via SetOrigin(origin): "; mitk::FillVector3D(origin, 37.0, 17.92, 27.83); imgMem->SetOrigin(origin); // Test origin MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetGeometry()->GetOrigin(), origin), "Testing correctness of changed origin via GetGeometry()->GetOrigin(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetSlicedGeometry()->GetPlaneGeometry(0)->GetOrigin(), origin), "Testing correctness of changed origin via GetSlicedGeometry()->GetPlaneGeometry(0)->GetOrigin(): "); //----------------- // testing spacing information and methodsunsigned int dim[]={100,100,20}; MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing), "Testing correct spacing from Geometry3D!"); mitk::FillVector3D(spacing, 7.0, 0.92, 1.83); imgMem->SetSpacing(spacing); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(imgMem->GetGeometry()->GetSpacing(), spacing), "Testing correctness of changed spacing via GetGeometry()->GetSpacing(): "); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(imgMem->GetSlicedGeometry()->GetPlaneGeometry(0)->GetSpacing(), spacing), "Testing correctness of changed spacing via GetSlicedGeometry()->GetPlaneGeometry(0)->GetSpacing(): "); mitk::Image::Pointer vecImg = mitk::Image::New(); try { mitk::ImageReadAccessor imgMemAcc(imgMem); vecImg->Initialize(imgMem->GetPixelType(), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/); vecImg->SetImportChannel(const_cast(imgMemAcc.GetData()), 0, mitk::Image::CopyMemory); vecImg->SetImportChannel(const_cast(imgMemAcc.GetData()), 1, mitk::Image::CopyMemory); mitk::ImageReadAccessor vecImgAcc(vecImg); mitk::ImageReadAccessor vecImgAcc0(vecImg, vecImg->GetChannelData(0)); mitk::ImageReadAccessor vecImgAcc1(vecImg, vecImg->GetChannelData(1)); MITK_TEST_CONDITION_REQUIRED(vecImgAcc0.GetData() != nullptr && vecImgAcc1.GetData() != nullptr, "Testing set and return of channel data!"); MITK_TEST_CONDITION_REQUIRED(vecImg->IsValidSlice(0, 0, 1), ""); MITK_TEST_OUTPUT(<< " Testing whether CopyMemory worked"); MITK_TEST_CONDITION_REQUIRED(imgMemAcc.GetData() != vecImgAcc.GetData(), ""); MITK_TEST_OUTPUT(<< " Testing destruction after SetImportChannel"); vecImg = nullptr; MITK_TEST_CONDITION_REQUIRED(vecImg.IsNull(), "testing destruction!"); } - catch (mitk::Exception &e) + catch ( const mitk::Exception &e ) { MITK_ERROR << e.what(); } //----------------- MITK_TEST_OUTPUT(<< "Testing initialization via vtkImageData"); MITK_TEST_OUTPUT(<< " Setting up vtkImageData"); vtkImageData *vtkimage = vtkImageData::New(); vtkimage->Initialize(); vtkimage->SetDimensions(2, 3, 4); double vtkorigin[] = {-350, -358.203, -1363.5}; vtkimage->SetOrigin(vtkorigin); mitk::Point3D vtkoriginAsMitkPoint; mitk::vtk2itk(vtkorigin, vtkoriginAsMitkPoint); double vtkspacing[] = {1.367, 1.367, 2}; vtkimage->SetSpacing(vtkspacing); vtkimage->AllocateScalars(VTK_SHORT, 1); std::cout << "[PASSED]" << std::endl; MITK_TEST_OUTPUT(<< " Testing mitk::Image::Initialize(vtkImageData*, ...)"); mitk::Image::Pointer mitkByVtkImage = mitk::Image::New(); mitkByVtkImage->Initialize(vtkimage); MITK_TEST_CONDITION_REQUIRED(mitkByVtkImage->IsInitialized(), ""); vtkimage->Delete(); MITK_TEST_OUTPUT(<< " Testing whether spacing has been correctly initialized from vtkImageData"); mitk::Vector3D spacing2 = mitkByVtkImage->GetGeometry()->GetSpacing(); mitk::Vector3D vtkspacingAsMitkVector; mitk::vtk2itk(vtkspacing, vtkspacingAsMitkVector); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(spacing2, vtkspacingAsMitkVector), ""); MITK_TEST_OUTPUT( << " Testing whether GetSlicedGeometry(0)->GetOrigin() has been correctly initialized from vtkImageData"); mitk::Point3D origin2 = mitkByVtkImage->GetSlicedGeometry(0)->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2, vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing whether GetGeometry()->GetOrigin() has been correctly initialized from vtkImageData"); origin2 = mitkByVtkImage->GetGeometry()->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(origin2, vtkoriginAsMitkPoint), ""); MITK_TEST_OUTPUT(<< " Testing if vtkOrigin is (0, 0, 0). This behaviour is due to historical development of MITK. " "Aslo see bug 5050!"); vtkImageData *vtkImage = imgMem->GetVtkImageData(); auto vtkOrigin = vtkImage->GetOrigin(); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(vtkOrigin[0], 0), "testing vtkOrigin[0] to be 0"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(vtkOrigin[1], 0), "testing vtkOrigin[1] to be 0"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(vtkOrigin[2], 0), "testing vtkOrigin[2] to be 0"); // TODO test the following initializers on channel-incorporation // void mitk::Image::Initialize(const mitk::PixelType& type, unsigned int dimension, unsigned int *dimensions, // unsigned int channels) // void mitk::Image::Initialize(const mitk::PixelType& type, int sDim, const mitk::PlaneGeometry& geometry2d, bool // flipped, unsigned int channels, int tDim ) // void mitk::Image::Initialize(const mitk::Image* image) // void mitk::Image::Initialize(const mitkIpPicDescriptor* pic, int channels, int tDim, int sDim) // mitk::Image::Pointer vecImg = mitk::Image::New(); // vecImg->Initialize(PixelType(typeid(float), 6, itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR), // *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, false /*shiftBoundingBoxMinimumToZero*/ ); // vecImg->Initialize(PixelType(typeid(itk::Vector)), *imgMem->GetGeometry(), 2 /* #channels */, 0 /*tDim*/, // false /*shiftBoundingBoxMinimumToZero*/ ); // testing access by index coordinates and by world coordinates MITK_TEST_CONDITION_REQUIRED(argc == 2, "Check if test image is accessible!"); const std::string filename = std::string(argv[1]); mitk::Image::Pointer image; try { image = mitk::IOUtil::Load(filename); MITK_TEST_CONDITION_REQUIRED(image.IsNotNull(), "Non-nullptr image") } catch (...) { MITK_TEST_FAILED_MSG(<< "Could not read file for testing: " << filename); return 0; } mitk::Point3D point; mitk::ScalarType value = -1.; mitkPixelTypeMultiplex3( TestRandomPixelAccess, image->GetImageDescriptor()->GetChannelTypeById(0), image, point, value) { // testing the clone method of mitk::Image mitk::Image::Pointer cloneImage = image->Clone(); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension() == image->GetDimension(), "Clone (testing dimension)"); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetPixelType() == image->GetPixelType(), "Clone (testing pixel type)"); // After cloning an image the geometry of both images should be equal too MITK_TEST_CONDITION_REQUIRED(cloneImage->GetGeometry()->GetOrigin() == image->GetGeometry()->GetOrigin(), "Clone (testing origin)"); MITK_TEST_CONDITION_REQUIRED(cloneImage->GetGeometry()->GetSpacing() == image->GetGeometry()->GetSpacing(), "Clone (testing spacing)"); MITK_TEST_CONDITION_REQUIRED( mitk::MatrixEqualElementWise(cloneImage->GetGeometry()->GetIndexToWorldTransform()->GetMatrix(), image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix()), "Clone (testing transformation matrix)"); MITK_TEST_CONDITION_REQUIRED( mitk::MatrixEqualElementWise(cloneImage->GetTimeGeometry() ->GetGeometryForTimeStep(cloneImage->GetDimension(3) - 1) ->GetIndexToWorldTransform() ->GetMatrix(), cloneImage->GetTimeGeometry() ->GetGeometryForTimeStep(image->GetDimension(3) - 1) ->GetIndexToWorldTransform() ->GetMatrix()), "Clone(testing time sliced geometry)"); for (unsigned int i = 0u; i < cloneImage->GetDimension(); ++i) { MITK_TEST_CONDITION_REQUIRED(cloneImage->GetDimension(i) == image->GetDimension(i), "Clone (testing dimension " << i << ")"); } } // access via itk if (image->GetDimension() > 3) // CastToItk only works with 3d images so we need to check for 4d images { mitk::ImageTimeSelector::Pointer selector = mitk::ImageTimeSelector::New(); selector->SetTimeNr(0); selector->SetInput(image); selector->Update(); image = selector->GetOutput(); } if (image->GetDimension() == 3) { typedef itk::Image ItkFloatImage3D; ItkFloatImage3D::Pointer itkimage; try { mitk::CastToItkImage(image, itkimage); MITK_TEST_CONDITION_REQUIRED(itkimage.IsNotNull(), "Test conversion to itk::Image!"); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_INFO << e.what(); } mitk::Point3D itkPhysicalPoint; image->GetGeometry()->WorldToItkPhysicalPoint(point, itkPhysicalPoint); MITK_INFO << "ITKPoint " << itkPhysicalPoint[0] << " " << itkPhysicalPoint[1] << " " << itkPhysicalPoint[2] << ""; mitk::Point3D backTransformedPoint; image->GetGeometry()->ItkPhysicalPointToWorld(itkPhysicalPoint, backTransformedPoint); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(point, backTransformedPoint), "Testing world->itk-physical->world consistency"); itk::Index<3> idx; bool status = itkimage->TransformPhysicalPointToIndex(itkPhysicalPoint, idx); MITK_INFO << "ITK Index " << idx[0] << " " << idx[1] << " " << idx[2] << ""; if (status && value != -1.) { float valByItk = itkimage->GetPixel(idx); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(valByItk, value), "Compare value of pixel returned by mitk in comparison to itk"); } else { MITK_WARN << "Index is out buffered region!"; } } else { MITK_INFO << "Image does not contain three dimensions, some test cases are skipped!"; } // clone generated 3D image with one slice in z direction (cf. bug 11058) auto *threeDdim = new unsigned int[3]; threeDdim[0] = 100; threeDdim[1] = 200; threeDdim[2] = 1; mitk::Image::Pointer threeDImage = mitk::Image::New(); threeDImage->Initialize(mitk::MakeScalarPixelType(), 3, threeDdim); mitk::Image::Pointer cloneThreeDImage = threeDImage->Clone(); // check that the clone image has the same dimensionality as the source image MITK_TEST_CONDITION_REQUIRED(cloneThreeDImage->GetDimension() == 3, "Testing if the clone image initializes with 3D!"); MITK_TEST_CONDITION_REQUIRED(ImageVtkDataReferenceCheck(argv[1]), "Checking reference count of Image after using GetVtkImageData()"); MITK_TEST_END(); } diff --git a/Modules/DICOMReader/src/legacy/mitkDicomSeriesReader.cpp b/Modules/DICOMReader/src/legacy/mitkDicomSeriesReader.cpp index 7d7d94a7f8..2ac53e24f0 100644 --- a/Modules/DICOMReader/src/legacy/mitkDicomSeriesReader.cpp +++ b/Modules/DICOMReader/src/legacy/mitkDicomSeriesReader.cpp @@ -1,1864 +1,1864 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // uncomment for learning more about the internal sorting mechanisms //#define MBILOG_ENABLE_DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkProperties.h" namespace mitk { std::string DicomSeriesReader::ReaderImplementationLevelToString(const ReaderImplementationLevel &enumValue) { switch (enumValue) { case ReaderImplementationLevel_Supported: return "Supported"; case ReaderImplementationLevel_PartlySupported: return "PartlySupported"; case ReaderImplementationLevel_Implemented: return "Implemented"; case ReaderImplementationLevel_Unsupported: return "Unsupported"; default: return ""; }; } std::string DicomSeriesReader::PixelSpacingInterpretationToString(const PixelSpacingInterpretation &enumValue) { switch (enumValue) { case PixelSpacingInterpretation_SpacingInPatient: return "In Patient"; case PixelSpacingInterpretation_SpacingAtDetector: return "At Detector"; case PixelSpacingInterpretation_SpacingUnknown: return "Unknown spacing"; default: return ""; }; } const DicomSeriesReader::TagToPropertyMapType &DicomSeriesReader::GetDICOMTagsToMITKPropertyMap() { static bool initialized = false; static TagToPropertyMapType dictionary; if (!initialized) { /* Selection criteria: - no sequences because we cannot represent that - nothing animal related (specied, breed registration number), MITK focusses on human medical image processing. - only general attributes so far When extending this, we should make use of a real dictionary (GDCM/DCMTK and lookup the tag names there) */ // Patient module dictionary["0010|0010"] = "dicom.patient.PatientsName"; dictionary["0010|0020"] = "dicom.patient.PatientID"; dictionary["0010|0030"] = "dicom.patient.PatientsBirthDate"; dictionary["0010|0040"] = "dicom.patient.PatientsSex"; dictionary["0010|0032"] = "dicom.patient.PatientsBirthTime"; dictionary["0010|1000"] = "dicom.patient.OtherPatientIDs"; dictionary["0010|1001"] = "dicom.patient.OtherPatientNames"; dictionary["0010|2160"] = "dicom.patient.EthnicGroup"; dictionary["0010|4000"] = "dicom.patient.PatientComments"; dictionary["0012|0062"] = "dicom.patient.PatientIdentityRemoved"; dictionary["0012|0063"] = "dicom.patient.DeIdentificationMethod"; // General Study module dictionary["0020|000d"] = "dicom.study.StudyInstanceUID"; dictionary["0008|0020"] = "dicom.study.StudyDate"; dictionary["0008|0030"] = "dicom.study.StudyTime"; dictionary["0008|0090"] = "dicom.study.ReferringPhysiciansName"; dictionary["0020|0010"] = "dicom.study.StudyID"; dictionary["0008|0050"] = "dicom.study.AccessionNumber"; dictionary["0008|1030"] = "dicom.study.StudyDescription"; dictionary["0008|1048"] = "dicom.study.PhysiciansOfRecord"; dictionary["0008|1060"] = "dicom.study.NameOfPhysicianReadingStudy"; // General Series module dictionary["0008|0060"] = "dicom.series.Modality"; dictionary["0020|000e"] = "dicom.series.SeriesInstanceUID"; dictionary["0020|0011"] = "dicom.series.SeriesNumber"; dictionary["0020|0060"] = "dicom.series.Laterality"; dictionary["0008|0021"] = "dicom.series.SeriesDate"; dictionary["0008|0031"] = "dicom.series.SeriesTime"; dictionary["0008|1050"] = "dicom.series.PerformingPhysiciansName"; dictionary["0018|1030"] = "dicom.series.ProtocolName"; dictionary["0008|103e"] = "dicom.series.SeriesDescription"; dictionary["0008|1070"] = "dicom.series.OperatorsName"; dictionary["0018|0015"] = "dicom.series.BodyPartExamined"; dictionary["0018|5100"] = "dicom.series.PatientPosition"; dictionary["0028|0108"] = "dicom.series.SmallestPixelValueInSeries"; dictionary["0028|0109"] = "dicom.series.LargestPixelValueInSeries"; // VOI LUT module dictionary["0028|1050"] = "dicom.voilut.WindowCenter"; dictionary["0028|1051"] = "dicom.voilut.WindowWidth"; dictionary["0028|1055"] = "dicom.voilut.WindowCenterAndWidthExplanation"; // Image Pixel module dictionary["0028|0004"] = "dicom.pixel.PhotometricInterpretation"; dictionary["0028|0010"] = "dicom.pixel.Rows"; dictionary["0028|0011"] = "dicom.pixel.Columns"; // Image Plane module dictionary["0028|0030"] = "dicom.PixelSpacing"; dictionary["0018|1164"] = "dicom.ImagerPixelSpacing"; // Misc dictionary["0008|0005"] = "dicom.SpecificCharacterSet"; initialized = true; } return dictionary; } DataNode::Pointer DicomSeriesReader::LoadDicomSeries(const StringContainer &filenames, bool sort, bool check_4d, bool correctTilt, UpdateCallBackMethod callback, Image::Pointer preLoadedImageBlock) { DataNode::Pointer node = DataNode::New(); if (DicomSeriesReader::LoadDicomSeries( filenames, *node, sort, check_4d, correctTilt, callback, preLoadedImageBlock)) { if (filenames.empty()) { return nullptr; } return node; } else { return nullptr; } } bool DicomSeriesReader::LoadDicomSeries(const StringContainer &filenames, DataNode &node, bool sort, bool check_4d, bool correctTilt, UpdateCallBackMethod callback, itk::SmartPointer preLoadedImageBlock) { if (filenames.empty()) { MITK_DEBUG << "Calling LoadDicomSeries with empty filename string container. Probably invalid application logic."; node.SetData(nullptr); return true; // this is not actually an error but the result is very simple } DcmIoType::Pointer io = DcmIoType::New(); try { if (io->CanReadFile(filenames.front().c_str())) { io->SetFileName(filenames.front().c_str()); io->ReadImageInformation(); if (io->GetPixelType() == itk::ImageIOBase::SCALAR || io->GetPixelType() == itk::ImageIOBase::RGB) { LoadDicom(filenames, node, sort, check_4d, correctTilt, callback, preLoadedImageBlock); } if (node.GetData()) { return true; } } } - catch (itk::MemoryAllocationError &e) + catch ( const itk::MemoryAllocationError &e ) { MITK_ERROR << "Out of memory. Cannot load DICOM series: " << e.what(); } - catch (std::exception &e) + catch ( const std::exception &e ) { MITK_ERROR << "Error encountered when loading DICOM series:" << e.what(); } catch (...) { MITK_ERROR << "Unspecified error encountered when loading DICOM series."; } return false; } bool DicomSeriesReader::IsDicom(const std::string &filename) { DcmIoType::Pointer io = DcmIoType::New(); return io->CanReadFile(filename.c_str()); } bool DicomSeriesReader::IsPhilips3DDicom(const std::string &filename) { DcmIoType::Pointer io = DcmIoType::New(); if (io->CanReadFile(filename.c_str())) { // Look at header Tag 3001,0010 if it is "Philips3D" gdcm::Reader reader; reader.SetFileName(filename.c_str()); reader.Read(); gdcm::DataSet &data_set = reader.GetFile().GetDataSet(); gdcm::StringFilter sf; sf.SetFile(reader.GetFile()); if (data_set.FindDataElement(gdcm::Tag(0x3001, 0x0010)) && (sf.ToString(gdcm::Tag(0x3001, 0x0010)) == "Philips3D ")) { return true; } } return false; } bool DicomSeriesReader::ReadPhilips3DDicom(const std::string &filename, itk::SmartPointer output_image) { // Now get PhilipsSpecific Tags gdcm::PixmapReader reader; reader.SetFileName(filename.c_str()); reader.Read(); gdcm::DataSet &data_set = reader.GetFile().GetDataSet(); gdcm::StringFilter sf; sf.SetFile(reader.GetFile()); gdcm::Attribute<0x0028, 0x0011> dimTagX; // coloumns || sagittal gdcm::Attribute<0x3001, 0x1001, gdcm::VR::UL, gdcm::VM::VM1> dimTagZ; // I have no idea what is VM1. // (Philips specific) // axial gdcm::Attribute<0x0028, 0x0010> dimTagY; // rows || coronal gdcm::Attribute<0x0028, 0x0008> dimTagT; // how many frames gdcm::Attribute<0x0018, 0x602c> spaceTagX; // Spacing in X , unit is "physicalTagx" (usually centimeter) gdcm::Attribute<0x0018, 0x602e> spaceTagY; gdcm::Attribute<0x3001, 0x1003, gdcm::VR::FD, gdcm::VM::VM1> spaceTagZ; // (Philips specific) gdcm::Attribute<0x0018, 0x6024> physicalTagX; // if 3, then spacing params are centimeter gdcm::Attribute<0x0018, 0x6026> physicalTagY; gdcm::Attribute<0x3001, 0x1002, gdcm::VR::US, gdcm::VM::VM1> physicalTagZ; // (Philips specific) dimTagX.Set(data_set); dimTagY.Set(data_set); dimTagZ.Set(data_set); dimTagT.Set(data_set); spaceTagX.Set(data_set); spaceTagY.Set(data_set); spaceTagZ.Set(data_set); physicalTagX.Set(data_set); physicalTagY.Set(data_set); physicalTagZ.Set(data_set); unsigned int dimX = dimTagX.GetValue(), dimY = dimTagY.GetValue(), dimZ = dimTagZ.GetValue(), dimT = dimTagT.GetValue(), physicalX = physicalTagX.GetValue(), physicalY = physicalTagY.GetValue(), physicalZ = physicalTagZ.GetValue(); float spaceX = spaceTagX.GetValue(), spaceY = spaceTagY.GetValue(), spaceZ = spaceTagZ.GetValue(); if (physicalX == 3) // spacing parameter in cm, have to convert it to mm. spaceX = spaceX * 10; if (physicalY == 3) // spacing parameter in cm, have to convert it to mm. spaceY = spaceY * 10; if (physicalZ == 3) // spacing parameter in cm, have to convert it to mm. spaceZ = spaceZ * 10; // Ok, got all necessary Tags! // Now read Pixeldata (7fe0,0010) X x Y x Z x T Elements const gdcm::Pixmap &pixels = reader.GetPixmap(); gdcm::RAWCodec codec; codec.SetPhotometricInterpretation(gdcm::PhotometricInterpretation::MONOCHROME2); codec.SetPixelFormat(pixels.GetPixelFormat()); codec.SetPlanarConfiguration(0); gdcm::DataElement out; codec.Decode(data_set.GetDataElement(gdcm::Tag(0x7fe0, 0x0010)), out); const gdcm::ByteValue *bv = out.GetByteValue(); const char *new_pixels = bv->GetPointer(); // Create MITK Image + Geometry typedef itk::Image ImageType; // Pixeltype might be different sometimes? Maybe read it out from header ImageType::RegionType myRegion; ImageType::SizeType mySize; ImageType::IndexType myIndex; ImageType::SpacingType mySpacing; ImageType::Pointer imageItk = ImageType::New(); mySpacing[0] = spaceX; mySpacing[1] = spaceY; mySpacing[2] = spaceZ; mySpacing[3] = 1; myIndex[0] = 0; myIndex[1] = 0; myIndex[2] = 0; myIndex[3] = 0; mySize[0] = dimX; mySize[1] = dimY; mySize[2] = dimZ; mySize[3] = dimT; myRegion.SetSize(mySize); myRegion.SetIndex(myIndex); imageItk->SetSpacing(mySpacing); imageItk->SetRegions(myRegion); imageItk->Allocate(); imageItk->FillBuffer(0); itk::ImageRegionIterator iterator(imageItk, imageItk->GetLargestPossibleRegion()); iterator.GoToBegin(); unsigned long pixCount = 0; unsigned long planeSize = dimX * dimY; unsigned long planeCount = 0; unsigned long timeCount = 0; unsigned long numberOfSlices = dimZ; while (!iterator.IsAtEnd()) { unsigned long adressedPixel = pixCount + (numberOfSlices - 1 - planeCount) * planeSize // add offset to adress the first pixel of current plane + timeCount * numberOfSlices * planeSize; // add time offset iterator.Set(new_pixels[adressedPixel]); pixCount++; ++iterator; if (pixCount == planeSize) { pixCount = 0; planeCount++; } if (planeCount == numberOfSlices) { planeCount = 0; timeCount++; } if (timeCount == dimT) { break; } } mitk::CastToMitkImage(imageItk, output_image); return true; // actually never returns false yet.. but exception possible } std::string DicomSeriesReader::ConstCharStarToString(const char *s) { return s ? std::string(s) : std::string(); } bool DicomSeriesReader::DICOMStringToSpacing(const std::string &s, ScalarType &spacingX, ScalarType &spacingY) { bool successful = false; std::istringstream spacingReader(s); std::string spacing; if (std::getline(spacingReader, spacing, '\\')) { spacingY = atof(spacing.c_str()); if (std::getline(spacingReader, spacing, '\\')) { spacingX = atof(spacing.c_str()); successful = true; } } return successful; } Point3D DicomSeriesReader::DICOMStringToPoint3D(const std::string &s, bool &successful) { Point3D p; successful = true; std::istringstream originReader(s); std::string coordinate; unsigned int dim(0); while (std::getline(originReader, coordinate, '\\') && dim < 3) { p[dim++] = atof(coordinate.c_str()); } if (dim && dim != 3) { successful = false; MITK_ERROR << "Reader implementation made wrong assumption on tag (0020,0032). Found " << dim << " instead of 3 values."; } else if (dim == 0) { successful = false; p.Fill(0.0); // assume default (0,0,0) } return p; } void DicomSeriesReader::DICOMStringToOrientationVectors(const std::string &s, Vector3D &right, Vector3D &up, bool &successful) { successful = true; std::istringstream orientationReader(s); std::string coordinate; unsigned int dim(0); while (std::getline(orientationReader, coordinate, '\\') && dim < 6) { if (dim < 3) { right[dim++] = atof(coordinate.c_str()); } else { up[dim++ - 3] = atof(coordinate.c_str()); } } if (dim && dim != 6) { successful = false; MITK_ERROR << "Reader implementation made wrong assumption on tag (0020,0037). Found " << dim << " instead of 6 values."; } else if (dim == 0) { // fill with defaults right.Fill(0.0); right[0] = 1.0; up.Fill(0.0); up[1] = 1.0; successful = false; } } DicomSeriesReader::SliceGroupingAnalysisResult DicomSeriesReader::AnalyzeFileForITKImageSeriesReaderSpacingAssumption( const StringContainer &files, bool groupImagesWithGantryTilt, const gdcm::Scanner::MappingType &tagValueMappings_) { // result.first = files that fit ITK's assumption // result.second = files that do not fit, should be run through // AnalyzeFileForITKImageSeriesReaderSpacingAssumption() // again SliceGroupingAnalysisResult result; // we const_cast here, because I could not use a map.at(), which would make the code much more readable auto &tagValueMappings = const_cast(tagValueMappings_); const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image Position (Patient) const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image Orientation const gdcm::Tag tagGantryTilt(0x0018, 0x1120); // gantry tilt Vector3D fromFirstToSecondOrigin; fromFirstToSecondOrigin.Fill(0.0); bool fromFirstToSecondOriginInitialized(false); Point3D thisOrigin; thisOrigin.Fill(0.0f); Point3D lastOrigin; lastOrigin.Fill(0.0f); Point3D lastDifferentOrigin; lastDifferentOrigin.Fill(0.0f); bool lastOriginInitialized(false); MITK_DEBUG << "--------------------------------------------------------------------------------"; MITK_DEBUG << "Analyzing files for z-spacing assumption of ITK's ImageSeriesReader (group tilted: " << groupImagesWithGantryTilt << ")"; unsigned int fileIndex(0); for (auto fileIter = files.begin(); fileIter != files.end(); ++fileIter, ++fileIndex) { bool fileFitsIntoPattern(false); std::string thisOriginString; // Read tag value into point3D. PLEASE replace this by appropriate GDCM code if you figure out how to do that thisOriginString = ConstCharStarToString(tagValueMappings[fileIter->c_str()][tagImagePositionPatient]); if (thisOriginString.empty()) { // don't let such files be in a common group. Everything without position information will be loaded as a single // slice: // with standard DICOM files this can happen to: CR, DX, SC MITK_DEBUG << " ==> Sort away " << *fileIter << " for later analysis (no position information)"; // we already have one occupying this position if (result.GetBlockFilenames().empty()) // nothing WITH position information yet { // ==> this is a group of its own, stop processing, come back later result.AddFileToSortedBlock(*fileIter); StringContainer remainingFiles; remainingFiles.insert(remainingFiles.end(), fileIter + 1, files.end()); result.AddFilesToUnsortedBlock(remainingFiles); fileFitsIntoPattern = false; break; // no files anymore } else { // ==> this does not match, consider later result.AddFileToUnsortedBlock(*fileIter); fileFitsIntoPattern = false; continue; // next file } } bool ignoredConversionError(-42); // hard to get here, no graceful way to react thisOrigin = DICOMStringToPoint3D(thisOriginString, ignoredConversionError); MITK_DEBUG << " " << fileIndex << " " << *fileIter << " at " /* << thisOriginString */ << "(" << thisOrigin[0] << "," << thisOrigin[1] << "," << thisOrigin[2] << ")"; if (lastOriginInitialized && (thisOrigin == lastOrigin)) { MITK_DEBUG << " ==> Sort away " << *fileIter << " for separate time step"; // we already have one occupying this position result.AddFileToUnsortedBlock(*fileIter); fileFitsIntoPattern = false; } else { if (!fromFirstToSecondOriginInitialized && lastOriginInitialized) // calculate vector as soon as possible when we get a new position { fromFirstToSecondOrigin = thisOrigin - lastDifferentOrigin; fromFirstToSecondOriginInitialized = true; // Here we calculate if this slice and the previous one are well aligned, // i.e. we test if the previous origin is on a line through the current // origin, directed into the normal direction of the current slice. // If this is NOT the case, then we have a data set with a TILTED GANTRY geometry, // which cannot be simply loaded into a single mitk::Image at the moment. // For this case, we flag this finding in the result and DicomSeriesReader // can correct for that later. Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); // might be down as well, but it is just a name at this point DICOMStringToOrientationVectors( tagValueMappings[fileIter->c_str()][tagImageOrientation], right, up, ignoredConversionError); GantryTiltInformation tiltInfo(lastDifferentOrigin, thisOrigin, right, up, 1); if (tiltInfo.IsSheared()) // mitk::eps is too small; 1/1000 of a mm should be enough to detect tilt { /* optimistic approach, accepting gantry tilt: save file for later, check all further files */ // at this point we have TWO slices analyzed! if they are the only two files, we still split, because there // is // no third to verify our tilting assumption. // later with a third being available, we must check if the initial tilting vector is still valid. if yes, // continue. // if NO, we need to split the already sorted part (result.first) and the currently analyzed file // (*fileIter) // tell apart gantry tilt from overall skewedness // sort out irregularly sheared slices, that IS NOT tilting if (groupImagesWithGantryTilt && tiltInfo.IsRegularGantryTilt()) { // check if this is at least roughly the same angle as recorded in DICOM tags if (tagValueMappings[fileIter->c_str()].find(tagGantryTilt) != tagValueMappings[fileIter->c_str()].end()) { // read value, compare to calculated angle std::string tiltStr = ConstCharStarToString(tagValueMappings[fileIter->c_str()][tagGantryTilt]); double angle = atof(tiltStr.c_str()); MITK_DEBUG << "Comparing recorded tilt angle " << angle << " against calculated value " << tiltInfo.GetTiltAngleInDegrees(); // TODO we probably want the signs correct, too (that depends: this is just a rough check, nothing // serious) // TODO TODO TODO when angle -27 and tiltangle 63, this will never trigger the if-clause... useless // check // in this case! old bug..?! if (fabs(angle) - tiltInfo.GetTiltAngleInDegrees() > 0.25) { result.AddFileToUnsortedBlock(*fileIter); // sort away for further analysis fileFitsIntoPattern = false; } else // tilt angle from header is less than 0.25 degrees different from what we calculated, assume this // is // fine { result.FlagGantryTilt(); result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else // we cannot check the calculated tilt angle against the one from the dicom header (so we assume we // are // right) { result.FlagGantryTilt(); result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else // caller does not want tilt compensation OR shearing is more complicated than tilt { result.AddFileToUnsortedBlock(*fileIter); // sort away for further analysis fileFitsIntoPattern = false; } } else // not sheared { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else if (fromFirstToSecondOriginInitialized) // we already know the offset between slices { Point3D assumedOrigin = lastDifferentOrigin + fromFirstToSecondOrigin; Vector3D originError = assumedOrigin - thisOrigin; double norm = originError.GetNorm(); double toleratedError(0.005); // max. 1/10mm error when measurement crosses 20 slices in z direction if (norm > toleratedError) { MITK_DEBUG << " File does not fit into the inter-slice distance pattern (diff = " << norm << ", allowed " << toleratedError << ")."; MITK_DEBUG << " Expected position (" << assumedOrigin[0] << "," << assumedOrigin[1] << "," << assumedOrigin[2] << "), got position (" << thisOrigin[0] << "," << thisOrigin[1] << "," << thisOrigin[2] << ")"; MITK_DEBUG << " ==> Sort away " << *fileIter << " for later analysis"; // At this point we know we deviated from the expectation of ITK's ImageSeriesReader // We split the input file list at this point, i.e. all files up to this one (excluding it) // are returned as group 1, the remaining files (including the faulty one) are group 2 /* Optimistic approach: check if any of the remaining slices fits in */ result.AddFileToUnsortedBlock(*fileIter); // sort away for further analysis fileFitsIntoPattern = false; } else { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } else // this should be the very first slice { result.AddFileToSortedBlock(*fileIter); // this file is good for current block fileFitsIntoPattern = true; } } // record current origin for reference in later iterations if (!lastOriginInitialized || (fileFitsIntoPattern && (thisOrigin != lastOrigin))) { lastDifferentOrigin = thisOrigin; } lastOrigin = thisOrigin; lastOriginInitialized = true; } if (result.ContainsGantryTilt()) { // check here how many files were grouped. // IF it was only two files AND we assume tiltedness (e.g. save "distance") // THEN we would want to also split the two previous files (simple) because // we don't have any reason to assume they belong together if (result.GetBlockFilenames().size() == 2) { result.UndoPrematureGrouping(); } } return result; } DicomSeriesReader::FileNamesGrouping DicomSeriesReader::GetSeries(const StringContainer &files, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { return GetSeries(files, true, groupImagesWithGantryTilt, restrictions); } DicomSeriesReader::FileNamesGrouping DicomSeriesReader::GetSeries(const StringContainer &files, bool sortTo3DPlust, bool groupImagesWithGantryTilt, const StringContainer & /*restrictions*/) { /** assumption about this method: returns a map of uid-like-key --> list(filename) each entry should contain filenames that have images of same - series instance uid (automatically done by GDCMSeriesFileNames - 0020,0037 image orientation (patient) - 0028,0030 pixel spacing (x,y) - 0018,0050 slice thickness */ // use GDCM directly, itk::GDCMSeriesFileNames does not work with GDCM 2 // PART I: scan files for sorting relevant DICOM tags, // separate images that differ in any of those // attributes (they cannot possibly form a 3D block) // scan for relevant tags in dicom files gdcm::Scanner scanner; const gdcm::Tag tagSOPClassUID(0x0008, 0x0016); // SOP class UID scanner.AddTag(tagSOPClassUID); const gdcm::Tag tagSeriesInstanceUID(0x0020, 0x000e); // Series Instance UID scanner.AddTag(tagSeriesInstanceUID); const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // image orientation scanner.AddTag(tagImageOrientation); const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // pixel spacing scanner.AddTag(tagPixelSpacing); const gdcm::Tag tagImagerPixelSpacing(0x0018, 0x1164); // imager pixel spacing scanner.AddTag(tagImagerPixelSpacing); const gdcm::Tag tagSliceThickness(0x0018, 0x0050); // slice thickness scanner.AddTag(tagSliceThickness); const gdcm::Tag tagNumberOfRows(0x0028, 0x0010); // number rows scanner.AddTag(tagNumberOfRows); const gdcm::Tag tagNumberOfColumns(0x0028, 0x0011); // number cols scanner.AddTag(tagNumberOfColumns); const gdcm::Tag tagGantryTilt(0x0018, 0x1120); // gantry tilt scanner.AddTag(tagGantryTilt); const gdcm::Tag tagModality(0x0008, 0x0060); // modality scanner.AddTag(tagModality); const gdcm::Tag tagNumberOfFrames(0x0028, 0x0008); // number of frames scanner.AddTag(tagNumberOfFrames); // additional tags read in this scan to allow later analysis // THESE tag are not used for initial separating of files const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image Position (Patient) scanner.AddTag(tagImagePositionPatient); // TODO add further restrictions from arguments (when anybody asks for it) FileNamesGrouping result; // let GDCM scan files if (!scanner.Scan(files)) { MITK_ERROR << "gdcm::Scanner failed when scanning " << files.size() << " input files."; return result; } // assign files IDs that will separate them for loading into image blocks for (auto fileIter = scanner.Begin(); fileIter != scanner.End(); ++fileIter) { if (std::string(fileIter->first).empty()) continue; // TODO understand why Scanner has empty string entries if (std::string(fileIter->first) == std::string("DICOMDIR")) continue; /* sort out multi-frame if ( scanner.GetValue( fileIter->first , tagNumberOfFrames ) ) { MITK_INFO << "Ignoring " << fileIter->first << " because we cannot handle multi-frame images."; continue; } */ // we const_cast here, because I could not use a map.at() function in CreateMoreUniqueSeriesIdentifier. // doing the same thing with find would make the code less readable. Since we forget the Scanner results // anyway after this function, we can simply tolerate empty map entries introduced by bad operator[] access std::string moreUniqueSeriesId = CreateMoreUniqueSeriesIdentifier(const_cast(fileIter->second)); result[moreUniqueSeriesId].AddFile(fileIter->first); } // PART II: sort slices spatially (or at least consistently if this is NOT possible, see method) for (FileNamesGrouping::const_iterator groupIter = result.begin(); groupIter != result.end(); ++groupIter) { try { result[groupIter->first] = ImageBlockDescriptor(SortSeriesSlices(groupIter->second.GetFilenames())); // sort each slice group spatially } catch (...) { MITK_ERROR << "Caught something."; } } // PART III: analyze pre-sorted images for valid blocks (i.e. blocks of equal z-spacing), // separate into multiple blocks if necessary. // // Analysis performs the following steps: // * imitate itk::ImageSeriesReader: use the distance between the first two images as z-spacing // * check what images actually fulfill ITK's z-spacing assumption // * separate all images that fail the test into new blocks, re-iterate analysis for these blocks // * this includes images which DO NOT PROVIDE spatial information, i.e. all images w/o // ImagePositionPatient will be loaded separately FileNamesGrouping groupsOf3DPlusTBlocks; // final result of this function for (FileNamesGrouping::const_iterator groupIter = result.begin(); groupIter != result.end(); ++groupIter) { FileNamesGrouping groupsOf3DBlocks; // intermediate result for only this group(!) StringContainer filesStillToAnalyze = groupIter->second.GetFilenames(); std::string groupUID = groupIter->first; unsigned int subgroup(0); MITK_DEBUG << "Analyze group " << groupUID << " of " << groupIter->second.GetFilenames().size() << " files"; while (!filesStillToAnalyze.empty()) // repeat until all files are grouped somehow { SliceGroupingAnalysisResult analysisResult = AnalyzeFileForITKImageSeriesReaderSpacingAssumption( filesStillToAnalyze, groupImagesWithGantryTilt, scanner.GetMappings()); // enhance the UID for additional groups std::stringstream newGroupUID; newGroupUID << groupUID << '.' << subgroup; ImageBlockDescriptor thisBlock(analysisResult.GetBlockFilenames()); std::string firstFileInBlock = thisBlock.GetFilenames().front(); thisBlock.SetImageBlockUID(newGroupUID.str()); thisBlock.SetSeriesInstanceUID( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagSeriesInstanceUID))); thisBlock.SetHasGantryTiltCorrected(analysisResult.ContainsGantryTilt()); thisBlock.SetSOPClassUID( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagSOPClassUID))); thisBlock.SetNumberOfFrames( ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagNumberOfFrames))); thisBlock.SetModality( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagModality))); thisBlock.SetPixelSpacingInformation( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagPixelSpacing)), DicomSeriesReader::ConstCharStarToString(scanner.GetValue(firstFileInBlock.c_str(), tagImagerPixelSpacing))); thisBlock.SetHasMultipleTimePoints(false); groupsOf3DBlocks[newGroupUID.str()] = thisBlock; // MITK_DEBUG << "Result: sorted 3D group " << newGroupUID.str() << " with " << groupsOf3DBlocks[ // newGroupUID.str() ].GetFilenames().size() << " files"; MITK_DEBUG << "Result: sorted 3D group with " << groupsOf3DBlocks[newGroupUID.str()].GetFilenames().size() << " files"; StringContainer debugOutputFiles = analysisResult.GetBlockFilenames(); for (StringContainer::const_iterator siter = debugOutputFiles.begin(); siter != debugOutputFiles.end(); ++siter) MITK_DEBUG << " IN " << *siter; ++subgroup; filesStillToAnalyze = analysisResult.GetUnsortedFilenames(); // remember what needs further analysis for (StringContainer::const_iterator siter = filesStillToAnalyze.begin(); siter != filesStillToAnalyze.end(); ++siter) MITK_DEBUG << " OUT " << *siter; } // end of grouping, now post-process groups // PART IV: attempt to group blocks to 3D+t blocks if requested // inspect entries of groupsOf3DBlocks // - if number of files is identical to previous entry, collect for 3D+t block // - as soon as number of files changes from previous entry, record collected blocks as 3D+t block, // start // a new one, continue // decide whether or not to group 3D blocks into 3D+t blocks where possible if (!sortTo3DPlust) { // copy 3D blocks to output groupsOf3DPlusTBlocks.insert(groupsOf3DBlocks.begin(), groupsOf3DBlocks.end()); } else { // sort 3D+t (as described in "PART IV") MITK_DEBUG << "================================================================================"; MITK_DEBUG << "3D+t analysis:"; unsigned int numberOfFilesInPreviousBlock(0); std::string previousBlockKey; for (FileNamesGrouping::const_iterator block3DIter = groupsOf3DBlocks.begin(); block3DIter != groupsOf3DBlocks.end(); ++block3DIter) { unsigned int numberOfFilesInThisBlock = block3DIter->second.GetFilenames().size(); std::string thisBlockKey = block3DIter->first; if (numberOfFilesInPreviousBlock == 0) { numberOfFilesInPreviousBlock = numberOfFilesInThisBlock; groupsOf3DPlusTBlocks[thisBlockKey] = block3DIter->second; MITK_DEBUG << " 3D+t group " << thisBlockKey; previousBlockKey = thisBlockKey; } else { bool identicalOrigins; try { // check whether this and the previous block share a comon origin // TODO should be safe, but a little try/catch or other error handling wouldn't hurt const char *origin_value = scanner.GetValue(groupsOf3DBlocks[thisBlockKey].GetFilenames().front().c_str(), tagImagePositionPatient), *previous_origin_value = scanner.GetValue( groupsOf3DBlocks[previousBlockKey].GetFilenames().front().c_str(), tagImagePositionPatient), *destination_value = scanner.GetValue( groupsOf3DBlocks[thisBlockKey].GetFilenames().back().c_str(), tagImagePositionPatient), *previous_destination_value = scanner.GetValue( groupsOf3DBlocks[previousBlockKey].GetFilenames().back().c_str(), tagImagePositionPatient); if (!origin_value || !previous_origin_value || !destination_value || !previous_destination_value) { identicalOrigins = false; } else { std::string thisOriginString = ConstCharStarToString(origin_value); std::string previousOriginString = ConstCharStarToString(previous_origin_value); // also compare last origin, because this might differ if z-spacing is different std::string thisDestinationString = ConstCharStarToString(destination_value); std::string previousDestinationString = ConstCharStarToString(previous_destination_value); identicalOrigins = ((thisOriginString == previousOriginString) && (thisDestinationString == previousDestinationString)); } } catch (...) { identicalOrigins = false; } if (identicalOrigins && (numberOfFilesInPreviousBlock == numberOfFilesInThisBlock)) { // group with previous block groupsOf3DPlusTBlocks[previousBlockKey].AddFiles(block3DIter->second.GetFilenames()); groupsOf3DPlusTBlocks[previousBlockKey].SetHasMultipleTimePoints(true); MITK_DEBUG << " --> group enhanced with another timestep"; } else { // start a new block groupsOf3DPlusTBlocks[thisBlockKey] = block3DIter->second; int numberOfTimeSteps = groupsOf3DPlusTBlocks[previousBlockKey].GetFilenames().size() / numberOfFilesInPreviousBlock; MITK_DEBUG << " ==> group closed with " << numberOfTimeSteps << " time steps"; previousBlockKey = thisBlockKey; MITK_DEBUG << " 3D+t group " << thisBlockKey << " started"; } } numberOfFilesInPreviousBlock = numberOfFilesInThisBlock; } } } MITK_DEBUG << "================================================================================"; MITK_DEBUG << "Summary: "; for (FileNamesGrouping::const_iterator groupIter = groupsOf3DPlusTBlocks.begin(); groupIter != groupsOf3DPlusTBlocks.end(); ++groupIter) { ImageBlockDescriptor block = groupIter->second; MITK_DEBUG << " " << block.GetFilenames().size() << " '" << block.GetModality() << "' images (" << block.GetSOPClassUIDAsString() << ") in volume " << block.GetImageBlockUID(); MITK_DEBUG << " (gantry tilt : " << (block.HasGantryTiltCorrected() ? "Yes" : "No") << "; " "pixel spacing : " << PixelSpacingInterpretationToString(block.GetPixelSpacingType()) << "; " "3D+t: " << (block.HasMultipleTimePoints() ? "Yes" : "No") << "; " "reader support: " << ReaderImplementationLevelToString(block.GetReaderImplementationLevel()) << ")"; StringContainer debugOutputFiles = block.GetFilenames(); for (StringContainer::const_iterator siter = debugOutputFiles.begin(); siter != debugOutputFiles.end(); ++siter) MITK_DEBUG << " F " << *siter; } MITK_DEBUG << "================================================================================"; return groupsOf3DPlusTBlocks; } DicomSeriesReader::FileNamesGrouping DicomSeriesReader::GetSeries(const std::string &dir, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { gdcm::Directory directoryLister; directoryLister.Load(dir.c_str(), false); // non-recursive return GetSeries(directoryLister.GetFilenames(), groupImagesWithGantryTilt, restrictions); } std::string DicomSeriesReader::CreateSeriesIdentifierPart(gdcm::Scanner::TagToValue &tagValueMap, const gdcm::Tag &tag) { std::string result; try { result = IDifyTagValue(tagValueMap[tag] ? tagValueMap[tag] : std::string("")); } - catch (std::exception &) + catch ( const std::exception & ) { // we are happy with even nothing, this will just group images of a series // MITK_WARN << "Could not access tag " << tag << ": " << e.what(); } return result; } std::string DicomSeriesReader::CreateMoreUniqueSeriesIdentifier(gdcm::Scanner::TagToValue &tagValueMap) { const gdcm::Tag tagSeriesInstanceUID(0x0020, 0x000e); // Series Instance UID const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // image orientation const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // pixel spacing const gdcm::Tag tagImagerPixelSpacing(0x0018, 0x1164); // imager pixel spacing const gdcm::Tag tagSliceThickness(0x0018, 0x0050); // slice thickness const gdcm::Tag tagNumberOfRows(0x0028, 0x0010); // number rows const gdcm::Tag tagNumberOfColumns(0x0028, 0x0011); // number cols const gdcm::Tag tagNumberOfFrames(0x0028, 0x0008); // number of frames const char *tagSeriesInstanceUid = tagValueMap[tagSeriesInstanceUID]; if (!tagSeriesInstanceUid) { mitkThrow() << "CreateMoreUniqueSeriesIdentifier() could not access series instance UID. Something is seriously " "wrong with this image, so stopping here."; } std::string constructedID = tagSeriesInstanceUid; constructedID += CreateSeriesIdentifierPart(tagValueMap, tagNumberOfRows); constructedID += CreateSeriesIdentifierPart(tagValueMap, tagNumberOfColumns); constructedID += CreateSeriesIdentifierPart(tagValueMap, tagPixelSpacing); constructedID += CreateSeriesIdentifierPart(tagValueMap, tagImagerPixelSpacing); constructedID += CreateSeriesIdentifierPart(tagValueMap, tagSliceThickness); constructedID += CreateSeriesIdentifierPart(tagValueMap, tagNumberOfFrames); // be a bit tolerant for orienatation, let only the first few digits matter // (http://bugs.mitk.org/show_bug.cgi?id=12263) // NOT constructedID += CreateSeriesIdentifierPart( tagValueMap, tagImageOrientation ); if (tagValueMap.find(tagImageOrientation) != tagValueMap.end()) { bool conversionError(false); Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); DICOMStringToOrientationVectors(tagValueMap[tagImageOrientation], right, up, conversionError); // string newstring sprintf(simplifiedOrientationString, "%.3f\\%.3f\\%.3f\\%.3f\\%.3f\\%.3f", right[0], // right[1], // right[2], up[0], up[1], up[2]); std::ostringstream ss; ss.setf(std::ios::fixed, std::ios::floatfield); ss.precision(5); ss << right[0] << "\\" << right[1] << "\\" << right[2] << "\\" << up[0] << "\\" << up[1] << "\\" << up[2]; std::string simplifiedOrientationString(ss.str()); constructedID += IDifyTagValue(simplifiedOrientationString); } constructedID.resize(constructedID.length() - 1); // cut of trailing '.' return constructedID; } std::string DicomSeriesReader::IDifyTagValue(const std::string &value) { std::string IDifiedValue(value); if (value.empty()) throw std::logic_error("IDifyTagValue() illegaly called with empty tag value"); // Eliminate non-alnum characters, including whitespace... // that may have been introduced by concats. for (std::size_t i = 0; i < IDifiedValue.size(); i++) { while (i < IDifiedValue.size() && !(IDifiedValue[i] == '.' || (IDifiedValue[i] >= 'a' && IDifiedValue[i] <= 'z') || (IDifiedValue[i] >= '0' && IDifiedValue[i] <= '9') || (IDifiedValue[i] >= 'A' && IDifiedValue[i] <= 'Z'))) { IDifiedValue.erase(i, 1); } } IDifiedValue += "."; return IDifiedValue; } DicomSeriesReader::StringContainer DicomSeriesReader::GetSeries(const std::string &dir, const std::string &series_uid, bool groupImagesWithGantryTilt, const StringContainer &restrictions) { FileNamesGrouping allSeries = GetSeries(dir, groupImagesWithGantryTilt, restrictions); StringContainer resultingFileList; for (FileNamesGrouping::const_iterator idIter = allSeries.begin(); idIter != allSeries.end(); ++idIter) { if (idIter->first.find(series_uid) == 0) // this ID starts with given series_uid { return idIter->second.GetFilenames(); } } return resultingFileList; } DicomSeriesReader::StringContainer DicomSeriesReader::SortSeriesSlices(const StringContainer &unsortedFilenames) { /* we CAN expect a group of equal - series instance uid - image orientation - pixel spacing - imager pixel spacing - slice thickness - number of rows/columns (each piece of information except the rows/columns might be missing) sorting with GdcmSortFunction tries its best by sorting by spatial position and more hints (acquisition number, acquisition time, trigger time) but will always produce a sorting by falling back to SOP Instance UID. */ gdcm::Sorter sorter; sorter.SetSortFunction(DicomSeriesReader::GdcmSortFunction); try { if (sorter.Sort(unsortedFilenames)) { return sorter.GetFilenames(); } else { MITK_WARN << "Sorting error. Leaving series unsorted."; return unsortedFilenames; } } - catch (std::logic_error &) + catch ( const std::logic_error & ) { MITK_WARN << "Sorting error. Leaving series unsorted."; return unsortedFilenames; } } bool DicomSeriesReader::GdcmSortFunction(const gdcm::DataSet &ds1, const gdcm::DataSet &ds2) { // This method MUST accept missing location and position information (and all else, too) // because we cannot rely on anything // (restriction on the sentence before: we have to provide consistent sorting, so we // rely on the minimum information all DICOM files need to provide: SOP Instance UID) /* we CAN expect a group of equal - series instance uid - image orientation - pixel spacing - imager pixel spacing - slice thickness - number of rows/columns */ static const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image Position (Patient) static const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image Orientation // see if we have Image Position and Orientation if (ds1.FindDataElement(tagImagePositionPatient) && ds1.FindDataElement(tagImageOrientation) && ds2.FindDataElement(tagImagePositionPatient) && ds2.FindDataElement(tagImageOrientation)) { gdcm::Attribute<0x0020, 0x0032> image_pos1; // Image Position (Patient) gdcm::Attribute<0x0020, 0x0037> image_orientation1; // Image Orientation (Patient) image_pos1.Set(ds1); image_orientation1.Set(ds1); gdcm::Attribute<0x0020, 0x0032> image_pos2; gdcm::Attribute<0x0020, 0x0037> image_orientation2; image_pos2.Set(ds2); image_orientation2.Set(ds2); /* we tolerate very small differences in image orientation, since we got to know about acquisitions where these values change across a single series (7th decimal digit) (http://bugs.mitk.org/show_bug.cgi?id=12263) still, we want to check if our assumption of 'almost equal' orientations is valid */ for (unsigned int dim = 0; dim < 6; ++dim) { if (fabs(image_orientation2[dim] - image_orientation1[dim]) > 0.0001) { MITK_ERROR << "Dicom images have different orientations."; throw std::logic_error( "Dicom images have different orientations. Call GetSeries() first to separate images."); } } double normal[3]; normal[0] = image_orientation1[1] * image_orientation1[5] - image_orientation1[2] * image_orientation1[4]; normal[1] = image_orientation1[2] * image_orientation1[3] - image_orientation1[0] * image_orientation1[5]; normal[2] = image_orientation1[0] * image_orientation1[4] - image_orientation1[1] * image_orientation1[3]; double dist1 = 0.0, dist2 = 0.0; // this computes the distance from world origin (0,0,0) ALONG THE NORMAL of the image planes for (unsigned char i = 0u; i < 3u; ++i) { dist1 += normal[i] * image_pos1[i]; dist2 += normal[i] * image_pos2[i]; } // if we can sort by just comparing the distance, we do exactly that if (fabs(dist1 - dist2) >= mitk::eps) { // default: compare position return dist1 < dist2; } else // we need to check more properties to distinguish slices { // try to sort by Acquisition Number static const gdcm::Tag tagAcquisitionNumber(0x0020, 0x0012); if (ds1.FindDataElement(tagAcquisitionNumber) && ds2.FindDataElement(tagAcquisitionNumber)) { gdcm::Attribute<0x0020, 0x0012> acquisition_number1; // Acquisition number gdcm::Attribute<0x0020, 0x0012> acquisition_number2; acquisition_number1.Set(ds1); acquisition_number2.Set(ds2); if (acquisition_number1 != acquisition_number2) { return acquisition_number1 < acquisition_number2; } else // neither position nor acquisition number are good for sorting, so check more { // try to sort by Acquisition Time static const gdcm::Tag tagAcquisitionTime(0x0008, 0x0032); if (ds1.FindDataElement(tagAcquisitionTime) && ds2.FindDataElement(tagAcquisitionTime)) { gdcm::Attribute<0x0008, 0x0032> acquisition_time1; // Acquisition time gdcm::Attribute<0x0008, 0x0032> acquisition_time2; acquisition_time1.Set(ds1); acquisition_time2.Set(ds2); if (acquisition_time1 != acquisition_time2) { return acquisition_time1 < acquisition_time2; } else // we gave up on image position, acquisition number and acquisition time now { // let's try trigger time static const gdcm::Tag tagTriggerTime(0x0018, 0x1060); if (ds1.FindDataElement(tagTriggerTime) && ds2.FindDataElement(tagTriggerTime)) { gdcm::Attribute<0x0018, 0x1060> trigger_time1; // Trigger time gdcm::Attribute<0x0018, 0x1060> trigger_time2; trigger_time1.Set(ds1); trigger_time2.Set(ds2); if (trigger_time1 != trigger_time2) { return trigger_time1 < trigger_time2; } // ELSE! // for this and many previous ifs we fall through if nothing lets us sort } // . } // . } // . } } } } // . // LAST RESORT: all valuable information for sorting is missing. // Sort by some meaningless but unique identifiers to satisfy the sort function static const gdcm::Tag tagSOPInstanceUID(0x0008, 0x0018); if (ds1.FindDataElement(tagSOPInstanceUID) && ds2.FindDataElement(tagSOPInstanceUID)) { MITK_DEBUG << "Dicom images are missing attributes for a meaningful sorting, falling back to SOP instance UID comparison."; gdcm::Attribute<0x0008, 0x0018> SOPInstanceUID1; // SOP instance UID is mandatory and unique gdcm::Attribute<0x0008, 0x0018> SOPInstanceUID2; SOPInstanceUID1.Set(ds1); SOPInstanceUID2.Set(ds2); return SOPInstanceUID1 < SOPInstanceUID2; } else { // no DICOM file should really come down here, this should only be reached with unskillful and unlucky // manipulation // of files std::string error_message("Malformed DICOM images, which do not even contain a SOP Instance UID."); MITK_ERROR << error_message; throw std::logic_error(error_message); } } std::string DicomSeriesReader::GetConfigurationString() { std::stringstream configuration; configuration << "MITK_USE_GDCMIO: "; configuration << "true"; configuration << "\n"; configuration << "GDCM_VERSION: "; #ifdef GDCM_MAJOR_VERSION configuration << GDCM_VERSION; #endif // configuration << "\n"; return configuration.str(); } void DicomSeriesReader::CopyMetaDataToImageProperties(StringContainer filenames, const gdcm::Scanner::MappingType &tagValueMappings_, DcmIoType *io, const ImageBlockDescriptor &blockInfo, Image *image) { std::list imageBlock; imageBlock.push_back(filenames); CopyMetaDataToImageProperties(imageBlock, tagValueMappings_, io, blockInfo, image); } void DicomSeriesReader::CopyMetaDataToImageProperties(std::list imageBlock, const gdcm::Scanner::MappingType &tagValueMappings_, DcmIoType *io, const ImageBlockDescriptor &blockInfo, Image *image) { if (!io || !image) return; StringLookupTable filesForSlices; StringLookupTable sliceLocationForSlices; StringLookupTable instanceNumberForSlices; StringLookupTable SOPInstanceNumberForSlices; auto &tagValueMappings = const_cast(tagValueMappings_); // DICOM tags which should be added to the image properties const gdcm::Tag tagSliceLocation(0x0020, 0x1041); // slice location const gdcm::Tag tagInstanceNumber(0x0020, 0x0013); // (image) instance number const gdcm::Tag tagSOPInstanceNumber(0x0008, 0x0018); // SOP instance number unsigned int timeStep(0); std::string propertyKeySliceLocation = "dicom.image.0020.1041"; std::string propertyKeyInstanceNumber = "dicom.image.0020.0013"; std::string propertyKeySOPInstanceNumber = "dicom.image.0008.0018"; // tags for each image for (auto i = imageBlock.begin(); i != imageBlock.end(); i++, timeStep++) { const StringContainer &files = (*i); unsigned int slice(0); for (auto fIter = files.begin(); fIter != files.end(); ++fIter, ++slice) { filesForSlices.SetTableValue(slice, *fIter); gdcm::Scanner::TagToValue tagValueMapForFile = tagValueMappings[fIter->c_str()]; if (tagValueMapForFile.find(tagSliceLocation) != tagValueMapForFile.end()) sliceLocationForSlices.SetTableValue(slice, tagValueMapForFile[tagSliceLocation]); if (tagValueMapForFile.find(tagInstanceNumber) != tagValueMapForFile.end()) instanceNumberForSlices.SetTableValue(slice, tagValueMapForFile[tagInstanceNumber]); if (tagValueMapForFile.find(tagSOPInstanceNumber) != tagValueMapForFile.end()) SOPInstanceNumberForSlices.SetTableValue(slice, tagValueMapForFile[tagSOPInstanceNumber]); } image->SetProperty("files", StringLookupTableProperty::New(filesForSlices)); // If more than one time step add postfix ".t" + timestep if (timeStep != 0) { std::ostringstream postfix; postfix << ".t" << timeStep; propertyKeySliceLocation.append(postfix.str()); propertyKeyInstanceNumber.append(postfix.str()); propertyKeySOPInstanceNumber.append(postfix.str()); } image->SetProperty(propertyKeySliceLocation.c_str(), StringLookupTableProperty::New(sliceLocationForSlices)); image->SetProperty(propertyKeyInstanceNumber.c_str(), StringLookupTableProperty::New(instanceNumberForSlices)); image->SetProperty(propertyKeySOPInstanceNumber.c_str(), StringLookupTableProperty::New(SOPInstanceNumberForSlices)); } // Copy tags for series, study, patient level (leave interpretation to application). // These properties will be copied to the DataNode by DicomSeriesReader. // tags for the series (we just use the one that ITK copied to its dictionary (proably that of the last slice) const itk::MetaDataDictionary &dict = io->GetMetaDataDictionary(); const TagToPropertyMapType &propertyLookup = DicomSeriesReader::GetDICOMTagsToMITKPropertyMap(); auto dictIter = dict.Begin(); while (dictIter != dict.End()) { // MITK_DEBUG << "Key " << dictIter->first; std::string value; if (itk::ExposeMetaData(dict, dictIter->first, value)) { // MITK_DEBUG << "Value " << value; auto valuePosition = propertyLookup.find(dictIter->first); if (valuePosition != propertyLookup.end()) { std::string propertyKey = valuePosition->second; // MITK_DEBUG << "--> " << propertyKey; image->SetProperty(propertyKey.c_str(), StringProperty::New(value)); } } else { MITK_WARN << "Tag " << dictIter->first << " not read as string as expected. Ignoring..."; } ++dictIter; } // copy imageblockdescriptor as properties image->SetProperty("dicomseriesreader.SOPClass", StringProperty::New(blockInfo.GetSOPClassUIDAsString())); image->SetProperty( "dicomseriesreader.ReaderImplementationLevelString", StringProperty::New(ReaderImplementationLevelToString(blockInfo.GetReaderImplementationLevel()))); image->SetProperty("dicomseriesreader.ReaderImplementationLevel", GenericProperty::New(blockInfo.GetReaderImplementationLevel())); image->SetProperty("dicomseriesreader.PixelSpacingInterpretationString", StringProperty::New(PixelSpacingInterpretationToString(blockInfo.GetPixelSpacingType()))); image->SetProperty("dicomseriesreader.PixelSpacingInterpretation", GenericProperty::New(blockInfo.GetPixelSpacingType())); image->SetProperty("dicomseriesreader.MultiFrameImage", BoolProperty::New(blockInfo.IsMultiFrameImage())); image->SetProperty("dicomseriesreader.GantyTiltCorrected", BoolProperty::New(blockInfo.HasGantryTiltCorrected())); image->SetProperty("dicomseriesreader.3D+t", BoolProperty::New(blockInfo.HasMultipleTimePoints())); } void DicomSeriesReader::FixSpacingInformation(mitk::Image *image, const ImageBlockDescriptor &imageBlockDescriptor) { // spacing provided by ITK/GDCM Vector3D imageSpacing = image->GetGeometry()->GetSpacing(); ScalarType imageSpacingX = imageSpacing[0]; ScalarType imageSpacingY = imageSpacing[1]; // spacing as desired by MITK (preference for "in patient", else "on detector", or "1.0/1.0") ScalarType desiredSpacingX = imageSpacingX; ScalarType desiredSpacingY = imageSpacingY; imageBlockDescriptor.GetDesiredMITKImagePixelSpacing(desiredSpacingX, desiredSpacingY); MITK_DEBUG << "Loaded spacing: " << imageSpacingX << "/" << imageSpacingY; MITK_DEBUG << "Corrected spacing: " << desiredSpacingX << "/" << desiredSpacingY; imageSpacing[0] = desiredSpacingX; imageSpacing[1] = desiredSpacingY; image->GetGeometry()->SetSpacing(imageSpacing); } void DicomSeriesReader::LoadDicom(const StringContainer &filenames, DataNode &node, bool sort, bool load4D, bool correctTilt, UpdateCallBackMethod callback, Image::Pointer preLoadedImageBlock) { mitk::LocaleSwitch localeSwitch("C"); std::locale previousCppLocale(std::cin.getloc()); std::locale l("C"); std::cin.imbue(l); ImageBlockDescriptor imageBlockDescriptor; const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image Position (Patient) const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image Orientation const gdcm::Tag tagSeriesInstanceUID(0x0020, 0x000e); // Series Instance UID const gdcm::Tag tagSOPClassUID(0x0008, 0x0016); // SOP class UID const gdcm::Tag tagModality(0x0008, 0x0060); // modality const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // pixel spacing const gdcm::Tag tagImagerPixelSpacing(0x0018, 0x1164); // imager pixel spacing const gdcm::Tag tagNumberOfFrames(0x0028, 0x0008); // number of frames try { Image::Pointer image = preLoadedImageBlock.IsNull() ? Image::New() : preLoadedImageBlock; CallbackCommand *command = callback ? new CallbackCommand(callback) : nullptr; bool initialize_node = false; /* special case for Philips 3D+t ultrasound images */ if (DicomSeriesReader::IsPhilips3DDicom(filenames.front().c_str())) { // TODO what about imageBlockDescriptor? // TODO what about preLoadedImageBlock? ReadPhilips3DDicom(filenames.front().c_str(), image); initialize_node = true; } else { /* default case: assume "normal" image blocks, possibly 3D+t */ bool canLoadAs4D(true); gdcm::Scanner scanner; ScanForSliceInformation(filenames, scanner); // need non-const access for map auto &tagValueMappings = const_cast(scanner.GetMappings()); std::list imageBlocks = SortIntoBlocksFor3DplusT(filenames, tagValueMappings, sort, canLoadAs4D); unsigned int volume_count = imageBlocks.size(); imageBlockDescriptor.SetSeriesInstanceUID( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagSeriesInstanceUID))); imageBlockDescriptor.SetSOPClassUID( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagSOPClassUID))); imageBlockDescriptor.SetModality( DicomSeriesReader::ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagModality))); imageBlockDescriptor.SetNumberOfFrames( ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagNumberOfFrames))); imageBlockDescriptor.SetPixelSpacingInformation( ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagPixelSpacing)), ConstCharStarToString(scanner.GetValue(filenames.front().c_str(), tagImagerPixelSpacing))); GantryTiltInformation tiltInfo; // check possibility of a single slice with many timesteps. In this case, don't check for tilt, no second slice // possible if (!imageBlocks.empty() && imageBlocks.front().size() > 1 && correctTilt) { // check tiltedness here, potentially fixup ITK's loading result by shifting slice contents // check first and last position slice from tags, make some calculations to detect tilt std::string firstFilename(imageBlocks.front().front()); // calculate from first and last slice to minimize rounding errors std::string secondFilename(imageBlocks.front().back()); std::string imagePosition1( ConstCharStarToString(tagValueMappings[firstFilename.c_str()][tagImagePositionPatient])); std::string imageOrientation( ConstCharStarToString(tagValueMappings[firstFilename.c_str()][tagImageOrientation])); std::string imagePosition2( ConstCharStarToString(tagValueMappings[secondFilename.c_str()][tagImagePositionPatient])); bool ignoredConversionError(-42); // hard to get here, no graceful way to react Point3D origin1(DICOMStringToPoint3D(imagePosition1, ignoredConversionError)); Point3D origin2(DICOMStringToPoint3D(imagePosition2, ignoredConversionError)); Vector3D right; right.Fill(0.0); Vector3D up; right.Fill(0.0); // might be down as well, but it is just a name at this point DICOMStringToOrientationVectors(imageOrientation, right, up, ignoredConversionError); tiltInfo = GantryTiltInformation(origin1, origin2, right, up, filenames.size() - 1); correctTilt = tiltInfo.IsSheared() && tiltInfo.IsRegularGantryTilt(); } else { correctTilt = false; // we CANNOT do that } imageBlockDescriptor.SetHasGantryTiltCorrected(correctTilt); if (volume_count == 1 || !canLoadAs4D || !load4D) { DcmIoType::Pointer io; image = MultiplexLoadDICOMByITK( imageBlocks.front(), correctTilt, tiltInfo, io, command, preLoadedImageBlock); // load first 3D block imageBlockDescriptor.AddFiles(imageBlocks.front()); // only the first part is loaded imageBlockDescriptor.SetHasMultipleTimePoints(false); FixSpacingInformation(image, imageBlockDescriptor); CopyMetaDataToImageProperties(imageBlocks.front(), scanner.GetMappings(), io, imageBlockDescriptor, image); initialize_node = true; } else if (volume_count > 1) { imageBlockDescriptor.AddFiles(filenames); // all is loaded imageBlockDescriptor.SetHasMultipleTimePoints(true); DcmIoType::Pointer io; image = MultiplexLoadDICOMByITK4D( imageBlocks, imageBlockDescriptor, correctTilt, tiltInfo, io, command, preLoadedImageBlock); initialize_node = true; } } if (initialize_node) { // forward some image properties to node node.GetPropertyList()->ConcatenatePropertyList(image->GetPropertyList(), true); std::string patientName = "NoName"; if (node.GetProperty("dicom.patient.PatientsName")) patientName = node.GetProperty("dicom.patient.PatientsName")->GetValueAsString(); node.SetData(image); node.SetName(patientName); std::cin.imbue(previousCppLocale); } MITK_DEBUG << "--------------------------------------------------------------------------------"; MITK_DEBUG << "DICOM files loaded (from series UID " << imageBlockDescriptor.GetSeriesInstanceUID() << "):"; MITK_DEBUG << " " << imageBlockDescriptor.GetFilenames().size() << " '" << imageBlockDescriptor.GetModality() << "' files (" << imageBlockDescriptor.GetSOPClassUIDAsString() << ") loaded into 1 mitk::Image"; MITK_DEBUG << " multi-frame: " << (imageBlockDescriptor.IsMultiFrameImage() ? "Yes" : "No"); MITK_DEBUG << " reader support: " << ReaderImplementationLevelToString(imageBlockDescriptor.GetReaderImplementationLevel()); MITK_DEBUG << " pixel spacing type: " << PixelSpacingInterpretationToString(imageBlockDescriptor.GetPixelSpacingType()) << " " << image->GetGeometry()->GetSpacing()[0] << "/" << image->GetGeometry()->GetSpacing()[0]; MITK_DEBUG << " gantry tilt corrected: " << (imageBlockDescriptor.HasGantryTiltCorrected() ? "Yes" : "No"); MITK_DEBUG << " 3D+t: " << (imageBlockDescriptor.HasMultipleTimePoints() ? "Yes" : "No"); MITK_DEBUG << "--------------------------------------------------------------------------------"; } - catch (std::exception &e) + catch ( const std::exception &e ) { // reset locale then throw up std::cin.imbue(previousCppLocale); MITK_DEBUG << "Caught exception in DicomSeriesReader::LoadDicom"; throw e; } } void DicomSeriesReader::ScanForSliceInformation(const StringContainer &filenames, gdcm::Scanner &scanner) { const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image position (Patient) scanner.AddTag(tagImagePositionPatient); const gdcm::Tag tagSeriesInstanceUID(0x0020, 0x000e); // Series Instance UID scanner.AddTag(tagSeriesInstanceUID); const gdcm::Tag tagImageOrientation(0x0020, 0x0037); // Image orientation scanner.AddTag(tagImageOrientation); const gdcm::Tag tagSliceLocation(0x0020, 0x1041); // slice location scanner.AddTag(tagSliceLocation); const gdcm::Tag tagInstanceNumber(0x0020, 0x0013); // (image) instance number scanner.AddTag(tagInstanceNumber); const gdcm::Tag tagSOPInstanceNumber(0x0008, 0x0018); // SOP instance number scanner.AddTag(tagSOPInstanceNumber); const gdcm::Tag tagPixelSpacing(0x0028, 0x0030); // Pixel Spacing scanner.AddTag(tagPixelSpacing); const gdcm::Tag tagImagerPixelSpacing(0x0018, 0x1164); // Imager Pixel Spacing scanner.AddTag(tagImagerPixelSpacing); const gdcm::Tag tagModality(0x0008, 0x0060); // Modality scanner.AddTag(tagModality); const gdcm::Tag tagSOPClassUID(0x0008, 0x0016); // SOP Class UID scanner.AddTag(tagSOPClassUID); const gdcm::Tag tagNumberOfFrames(0x0028, 0x0008); // number of frames scanner.AddTag(tagNumberOfFrames); scanner.Scan(filenames); // make available image information for each file } std::list DicomSeriesReader::SortIntoBlocksFor3DplusT( const StringContainer &presortedFilenames, const gdcm::Scanner::MappingType &tagValueMappings, bool /*sort*/, bool &canLoadAs4D) { std::list imageBlocks; // ignore sort request, because most likely re-sorting is now needed due to changes in GetSeries(bug #8022) StringContainer sorted_filenames = DicomSeriesReader::SortSeriesSlices(presortedFilenames); std::string firstPosition; unsigned int numberOfBlocks(0); // number of 3D image blocks static const gdcm::Tag tagImagePositionPatient(0x0020, 0x0032); // Image position (Patient) const gdcm::Tag tagModality(0x0008, 0x0060); // loop files to determine number of image blocks for (StringContainer::const_iterator fileIter = sorted_filenames.begin(); fileIter != sorted_filenames.end(); ++fileIter) { gdcm::Scanner::TagToValue tagToValueMap = tagValueMappings.find(fileIter->c_str())->second; if (tagToValueMap.find(tagImagePositionPatient) == tagToValueMap.end()) { const std::string &modality = tagToValueMap.find(tagModality)->second; if (modality.compare("RTIMAGE ") == 0 || modality.compare("RTIMAGE") == 0) { MITK_WARN << "Modality " << modality << " is not fully supported yet."; numberOfBlocks = 1; break; } else { // we expect to get images w/ missing position information ONLY as separated blocks. assert(presortedFilenames.size() == 1); numberOfBlocks = 1; break; } } std::string position = tagToValueMap.find(tagImagePositionPatient)->second; MITK_DEBUG << " " << *fileIter << " at " << position; if (firstPosition.empty()) { firstPosition = position; } if (position == firstPosition) { ++numberOfBlocks; } else { break; // enough information to know the number of image blocks } } MITK_DEBUG << " ==> Assuming " << numberOfBlocks << " time steps"; if (numberOfBlocks == 0) return imageBlocks; // only possible if called with no files // loop files to sort them into image blocks unsigned int numberOfExpectedSlices(0); for (unsigned int block = 0; block < numberOfBlocks; ++block) { StringContainer filesOfCurrentBlock; for (StringContainer::const_iterator fileIter = sorted_filenames.begin() + block; fileIter != sorted_filenames.end(); // fileIter += numberOfBlocks) // TODO shouldn't this work? give invalid iterators on first attempts ) { filesOfCurrentBlock.push_back(*fileIter); for (unsigned int b = 0; b < numberOfBlocks; ++b) { if (fileIter != sorted_filenames.end()) ++fileIter; } } imageBlocks.push_back(filesOfCurrentBlock); if (block == 0) { numberOfExpectedSlices = filesOfCurrentBlock.size(); } else { if (filesOfCurrentBlock.size() != numberOfExpectedSlices) { MITK_WARN << "DicomSeriesReader expected " << numberOfBlocks << " image blocks of " << numberOfExpectedSlices << " images each. Block " << block << " got " << filesOfCurrentBlock.size() << " instead. Cannot load this as 3D+t"; // TODO implement recovery (load as many slices 3D+t as much // as possible) canLoadAs4D = false; } } } return imageBlocks; } Image::Pointer DicomSeriesReader::MultiplexLoadDICOMByITK(const StringContainer &filenames, bool correctTilt, const GantryTiltInformation &tiltInfo, DcmIoType::Pointer &io, CallbackCommand *command, Image::Pointer preLoadedImageBlock) { io = DcmIoType::New(); io->SetFileName(filenames.front().c_str()); io->ReadImageInformation(); if (io->GetPixelType() == itk::ImageIOBase::SCALAR) { return MultiplexLoadDICOMByITKScalar(filenames, correctTilt, tiltInfo, io, command, preLoadedImageBlock); } else if (io->GetPixelType() == itk::ImageIOBase::RGB) { return MultiplexLoadDICOMByITKRGBPixel(filenames, correctTilt, tiltInfo, io, command, preLoadedImageBlock); } else { return nullptr; } } Image::Pointer DicomSeriesReader::MultiplexLoadDICOMByITK4D(std::list &imageBlocks, ImageBlockDescriptor imageBlockDescriptor, bool correctTilt, const GantryTiltInformation &tiltInfo, DcmIoType::Pointer &io, CallbackCommand *command, Image::Pointer preLoadedImageBlock) { io = DcmIoType::New(); io->SetFileName(imageBlocks.front().front().c_str()); io->ReadImageInformation(); if (io->GetPixelType() == itk::ImageIOBase::SCALAR) { return MultiplexLoadDICOMByITK4DScalar( imageBlocks, imageBlockDescriptor, correctTilt, tiltInfo, io, command, preLoadedImageBlock); } else if (io->GetPixelType() == itk::ImageIOBase::RGB) { return MultiplexLoadDICOMByITK4DRGBPixel( imageBlocks, imageBlockDescriptor, correctTilt, tiltInfo, io, command, preLoadedImageBlock); } else { return nullptr; } } } // end namespace mitk diff --git a/Modules/IGT/Testing/mitkNavigationDataLandmarkTransformFilterTest.cpp b/Modules/IGT/Testing/mitkNavigationDataLandmarkTransformFilterTest.cpp index a0d8ff538f..e26932362e 100644 --- a/Modules/IGT/Testing/mitkNavigationDataLandmarkTransformFilterTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataLandmarkTransformFilterTest.cpp @@ -1,511 +1,511 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataLandmarkTransformFilter.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" #include class mitkNavigationDataLandmarkTransformFilterTestClass { public: static void TestInstantiation() { // let's create an object of our class mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter = mitk::NavigationDataLandmarkTransformFilter::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); } static void TestFilter() { // let's create an object of our class mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter = mitk::NavigationDataLandmarkTransformFilter::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); /*create helper objects: source and target pointSets for landmark transform*/ mitk::Point3D sPoint1, sPoint2, sPoint3, tPoint1, tPoint2, tPoint3; mitk::FillVector3D(sPoint1, 1.1, 1.1, 1.1); mitk::FillVector3D(sPoint2, 2.2, 2.2, 2.2); mitk::FillVector3D(sPoint3, 3.3, 3.3, 3.3); mitk::FillVector3D(tPoint1, 2.1, 2.1, 2.1); mitk::FillVector3D(tPoint2, 3.2, 3.2, 3.2); mitk::FillVector3D(tPoint3, 4.3, 4.3, 4.3); mitk::PointSet::Pointer sourcePoints = mitk::PointSet::New(); mitk::PointSet::Pointer targetPoints = mitk::PointSet::New(); sourcePoints->SetPoint(0,sPoint1); sourcePoints->SetPoint(1,sPoint2); sourcePoints->SetPoint(2,sPoint3); targetPoints->SetPoint(0,tPoint1); targetPoints->SetPoint(1,tPoint2); targetPoints->SetPoint(2,tPoint3); /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */ mitk::NavigationData::PositionType initialPos1,initialPos2, resultPos1,resultPos2; mitk::FillVector3D(initialPos1, 1.1, 1.1, 1.1); mitk::FillVector3D(initialPos2, 22.2,22.2, 22.2); mitk::FillVector3D(resultPos1, 2.1, 2.1, 2.1); mitk::FillVector3D(resultPos2, 23.2, 23.2, 23.2); mitk::NavigationData::OrientationType initialOri(0.1, 0.1, 0.1, 0.1); mitk::ScalarType initialError(0.0); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos1); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); mitk::NavigationData::Pointer nd2 = mitk::NavigationData::New(); nd2->SetPosition(initialPos2); nd2->SetOrientation(initialOri); nd2->SetPositionAccuracy(initialError); nd2->SetDataValid(initialValid); myFilter->SetInput(0,nd1); MITK_TEST_CONDITION(myFilter->GetInput(0) == nd1, "Testing Set-/GetInput() ND1"); mitk::NavigationData* output1 = myFilter->GetOutput(); MITK_TEST_CONDITION_REQUIRED(output1 != nullptr, "Testing GetOutput() ND1"); MITK_TEST_CONDITION(myFilter->IsInitialized() == false, "Testing IsInitialized() before setting source points"); myFilter->SetSourceLandmarks(sourcePoints); MITK_TEST_CONDITION(myFilter->IsInitialized() == false, "Testing IsInitialized() after setting source points and before setting target points"); mitk::PointSet::Pointer zeroTargetPoints = mitk::PointSet::New(); MITK_TEST_FOR_EXCEPTION(itk::ExceptionObject, myFilter->SetTargetLandmarks(zeroTargetPoints)); MITK_TEST_CONDITION(myFilter->IsInitialized() == false, "Testing IsInitialized() after setting target pointset with insufficient points"); myFilter->SetTargetLandmarks(targetPoints); MITK_TEST_CONDITION(myFilter->IsInitialized() == true, "Testing IsInitialized() after setting source& target points"); //------------------------landmark transform should be initialized at this point------------------------ output1->Update(); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(output1->GetPosition(), resultPos1), "Testing ND1 position correctly transformed"); //------------------------add another ND------------------------ myFilter->SetInput(1,nd2); MITK_TEST_CONDITION(myFilter->GetInput(1) == nd2, "Testing Set-/GetInput() ND2"); mitk::NavigationData* output2 = myFilter->GetOutput(1); MITK_TEST_CONDITION_REQUIRED(output2 != nullptr, "Testing GetOutput() ND2"); //------------------------update output1 but check result2------------------------ output1->Update(); MITK_TEST_CONDITION_REQUIRED( mitk::Equal(output2->GetPosition(), resultPos2), "Testing ND2 position correctly transformed"); //------------------------update ND on slot 1------------------------ mitk::FillVector3D(initialPos2, 222.22, 222.22, 222.22); mitk::FillVector3D(resultPos2, 223.22, 223.22, 223.22); nd2->SetPosition(initialPos2); myFilter->SetInput(1,nd2); MITK_TEST_CONDITION(myFilter->GetInput(1) == nd2, "Testing Set-/GetInput() ND2 after updating value"); output2 = myFilter->GetOutput(1); MITK_TEST_CONDITION_REQUIRED(output2 != nullptr, "Testing GetOutput() ND2 after updating value"); //------------------------update output2 and check result2------------------------ output2->Update(); MITK_TEST_CONDITION( mitk::Equal(output2->GetPosition(), resultPos2, 0.00001), "Testing ND2 position correctly transformed after updating value"); //------------------------change target PointSet------------------------ mitk::FillVector3D(tPoint1, 3.1, 3.1, 3.1); mitk::FillVector3D(tPoint2, 4.2, 4.2, 4.2); mitk::FillVector3D(tPoint3, 5.3, 5.3, 5.3); mitk::FillVector3D(resultPos1, 3.1 ,3.1 ,3.1); mitk::FillVector3D(resultPos2, 224.22, 224.22, 224.22); targetPoints->SetPoint(0,tPoint1); targetPoints->SetPoint(1,tPoint2); targetPoints->SetPoint(2,tPoint3); myFilter->SetTargetLandmarks(targetPoints); output1->Update(); MITK_TEST_CONDITION( mitk::Equal(output1->GetPosition(), resultPos1), "Testing ND1 position correctly transformed after targetPointSet changed"); MITK_TEST_CONDITION( mitk::Equal(output2->GetPosition(), resultPos2, 0.00001), "Testing ND2 position correctly transformed after targetPointSet changed"); //------------------------change source PointSet------------------------ mitk::FillVector3D(sPoint1, 0.1, 0.1, 0.1); mitk::FillVector3D(sPoint2, 1.2, 1.2, 1.2); mitk::FillVector3D(sPoint3, 2.3, 2.3, 2.3); mitk::FillVector3D(resultPos1, 4.1 ,4.1 ,4.1); mitk::FillVector3D(resultPos2, 225.22, 225.22, 225.22); sourcePoints->SetPoint(0,sPoint1); sourcePoints->SetPoint(1,sPoint2); sourcePoints->SetPoint(2,sPoint3); myFilter->SetSourceLandmarks(sourcePoints); output1->Update(); MITK_TEST_CONDITION( mitk::Equal(output1->GetPosition(), resultPos1, 0.00001), "Testing ND1 position correctly transformed after sourcePointSet changed"); MITK_TEST_CONDITION( mitk::Equal(output2->GetPosition(), resultPos2,0.00001), "Testing ND2 position correctly transformed after sourcePointSet changed"); //--------------------- Test ICP initialization -------------------------- { mitk::PointSet::Pointer sourcePoints = mitk::PointSet::New(); mitk::Point3D s1, s2, s3, s4, s5, s6; mitk::FillVector3D(s1, 1.1, 1.1, 1.1); mitk::FillVector3D(s2, 2.2, 2.2, 2.2); mitk::FillVector3D(s3, 3.3, 3.3, 3.3); mitk::FillVector3D(s4, 4.4, 4.4, 4.4); mitk::FillVector3D(s5, 5.5, 5.5, 5.5); mitk::FillVector3D(s6, 6.6, 6.6, 6.6); sourcePoints->SetPoint(1, s4); // use random source point order sourcePoints->SetPoint(2, s6); sourcePoints->SetPoint(3, s3); sourcePoints->SetPoint(4, s1); sourcePoints->SetPoint(5, s2); sourcePoints->SetPoint(6, s5); mitk::PointSet::Pointer targetPoints = mitk::PointSet::New(); mitk::Point3D t1, t2, t3, t4, t5, t6; mitk::FillVector3D(t1, 2.1, 2.1, 102.1); // ==> targets have offset [1, 1, 101] mitk::FillVector3D(t2, 3.2, 3.2, 103.2); mitk::FillVector3D(t3, 4.3, 4.3, 104.3); mitk::FillVector3D(t4, 5.4, 5.4, 105.4); mitk::FillVector3D(t5, 6.5, 6.5, 106.5); mitk::FillVector3D(t6, 7.6, 7.6, 107.6); targetPoints->SetPoint(1, t1); targetPoints->SetPoint(2, t2); targetPoints->SetPoint(3, t3); targetPoints->SetPoint(4, t4); targetPoints->SetPoint(5, t5); targetPoints->SetPoint(6, t6); mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter = mitk::NavigationDataLandmarkTransformFilter::New(); myFilter->UseICPInitializationOn(); myFilter->SetSourceLandmarks(sourcePoints); myFilter->SetTargetLandmarks(targetPoints); // errors would raise exceptions // prepare input mitk::NavigationData::PositionType initialPos1, resultPos1; mitk::FillVector3D(initialPos1, 1.1, 1.1, 1.1); mitk::FillVector3D(resultPos1, 2.1, 2.1, 102.1); mitk::NavigationData::OrientationType initialOri(0.1, 0.1, 0.1, 0.1); mitk::ScalarType initialError(0.0); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos1); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); myFilter->SetInput(0, nd1); mitk::NavigationData::Pointer output = myFilter->GetOutput(); output->Update(); MITK_TEST_CONDITION(mitk::Equal(output->GetPosition(), resultPos1,0.00001), "Testing ND1 position correctly transformed after ICP initialization"); } //------------------------catch exception --> source points < 3------------------------ mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter2 = mitk::NavigationDataLandmarkTransformFilter::New(); MITK_TEST_CONDITION_REQUIRED(myFilter2.IsNotNull(),"Testing instantiation for second filter"); mitk::PointSet::Pointer sourcePoints2 = mitk::PointSet::New(); MITK_TEST_FOR_EXCEPTION(std::exception, myFilter2->SetSourceLandmarks(sourcePoints2);); //------------------------catch exception --> target points < 3------------------------ mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter3 = mitk::NavigationDataLandmarkTransformFilter::New(); MITK_TEST_CONDITION_REQUIRED(myFilter3.IsNotNull(),"Testing instantiation for second filter"); mitk::PointSet::Pointer targetPoints2 = mitk::PointSet::New(); MITK_TEST_FOR_EXCEPTION(std::exception, myFilter3->SetTargetLandmarks(targetPoints2);); //------------------------rotate orientation------------------------ myFilter=nullptr; myFilter = mitk::NavigationDataLandmarkTransformFilter::New(); mitk::FillVector3D(sPoint1, 1.1, 1.1, 1.1); mitk::FillVector3D(sPoint2, 1.1, -1.1, 1.1); mitk::FillVector3D(sPoint3, -1.1, -1.1, 1.1); mitk::FillVector3D(tPoint1, -1.1, 1.1, 1.1); mitk::FillVector3D(tPoint2, 1.1, 1.1, 1.1); mitk::FillVector3D(tPoint3, 1.1, -1.1, 1.1); sourcePoints->SetPoint(0,sPoint1); sourcePoints->SetPoint(1,sPoint2); sourcePoints->SetPoint(2,sPoint3); targetPoints->SetPoint(0,tPoint1); targetPoints->SetPoint(1,tPoint2); targetPoints->SetPoint(2,tPoint3); myFilter->SetSourceLandmarks(sourcePoints); myFilter->SetTargetLandmarks(targetPoints); //set initial orientation (x y z r) mitk::NavigationData::OrientationType initialQuat(0.0, 0.0, 0.0, 1.0); mitk::NavigationData::OrientationType resultQuat(0.0, 0.0, -0.7071, -0.7071); //set position mitk::FillVector3D(initialPos1, 2.2, 2.2, 2.2); mitk::FillVector3D(resultPos1, -2.2, 2.2, 2.2); nd1->SetOrientation(initialQuat); nd1->SetPosition(initialPos1); myFilter->SetInput(0,nd1); output1 = myFilter->GetOutput(); output1->Update(); MITK_TEST_CONDITION( mitk::Equal(output1->GetPosition(), resultPos1, 0.00001), "Testing ND1 position correctly transformed "); MITK_TEST_CONDITION( mitk::Equal(output1->GetOrientation(), resultQuat, 0.00001), "Testing ND1 orientation correctly transformed "); MITK_TEST_OUTPUT(<<"Orientation1"); MITK_TEST_OUTPUT(<GetOrientation()); MITK_TEST_OUTPUT(<<"qX:"); MITK_TEST_OUTPUT(<GetOrientation().x()); MITK_TEST_OUTPUT(<<"qY:"); MITK_TEST_OUTPUT(<GetOrientation().y()); MITK_TEST_OUTPUT(<<"qZ:"); MITK_TEST_OUTPUT(<GetOrientation().z()); MITK_TEST_OUTPUT(<<"qR:"); MITK_TEST_OUTPUT(<GetOrientation().r()); MITK_TEST_OUTPUT(<<"angle:"); //MITK_TEST_OUTPUT(<angle()); //TODO: something was modified on vnl_quaternion, check what. DONE MITK_TEST_OUTPUT(<<"Orientation2"); MITK_TEST_OUTPUT(<SetPoint(0, refPoint); movPoint.Fill(1); movSet->SetPoint(0, movPoint); //Point 1 refPoint[0]=3; refPoint[1]=0; refPoint[2]=0; refSet->SetPoint(1, refPoint); movPoint[0]=2; movPoint[1]=1; movPoint[2]=1; movSet->SetPoint(1, movPoint); //Point 2 refPoint[0]=0; refPoint[1]=0; refPoint[2]=3; refSet->SetPoint(2, refPoint); movPoint[0]=1; movPoint[1]=1; movPoint[2]=2; movSet->SetPoint(2, movPoint); //Point 3 refPoint[0]=3; refPoint[1]=0; refPoint[2]=3; refSet->SetPoint(3, refPoint); movPoint[0]=2; movPoint[1]=1; movPoint[2]=2; movSet->SetPoint(3, movPoint); //Point 4 refPoint[0]=0; refPoint[1]=3; refPoint[2]=0; refSet->SetPoint(4, refPoint); movPoint[0]=1; movPoint[1]=2; movPoint[2]=1; movSet->SetPoint(4, movPoint); //Point 5 refPoint[0]=3; refPoint[1]=3; refPoint[2]=0; refSet->SetPoint(5, refPoint); movPoint[0]=2; movPoint[1]=2; movPoint[2]=1; movSet->SetPoint(5, movPoint); //Point 6 refPoint[0]=0; refPoint[1]=3; refPoint[2]=3; refSet->SetPoint(6, refPoint); movPoint[0]=1; movPoint[1]=2; movPoint[2]=2; movSet->SetPoint(6, movPoint); //Point 7 refPoint[0]=3; refPoint[1]=3; refPoint[2]=3; refSet->SetPoint(7, refPoint); movPoint[0]=2; movPoint[1]=2; movPoint[2]=2; movSet->SetPoint(7, movPoint); mitk::NavigationDataLandmarkTransformFilter::Pointer myFREFilter = mitk::NavigationDataLandmarkTransformFilter::New(); myFREFilter->SetSourceLandmarks(refSet); myFREFilter->SetTargetLandmarks(movSet); //very simple test case, everything is the same (min = max = mean = RMS = abs max error) //but still ok to see if the methods work without a crash MITK_TEST_CONDITION_REQUIRED(mitk::Equal(myFREFilter->GetFRE(), (double) sqrt(3.0), 0.00001), "Testing mean error calculation"); MITK_TEST_CONDITION_REQUIRED(myFREFilter->GetMaxError() == (double) sqrt(3.0),"Testing max error calculation"); MITK_TEST_CONDITION_REQUIRED(myFREFilter->GetMinError() == (double) sqrt(3.0),"Testing min error calculation"); MITK_TEST_CONDITION_REQUIRED(myFREFilter->GetRMSError() == (double) sqrt(3.0),"Testing RMS error calculation"); MITK_TEST_CONDITION_REQUIRED(mitk::Equal(myFREFilter->GetFREStdDev(), (double) 0.0, 0.00001),"Testing SD calculation"); MITK_TEST_CONDITION_REQUIRED(myFREFilter->GetAbsMaxError() == (double) sqrt(3.0),"Testing abs max error calculation"); MITK_TEST_CONDITION_REQUIRED(myFREFilter->GetErrorVector().size() == 8,"Testing method GetErrorVector"); //todo: extend by a more complex test case with different values? } static void TestPrintSelfMethod() { mitk::PointSet::Pointer refSet = mitk::PointSet::New(); mitk::PointSet::Pointer movSet = mitk::PointSet::New(); mitk::Point3D refPoint; mitk::Point3D movPoint; //Point 0 refPoint.Fill(0); refSet->SetPoint(0, refPoint); movPoint.Fill(1); movSet->SetPoint(0, movPoint); //Point 1 refPoint[0]=3; refPoint[1]=0; refPoint[2]=0; refSet->SetPoint(1, refPoint); movPoint[0]=2; movPoint[1]=1; movPoint[2]=1; movSet->SetPoint(1, movPoint); //Point 2 refPoint[0]=0; refPoint[1]=0; refPoint[2]=3; refSet->SetPoint(2, refPoint); movPoint[0]=1; movPoint[1]=1; movPoint[2]=2; movSet->SetPoint(2, movPoint); //Point 3 refPoint[0]=3; refPoint[1]=0; refPoint[2]=3; refSet->SetPoint(3, refPoint); movPoint[0]=2; movPoint[1]=1; movPoint[2]=2; movSet->SetPoint(3, movPoint); //Point 4 refPoint[0]=0; refPoint[1]=3; refPoint[2]=0; refSet->SetPoint(4, refPoint); movPoint[0]=1; movPoint[1]=2; movPoint[2]=1; movSet->SetPoint(4, movPoint); //Point 5 refPoint[0]=3; refPoint[1]=3; refPoint[2]=0; refSet->SetPoint(5, refPoint); movPoint[0]=2; movPoint[1]=2; movPoint[2]=1; movSet->SetPoint(5, movPoint); //Point 6 refPoint[0]=0; refPoint[1]=3; refPoint[2]=3; refSet->SetPoint(6, refPoint); movPoint[0]=1; movPoint[1]=2; movPoint[2]=2; movSet->SetPoint(6, movPoint); //Point 7 refPoint[0]=3; refPoint[1]=3; refPoint[2]=3; refSet->SetPoint(7, refPoint); movPoint[0]=2; movPoint[1]=2; movPoint[2]=2; movSet->SetPoint(7, movPoint); mitk::NavigationDataLandmarkTransformFilter::Pointer myFREFilter = mitk::NavigationDataLandmarkTransformFilter::New(); myFREFilter->SetSourceLandmarks(refSet); myFREFilter->SetTargetLandmarks(movSet); bool success = false; try { MITK_INFO << "Testing printing of object: " << myFREFilter; success = true; } catch(...) { MITK_ERROR << "Error while printing the object"; } MITK_TEST_CONDITION_REQUIRED(success,"Testing printing object to a stream"); } static void TestFilterInvalidCases() { mitk::NavigationDataLandmarkTransformFilter::Pointer myFilter = mitk::NavigationDataLandmarkTransformFilter::New(); mitk::PointSet::Pointer refSet = mitk::PointSet::New(); mitk::PointSet::Pointer movSet = mitk::PointSet::New(); mitk::Point3D refPoint; mitk::Point3D movPoint; //Point 0 refPoint.Fill(0); refSet->SetPoint(0, refPoint); movPoint.Fill(1); movSet->SetPoint(0, movPoint); //Point 1 refPoint[0]=3; refPoint[1]=0; refPoint[2]=0; refSet->SetPoint(1, refPoint); movPoint[0]=2; movPoint[1]=1; movPoint[2]=1; movSet->SetPoint(1, movPoint); //Point 2 refPoint[0]=0; refPoint[1]=0; refPoint[2]=3; refSet->SetPoint(2, refPoint); movPoint[0]=1; movPoint[1]=1; movPoint[2]=2; movSet->SetPoint(2, movPoint); myFilter->SetUseICPInitialization(true); bool exceptionThrown = false; try { //should throw exception because less than 6 points myFilter->SetSourceLandmarks(refSet); myFilter->SetTargetLandmarks(movSet); } - catch(itk::ExceptionObject) + catch(itk::ExceptionObject&) { exceptionThrown = true; } MITK_TEST_CONDITION_REQUIRED(exceptionThrown,"Testing invalid number of landmarks when using ICP initialization.") } }; /**Documentation * test for the class "NavigationDataLandmarkTransformFilter". */ int mitkNavigationDataLandmarkTransformFilterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataLandmarkTransformFilter") mitkNavigationDataLandmarkTransformFilterTestClass::TestInstantiation(); mitkNavigationDataLandmarkTransformFilterTestClass::TestFilter(); mitkNavigationDataLandmarkTransformFilterTestClass::TestPrintSelfMethod(); mitkNavigationDataLandmarkTransformFilterTestClass::TestFilterInvalidCases(); // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataSequentialPlayerTest.cpp b/Modules/IGT/Testing/mitkNavigationDataSequentialPlayerTest.cpp index efdcce7a28..7c7c6f2b45 100644 --- a/Modules/IGT/Testing/mitkNavigationDataSequentialPlayerTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataSequentialPlayerTest.cpp @@ -1,175 +1,175 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkTestingMacros.h" #include #include #include #include //foe exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" class mitkNavigationDataSequentialPlayerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkNavigationDataSequentialPlayerTestSuite); MITK_TEST(TestStandardWorkflow); MITK_TEST(TestRestartWithNewNavigationDataSet); MITK_TEST(TestGoToSnapshotException); MITK_TEST(TestDoubleUpdate); CPPUNIT_TEST_SUITE_END(); private: /** Members used inside the different test methods. All members are initialized via setUp().*/ mitk::NavigationDataSet::Pointer NavigationDataSet; mitk::NavigationDataSequentialPlayer::Pointer player; public: void setUp() override{ player = mitk::NavigationDataSequentialPlayer::New(); std::string file = GetTestDataFilePath("IGT-Data/NavigationDataTestData_2ToolsDouble.xml"); NavigationDataSet = dynamic_cast (mitk::IOUtil::Load(file)[0].GetPointer()); } void tearDown() override { } bool runLoop() { player->Update(); mitk::NavigationData::Pointer nd0; mitk::NavigationData::Pointer nd1; for(unsigned int i=0; iGetNumberOfSnapshots(); ++i) { nd0 = player->GetOutput(0); nd1 = player->GetOutput(1); // test some values if(nd0.IsNull() || nd1.IsNull()) return false; //Compare data mitk::NavigationData::Pointer ref0 = NavigationDataSet->GetNavigationDataForIndex(i,0); mitk::NavigationData::Pointer ref1 = NavigationDataSet->GetNavigationDataForIndex(i,1); if (!(ref0->GetOrientation().as_vector() == nd0->GetOrientation().as_vector())) {return false;} if (!(ref1->GetOrientation().as_vector() == nd1->GetOrientation().as_vector())) {return false;} if (!(ref0->GetPosition().GetVnlVector() == nd0->GetPosition().GetVnlVector())) {return false;} if (!(ref1->GetPosition().GetVnlVector() == nd1->GetPosition().GetVnlVector())) {return false;} // Goto next Snapshot player->GoToNextSnapshot(); } return true; } void TestStandardWorkflow() { // Set NavigationDatas for player player->SetNavigationDataSet(NavigationDataSet); MITK_TEST_CONDITION(player->GetNumberOfSnapshots() == 3,"Testing if player reports correct number of Snapshots"); MITK_TEST_CONDITION(player->GetNumberOfIndexedOutputs() == 2,"Testing number of outputs"); //rest repeat player->SetRepeat(true); MITK_TEST_CONDITION(runLoop(),"Testing first run."); MITK_TEST_CONDITION(runLoop(),"Testing second run."); //repeat is on should work a second time // now test the go to snapshot function player->GoToSnapshot(2); mitk::NavigationData::Pointer nd1 = player->GetOutput(1); mitk::NavigationData::Pointer ref1 = NavigationDataSet->GetNavigationDataForIndex(2,1); MITK_TEST_CONDITION(ref1->GetPosition().GetVnlVector() == nd1->GetPosition().GetVnlVector(), "Testing GoToSnapshot() [1]"); //MITK_TEST_OUTPUT( << "Reference:" << ref1->GetPosition().GetVnlVector() << "\tObserved: " << nd1->GetPosition().GetVnlVector()); player->GoToSnapshot(0); mitk::NavigationData::Pointer nd0 = player->GetOutput(); mitk::NavigationData::Pointer ref0 = NavigationDataSet->GetNavigationDataForIndex(0,0); MITK_TEST_CONDITION(ref0->GetOrientation().as_vector() == nd0->GetOrientation().as_vector(), "Testing GoToSnapshot() [2]"); //MITK_TEST_OUTPUT( << "Reference" << ref0->GetPosition().GetVnlVector() << "\tObserved:" <GetOrientation().as_vector() ); } void TestRestartWithNewNavigationDataSet() { player->SetNavigationDataSet(NavigationDataSet); mitk::NavigationData::PositionType nd1 = player->GetOutput(0)->GetPosition(); player->SetNavigationDataSet(NavigationDataSet); mitk::NavigationData::PositionType nd2 = player->GetOutput(0)->GetPosition(); MITK_TEST_CONDITION(nd1 == nd2, "First output must be the same after setting same navigation data again."); // setting new NavigationDataSet with different tool count should result in an exception std::string file = GetTestDataFilePath("IGT-Data/NavigationDataTestData.xml"); mitk::NavigationDataSet::Pointer dataset = dynamic_cast (mitk::IOUtil::Load(file)[0].GetPointer()); MITK_TEST_FOR_EXCEPTION(mitk::IGTException, player->SetNavigationDataSet(dataset)); } void TestGoToSnapshotException() { //testing GoToSnapShot for exception mitk::NavigationDataSequentialPlayer::Pointer myTestPlayer2 = mitk::NavigationDataSequentialPlayer::New(); std::string file = GetTestDataFilePath("IGT-Data/NavigationDataTestData_2Tools.xml"); mitk::NavigationDataSet::Pointer dataset = dynamic_cast (mitk::IOUtil::Load(file)[0].GetPointer()); myTestPlayer2->SetNavigationDataSet(dataset); bool exceptionThrown2=false; try { unsigned int invalidSnapshot = 1000; myTestPlayer2->GoToSnapshot(invalidSnapshot); } - catch(mitk::IGTException) + catch(mitk::IGTException&) { exceptionThrown2=true; } MITK_TEST_CONDITION(exceptionThrown2, "Testing if exception is thrown when GoToSnapShot method is called with an index that doesn't exist."); } void TestDoubleUpdate() { //std::string file = GetTestDataFilePath("IGT-Data/NavigationDataTestData_2Tools.xml"); //mitk::NavigationDataReaderXML::Pointer reader = mitk::NavigationDataReaderXML::New(); //player->SetNavigationDataSet(reader->Read(file)); player->SetNavigationDataSet(NavigationDataSet); player->Update(); mitk::Quaternion nd1Orientation = player->GetOutput()->GetOrientation(); player->Update(); mitk::Quaternion nd2Orientation = player->GetOutput()->GetOrientation(); MITK_TEST_CONDITION(nd1Orientation.as_vector() == nd2Orientation.as_vector(), "Output must be the same no matter if Update() was called between."); MITK_TEST_CONDITION(player->GoToNextSnapshot(), "There must be a next snapshot available."); player->Update(); mitk::Quaternion nd3Orientation = player->GetOutput()->GetOrientation(); MITK_TEST_CONDITION(nd1Orientation.as_vector() != nd3Orientation.as_vector(), "Output must be different if GoToNextSnapshot() was called between."); } }; MITK_TEST_SUITE_REGISTRATION(mitkNavigationDataSequentialPlayer) diff --git a/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterXMLTest.cpp b/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterXMLTest.cpp index db69bfda66..8a5fe804f9 100644 --- a/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterXMLTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataSetReaderWriterXMLTest.cpp @@ -1,136 +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. ===================================================================*/ //testing headers //#include #include #include #include #include #include #include #include #include #include #include #include #include //for exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" class mitkNavigationDataSetReaderWriterXMLTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkNavigationDataSetReaderWriterXMLTestSuite); MITK_TEST(TestCompareFunction); MITK_TEST(TestReadWrite); MITK_TEST(TestSetXMLStringException); CPPUNIT_TEST_SUITE_END(); private: std::string pathRead; std::string pathWrite; std::string pathWrong; mitk::NavigationDataSet::Pointer set; public: void setUp() override { pathRead = GetTestDataFilePath("IGT-Data/RecordedNavigationData.xml"); pathWrite = pathRead; pathWrite.insert(pathWrite.end()-4,'2');;//Insert 2: IGT-Data/NavigationDataSet2.xml std::ifstream FileTest(pathWrite.c_str()); if(FileTest){ - //remove file if it already exists. TODO: Löschen funktioniert nicht!!!! xxxxxxxxxxxxxxxx + //remove file if it already exists. TODO: Loeschen funktioniert nicht!!!! xxxxxxxxxxxxxxxx FileTest.close(); std::remove(pathWrite.c_str()); } pathWrong = GetTestDataFilePath("IGT-Data/NavigationDataTestData.xml"); } void tearDown() override { } void TestReadWrite() { // Aim is to read an xml into a pointset, write that xml again, and compare the output set = dynamic_cast (mitk::IOUtil::Load(pathRead)[0].GetPointer()); mitk::IOUtil::Save(set, pathWrite); //FIXME: Commented out, because test fails under linux. binary comparison of files is probably not the wa to go // See Bug 17775 //CPPUNIT_ASSERT_MESSAGE( "Testing if read/write cycle creates identical files", CompareFiles(pathRead, pathWrite)); remove(pathWrite.c_str()); } bool CompareFiles(std::string file1, std::string file2) { FILE* f1 = fopen (file1.c_str() , "r"); FILE* f2 = fopen (file2.c_str() , "r"); char buf1[10000]; char buf2[10000]; do { size_t r1 = fread(buf1, 1, 10000, f1); size_t r2 = fread(buf2, 1, 10000, f2); if (r1 != r2 || memcmp(buf1, buf2, r1)) { fclose(f1); fclose(f2); return false; // Files are not equal } } while (!feof(f1) && !feof(f2)); bool returnValue = feof(f1) && feof(f2); fclose(f1); fclose(f2); return returnValue; } void TestSetXMLStringException() { bool exceptionThrown3=false; try { std::string file = GetTestDataFilePath("IGT-Data/InvalidVersionNavigationDataTestData.xml"); mitk::NavigationDataSet::Pointer dataset = dynamic_cast (mitk::IOUtil::Load(file)[0].GetPointer()); } - catch(mitk::Exception) + catch(mitk::Exception&) { exceptionThrown3=true; } MITK_TEST_CONDITION(exceptionThrown3, "Reading an invalid XML string and expecting a exception"); } void TestCompareFunction() { CPPUNIT_ASSERT_MESSAGE("Asserting that compare function for files works correctly - Positive Test", CompareFiles(pathRead, pathRead)); CPPUNIT_ASSERT_MESSAGE("Asserting that compare function for files works correctly - Negative Test", ! CompareFiles(pathRead, pathWrong) ); } }; MITK_TEST_SUITE_REGISTRATION(mitkNavigationDataSetReaderWriterXML) diff --git a/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp b/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp index de5a9fcc2c..ea477e3e27 100644 --- a/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataSourceTest.cpp @@ -1,175 +1,175 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNavigationDataSource.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" /**Documentation * \brief test class that only adds a public New() method to NavigationDataSource, so that it can be tested * */ class MyNavigationDataSourceTest : public mitk::NavigationDataSource { public: mitkClassMacro(MyNavigationDataSourceTest, mitk::NavigationDataSource); itkFactorylessNewMacro(Self) itkCloneMacro(Self) void CreateOutput() { this->SetNumberOfIndexedOutputs(1); this->SetNthOutput(0, this->MakeOutput(0)); }; }; /** Class that holds static test methods to structure the test. */ class mitkNavigationDataSourceTestClass { public: static void TestInstantiation() { // let's create an object of our class MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(), "Testing instantiation"); // testing create outputs MITK_TEST_CONDITION(myFilter->GetNumberOfInputs() == 0, "testing initial number of inputs"); MITK_TEST_CONDITION(myFilter->GetNumberOfOutputs() == 0, "testing initial number of outputs"); myFilter->CreateOutput(); MITK_TEST_CONDITION(myFilter->GetNumberOfOutputs() == 1, "testing SetNumberOfOutputs() and MakeOutput()"); MITK_TEST_CONDITION(dynamic_cast(myFilter->GetOutput()) != nullptr, "test GetOutput() returning valid output object"); } static void TestMethodsNormalCases() { //create and initialize test objects MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); myFilter->CreateOutput(); mitk::NavigationData::PositionType initialPos; mitk::FillVector3D(initialPos, 1.0, 2.0, 3.0); mitk::NavigationData::OrientationType initialOri(0.1, 0.2, 0.3, 0.4); mitk::ScalarType initialError(22.22); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); //test method graft MITK_TEST_OUTPUT(<< "testing Graftoutput()"); myFilter->GraftOutput(nd1); mitk::NavigationData::Pointer out = myFilter->GetOutput(); MITK_TEST_CONDITION(out.GetPointer() != nd1.GetPointer(), "testing if output is same object as source of graft"); MITK_TEST_CONDITION(mitk::Equal(out->GetPosition(), nd1->GetPosition()),"testing position equality after graft") MITK_TEST_CONDITION(mitk::Equal(out->GetOrientation(), nd1->GetOrientation()),"testing orientation equality after graft") MITK_TEST_CONDITION((out->GetCovErrorMatrix() == nd1->GetCovErrorMatrix()),"testing error matrix equality after graft") MITK_TEST_CONDITION((out->IsDataValid() == nd1->IsDataValid()),"testing data valid equality after graft") MITK_TEST_CONDITION(mitk::Equal(out->GetIGTTimeStamp(), nd1->GetIGTTimeStamp()), "testing timestamp equality after graft"); //test method GetParameters() mitk::PropertyList::ConstPointer list = myFilter->GetParameters(); MITK_TEST_CONDITION(list.IsNotNull(), "testing GetParameters()"); } static void TestMethodsInvalidCases() { //test invalid call of methods MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); mitk::NavigationData::Pointer testOutput = myFilter->GetOutput(); MITK_TEST_CONDITION(testOutput.IsNull(), "testing GetOutput(int) before initialization"); testOutput = myFilter->GetOutput("test"); MITK_TEST_CONDITION(testOutput.IsNull(), "testing GetOutput(string) before initialization"); //test GetOutputIndex() with invalid output name myFilter->CreateOutput(); bool exceptionThrown=false; try { myFilter->GetOutputIndex("nonsense name"); } - catch(std::invalid_argument e) + catch(std::invalid_argument&) { exceptionThrown=true; } MITK_TEST_CONDITION(exceptionThrown,"Testing method GetOutputIndex with invalid navigation data name"); //test method GraftNthOutput with invalid index exceptionThrown=false; try { mitk::NavigationData::Pointer graftObject; myFilter->GraftNthOutput(100,graftObject); } - catch(itk::ExceptionObject e) + catch(itk::ExceptionObject&) { exceptionThrown=true; } MITK_TEST_CONDITION(exceptionThrown,"Testing method GraftNthOutput with invalid index"); } static void TestMicroserviceRegister() { MyNavigationDataSourceTest::Pointer myFilter = MyNavigationDataSourceTest::New(); myFilter->CreateOutput(); mitk::NavigationData::PositionType initialPos; mitk::FillVector3D(initialPos, 1.0, 2.0, 3.0); mitk::NavigationData::OrientationType initialOri(0.1, 0.2, 0.3, 0.4); mitk::ScalarType initialError(22.22); bool initialValid(true); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(initialPos); nd1->SetOrientation(initialOri); nd1->SetPositionAccuracy(initialError); nd1->SetDataValid(initialValid); myFilter->RegisterAsMicroservice(); MITK_TEST_CONDITION(myFilter->GetMicroserviceID()!="","Testing if microservice was registered successfully."); } static void TestMicroserviceAvailabilityAndUnregister() { //TODO: test if Microservice is available //TODO: remove Microservice //TODO: test if Microservice is not available any more } }; /**Documentation * test for the class "NavigationDataSource". */ int mitkNavigationDataSourceTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataSource"); mitkNavigationDataSourceTestClass::TestInstantiation(); mitkNavigationDataSourceTestClass::TestMethodsNormalCases(); mitkNavigationDataSourceTestClass::TestMethodsInvalidCases(); mitkNavigationDataSourceTestClass::TestMicroserviceRegister(); mitkNavigationDataSourceTestClass::TestMicroserviceAvailabilityAndUnregister(); // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataTest.cpp b/Modules/IGT/Testing/mitkNavigationDataTest.cpp index 8f1ee9bd87..ed581ef1ca 100644 --- a/Modules/IGT/Testing/mitkNavigationDataTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataTest.cpp @@ -1,624 +1,624 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkNavigationData.h" #include "mitkVector.h" #include #include using namespace mitk; /** * helper function which checks if the non position / orientation / covariance related members are all set to certain values */ static bool AreBasicNavigationMembersEqual(const NavigationData::Pointer nd, const bool dataValid, const NavigationData::TimeStampType timeStamp, const std::string name) { bool result = true; result = result && (nd->IsDataValid() == dataValid); result = result && (mitk::Equal(nd->GetIGTTimeStamp(), timeStamp)); result = result && (0 == name.compare(nd->GetName())); return result; } /** * helper function which checks if the basic members, meaning the members not related to position / orientation / covariance * are the same for two NavigationData objects. */ static bool AreBasicNavigationMembersEqual(const NavigationData::Pointer nd1, const NavigationData::Pointer nd2) { return AreBasicNavigationMembersEqual(nd1, nd2->IsDataValid(), nd2->GetIGTTimeStamp(), nd2->GetName()); } /** * Test if the NavigationData object nd has the correct settings for covariance matrix specific members. * * @param nd * @param hasPosition the desired value for the hasPosition member * @param hasOrientation the desired value for the hasOrientation member * @param covMatrix the covariance matrix nd should have * @return */ static bool AreCovarianceNavigationMembersEqual(const NavigationData::Pointer nd, bool hasPosition, bool hasOrientation, NavigationData::CovarianceMatrixType covMatrix) { bool result = true; result = result && (nd->GetHasPosition() == hasPosition); result = result && (nd->GetHasOrientation() == hasOrientation); result = result && (mitk::MatrixEqualElementWise(nd->GetCovErrorMatrix(), covMatrix)); return result; } /** * Checks if the covariance related members of the two NavigationData objects are the same * * @see AreCovarianceNavigationMembersEqual * * @param nd1 * @param nd2 * @return */ static bool AreCovarianceNavigationMembersEqual(const NavigationData::Pointer nd1, const NavigationData::Pointer nd2) { return AreCovarianceNavigationMembersEqual(nd1, nd2->GetHasPosition(), nd2->GetHasOrientation(), nd2->GetCovErrorMatrix()); } /** * Creates a fully set NavigationData object for testing purposes. * * @return a smartpointer to the object */ static mitk::NavigationData::Pointer GetTestData() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); nd->SetDataValid(true); nd->SetIGTTimeStamp(100.111); nd->SetHasPosition(false); nd->SetHasOrientation(false); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); nd->SetName("my NavigationData"); nd->SetPositionAccuracy(100.0); nd->SetOrientationAccuracy(10.0); return nd; } static void TestInstatiation() { // Test instantiation of NavigationData mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); MITK_TEST_CONDITION(nd.IsNotNull(),"Test instatiation"); } static void TestGetterSetter() { mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType p; mitk::FillVector3D(p, 44.4, 55.5, 66.66); nd->SetPosition(p); MITK_TEST_CONDITION(nd->GetPosition() == p, "Set-/GetPosition()"); mitk::NavigationData::OrientationType o(1.0, 2.0, 3.0, 4.0); nd->SetOrientation(o); MITK_TEST_CONDITION(nd->GetOrientation() == o, "Set-/GetOrientation()"); nd->SetDataValid(true); MITK_TEST_CONDITION(nd->IsDataValid() == true, "Set-/IsDataValid()"); nd->SetIGTTimeStamp(100.111); MITK_TEST_CONDITION(mitk::Equal(nd->GetIGTTimeStamp(), 100.111), "Set-/GetIGTTimeStamp()"); nd->SetHasPosition(false); MITK_TEST_CONDITION(nd->GetHasPosition() == false, "Set-/GetHasPosition()"); nd->SetHasOrientation(false); MITK_TEST_CONDITION(nd->GetHasOrientation() == false, "Set-/GetHasOrientation()"); mitk::NavigationData::CovarianceMatrixType m; m.Fill(17.17); m(2, 2) = 1000.01; nd->SetCovErrorMatrix(m); MITK_TEST_CONDITION(nd->GetCovErrorMatrix() == m, "Set-/GetCovErrorMatrix()"); nd->SetName("my NavigationData"); MITK_TEST_CONDITION(std::string(nd->GetName()) == "my NavigationData", "Set-/GetName()"); nd->SetPositionAccuracy(100.0); mitk::NavigationData::CovarianceMatrixType result = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result(0, 0), 10000.0) && mitk::Equal(result(1, 1), 10000.0) && mitk::Equal(result(2, 2), 10000.0), "SetPositionAccuracy()"); nd->SetOrientationAccuracy(10.0); mitk::NavigationData::CovarianceMatrixType result2 = nd->GetCovErrorMatrix(); MITK_TEST_CONDITION(mitk::Equal(result2(3, 3), 100.0) && mitk::Equal(result2(4, 4), 100.0) && mitk::Equal(result2(5, 5), 100.0), "SetOrientationAccuracy()"); } static void TestGraft() { //create test data mitk::NavigationData::Pointer nd = GetTestData(); mitk::NavigationData::Pointer graftedCopy = mitk::NavigationData::New(); graftedCopy->Graft(nd); bool graftIsEqual = (nd->GetPosition() == graftedCopy->GetPosition()) && (nd->GetOrientation() == graftedCopy->GetOrientation()) && AreCovarianceNavigationMembersEqual(nd, graftedCopy) && AreBasicNavigationMembersEqual(nd, graftedCopy); MITK_TEST_CONDITION(graftIsEqual, "Graft() produces equal NavigationData object"); } static void TestPrintSelf() { mitk::NavigationData::Pointer nd = GetTestData(); itk::Indent myIndent = itk::Indent(); MITK_TEST_OUTPUT(<<"Testing method PrintSelf(), method output will follow:"); bool success = true; try { nd->PrintSelf(std::cout,myIndent); } catch(...) { success = false; } MITK_TEST_CONDITION(success, "Testing method PrintSelf()."); } static void TestWrongInputs() { mitk::NavigationData::Pointer nd = GetTestData(); // Test CopyInformation bool success = false; try { nd->CopyInformation(nullptr); } - catch(itk::ExceptionObject e) + catch(itk::ExceptionObject&) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method CopyInformation."); // Test Graft success = false; try { nd->Graft(nullptr); } - catch(itk::ExceptionObject e) + catch(itk::ExceptionObject&) { success = true; } MITK_TEST_CONDITION(success, "Testing wrong input for method Graft."); } static mitk::Quaternion quaternion; static mitk::Quaternion quaternion_realistic; static mitk::Vector3D offsetVector; static mitk::Point3D offsetPoint; static mitk::Matrix3D rotation; static mitk::Quaternion quaternion2; static mitk::Vector3D offsetVector2; static mitk::Point3D offsetPoint2; static mitk::Matrix3D rotation2; static mitk::Point3D point; /** * Helper method setting up data required for tests (like points which shall be transformed by the NavigationData). */ static void SetupNaviDataTests() { // set rotation matrix to /* * 0 -1 0 * 1 0 0 * 0 0 1 */ rotation.Fill(0); rotation[0][1] = -1; rotation[1][0] = 1; rotation[2][2] = 1; // set quaternion to quaternion equivalent // values calculated with javascript at // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ quaternion = mitk::Quaternion(0, 0, 0.7071067811865475, 0.7071067811865476); // a more realistic quaternion from real tracking data quaternion_realistic = mitk::Quaternion(-0.57747,0.225593,0.366371,0.693933); // set offset to some value. Some tests need vectors, offers points. double offsetArray[3] = {1.0,2.0,3.123456}; offsetVector = offsetArray; offsetPoint = offsetArray; /***** Second set of data for compose tests ****/ // set rotation2 matrix to /* * 1 0 0 * 0 0 -1 * 0 1 0 */ rotation2.Fill(0); rotation2[0][0] = 1; rotation2[1][2] = -1; rotation2[2][1] = 1; quaternion2 = mitk::Quaternion(0.7071067811865475, 0, 0, 0.7071067811865476); mitk::ScalarType offsetArray2[3] = {1, 0, 0}; offsetVector2 = offsetArray2; offsetPoint2 = offsetArray2; /***** Create a point to be transformed *****/ mitk::ScalarType pointArray[] = {1.0, 3.0, 5.0}; point = pointArray; } /** * Helper method, which creates a NavigationData object using the data created in SetupNaviDataTests() */ static mitk::NavigationData::Pointer CreateNavidata(mitk::Quaternion quaternion, mitk::Point3D offset) { mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(); navigationData->SetOrientation(quaternion); navigationData->SetPosition(offset); return navigationData; } /** * Helper method which creates an affine transformation only composed by a rotation and a translation (no scalings and the likes). * * @param rotationMatrix * @param offset * @return */ static mitk::AffineTransform3D::Pointer CreateAffineTransform(mitk::Matrix3D rotationMatrix, mitk::Vector3D offset) { mitk::AffineTransform3D::Pointer affineTransform3D = mitk::AffineTransform3D::New(); affineTransform3D->SetOffset(offset); affineTransform3D->SetMatrix(rotationMatrix); return affineTransform3D; } /** * Test if NavigationData::GetInverse returns the correct inverse */ /*static void TestInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndInverse = nd->GetInverse(); // calculate expected inverted position vector: b2 = -A2b1 // for -A2b1 we need vnl_vectors. vnl_vector_fixed b1; for (int i = 0; i < 3; ++i) { b1[i] = nd->GetPosition()[i]; } vnl_vector_fixed b2; b2 = -(ndInverse->GetOrientation().rotate(b1)); // now copy result back into our mitk::Point3D mitk::Point3D invertedPosition; for (int i = 0; i < 3; ++i) { invertedPosition[i] = b2[i]; } MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation().inverse(), ndInverse->GetOrientation()),"Testing GetInverse: orientation inverted"); MITK_TEST_CONDITION(mitk::Equal(invertedPosition, ndInverse->GetPosition()), "Testing GetInverse: position inverted"); bool otherFlagsOk = AreBasicNavigationMembersEqual(nd, ndInverse) && AreCovarianceNavigationMembersEqual(ndInverse, false, false, nd->GetCovErrorMatrix()); // covariance update mechanism not yet implemented, thus validities are set to false. MITK_TEST_CONDITION(otherFlagsOk, "Testing GetInverse: other flags are same"); //######################################################################################## //################### Second test with more realistic quaternion ######################### //######################################################################################## //just copy data to be real sure that it is not overwritten during the test mitk::Quaternion referenceQuaternion; referenceQuaternion[0] = quaternion_realistic[0]; referenceQuaternion[1] = quaternion_realistic[1]; referenceQuaternion[2] = quaternion_realistic[2]; referenceQuaternion[3] = quaternion_realistic[3]; mitk::Point3D referencePoint; referencePoint[0] = offsetPoint[0]; referencePoint[1] = offsetPoint[1]; referencePoint[2] = offsetPoint[2]; referencePoint[3] = offsetPoint[3]; mitk::NavigationData::Pointer nd2 = CreateNavidata(quaternion_realistic, offsetPoint); mitk::NavigationData::Pointer ndInverse2 = nd2->GetInverse(); MITK_TEST_CONDITION(mitk::Equal(nd2->GetOrientation(),referenceQuaternion),"Testing if the method GetInverse() modifies the data which should never happen!"); MITK_TEST_CONDITION(mitk::Equal(ndInverse2->GetOrientation(),referenceQuaternion.inverse()),"Testing if the Qrientation was inverted correctly with the realistic quaternion"); }*/ /** * Test if the original orientation and position are retained after inverting two times. */ static void TestDoubleInverse() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer ndDoubleInverse = nd->GetInverse()->GetInverse(); MITK_TEST_CONDITION(mitk::Equal(nd->GetOrientation(), ndDoubleInverse->GetOrientation()),"Testing GetInverse double application: orientation preserved"); MITK_TEST_CONDITION(mitk::Equal(nd->GetPosition(), ndDoubleInverse->GetPosition()), "Testing GetInverse double application: position preserved"); } /** * Tests if NavigationData::GetInverse throws an error if the NavigationData has no inverse * (e.g. after it is initialized, no rotation is stored -> the transformation cannot be inverted). */ static void TestInverseError() { // initialize empty NavigationData (quaternion is zeroed) mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::Quaternion quaternion; quaternion.fill(0); nd->SetOrientation(quaternion); MITK_TEST_FOR_EXCEPTION(mitk::Exception, nd->GetInverse()); } /** * Tests if NavigationData::TransformPoint works. */ static void TestTransform() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); point = navigationData->TransformPoint(point); mitk::ScalarType resultingPointArray[] = {-2, 3, 8.123456}; mitk::Point3D resultingPoint = resultingPointArray; MITK_TEST_CONDITION(mitk::Equal(resultingPoint, point), "Testing point transformation"); } /** * Tests if the construction of a NavigationData object from an * affine transformation which is only composed of a rotation and translation works. */ static void TestAffineConstructor() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); MITK_TEST_CONDITION(AreBasicNavigationMembersEqual(navigationData, true, 0.0, ""), "Testing affine constructor: dataValid, timeStamp and name have been initialized to default values"); NavigationData::CovarianceMatrixType covMatrix; // empty covariance matrix MITK_TEST_CONDITION(AreCovarianceNavigationMembersEqual(navigationData, true, true, covMatrix), "Testing affine constructor: covariance matrix values have been correctly initialized"); // TODO: discuss with Alfred // why this is the desired initialization of the covariance information. MITK_TEST_CONDITION(mitk::Equal(navigationData->GetPosition(), offsetPoint), "Testing affine constructor: offset"); MITK_TEST_CONDITION(mitk::Equal(navigationData->GetOrientation(), quaternion), "Testing affine constructor: quaternion"); } /** * Tests if the construction of a NavigationData object throws an error when constructing from an * affine transformation which is orthogonal. */ static void TestAffineConstructorErrorTransposedNotInverse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[1][0] = 2; // this matrix has determinant = 1 (triangular matrix with ones in diagonal) but transposed != inverse mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::NavigationData::New(affineTransform3D)); } /** * Tests if the construction of a NavigationData object throws an error when constructing from an * affine transformation which is not normal. */ static void TestAffineConstructorErrorDeterminantNonEqualOne() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); MITK_TEST_FOR_EXCEPTION(mitk::Exception, mitk::NavigationData::New(affineTransform3D)); } /** * Tests if the error suppression mechanism works if a NavigationData object is created from a * invalid affine transformation (one that is not only rotation and translation). */ static void TestAffineConstructorErrorCheckingFalse() { SetupNaviDataTests(); rotation.SetIdentity(); rotation[0][0] = 2; // determinant for diagonal matrices is product of diagonal elements => det = 2 mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); bool exceptionSuppressed = true; try { mitk::NavigationData::New(affineTransform3D, false); } catch (mitk::Exception&) { exceptionSuppressed = false; } MITK_TEST_CONDITION(exceptionSuppressed, "Test affine constructor: exception can be suppressed.") } /** * Test if NavigationData::GetAffineTransform3D() returns the correct affine transformation. */ static void TestAffineGetter() { SetupNaviDataTests(); mitk::NavigationData::Pointer navigationData = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer affineTransform = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform->GetOffset(), offsetVector), "Testing AffineTransform3D getter: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform->GetMatrix(), rotation), "Testing AffineTransform3D getter: rotation"); } /** * This test tests the complete chain from affineTransform -> NavigationData -> affineTransform */ static void TestAffineToNaviDataToAffine() { SetupNaviDataTests(); mitk::AffineTransform3D::Pointer affineTransform3D = CreateAffineTransform(rotation, offsetVector); // there and back again: affineTransform -> NavigationData -> affineTransform mitk::NavigationData::Pointer navigationData = mitk::NavigationData::New(affineTransform3D); mitk::AffineTransform3D::Pointer affineTransform3D_2; affineTransform3D_2 = navigationData->GetAffineTransform3D(); MITK_TEST_CONDITION(mitk::Equal(affineTransform3D->GetOffset(), affineTransform3D_2->GetOffset()), "Testing affine -> navidata -> affine chain: offset"); MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(affineTransform3D->GetMatrix(), affineTransform3D_2->GetMatrix()), "Testing affine -> navidata -> affine chain: rotation"); } static void TestCompose(bool pre = false) { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::AffineTransform3D::Pointer at = CreateAffineTransform(rotation, offsetVector); // second transform for composition mitk::NavigationData::Pointer nd2 = CreateNavidata(quaternion2, offsetPoint2); mitk::AffineTransform3D::Pointer at2 = CreateAffineTransform(rotation2, offsetVector2); // save point for affinetransform mitk::Point3D point2 = point; nd->Compose(nd2, pre); point = nd->TransformPoint(point); at->Compose(at2, pre); point2 = at->TransformPoint(point2); MITK_TEST_CONDITION(mitk::Equal(point, point2), "Compose pre = " << pre << ": composition works "); bool covarianceValidityReset = !nd->GetHasOrientation() && !nd->GetHasPosition(); MITK_TEST_CONDITION(covarianceValidityReset, "Compose pre = " << pre << ": covariance validities reset because not implemented yet."); } static void TestReverseCompose() { TestCompose(true); } /** * Tests the clone method. */ static void TestClone() { SetupNaviDataTests(); mitk::NavigationData::Pointer nd = CreateNavidata(quaternion, offsetPoint); mitk::NavigationData::Pointer myClone = nd->Clone(); MITK_TEST_CONDITION(mitk::Equal(*nd,*myClone,mitk::eps,true), "Test if clone is equal to original object."); //change clone, original object should not change mitk::Point3D myPoint; mitk::FillVector3D(myPoint,121,32132,433); myClone->SetPosition(myPoint); MITK_TEST_CONDITION(!mitk::Equal(*nd,*myClone), "Test if clone could be modified without changing the original object."); } /** * This function is testing the Class mitk::NavigationData. For most tests we would need the MicronTracker hardware, so only a few * simple tests, which can run without the hardware are implemented yet (2009, January, 23rd). As soon as there is a working * concept to test the tracking classes which are very close to the hardware on all systems more tests are needed here. */ int mitkNavigationDataTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationData"); TestInstatiation(); TestGetterSetter(); TestGraft(); TestPrintSelf(); TestWrongInputs(); TestAffineConstructor(); TestAffineConstructorErrorDeterminantNonEqualOne(); TestAffineConstructorErrorTransposedNotInverse(); TestAffineConstructorErrorCheckingFalse(); TestAffineGetter(); TestAffineToNaviDataToAffine(); TestTransform(); //TestInverse(); Fails under MAC, see bug 18306 TestDoubleInverse(); TestInverseError(); TestCompose(); TestReverseCompose(); TestClone(); MITK_TEST_END(); } diff --git a/Modules/IGT/Testing/mitkNavigationDataToNavigationDataFilterTest.cpp b/Modules/IGT/Testing/mitkNavigationDataToNavigationDataFilterTest.cpp index 33b8ca2bd7..2890bb539c 100644 --- a/Modules/IGT/Testing/mitkNavigationDataToNavigationDataFilterTest.cpp +++ b/Modules/IGT/Testing/mitkNavigationDataToNavigationDataFilterTest.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 "mitkNavigationDataToNavigationDataFilter.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" /**Documentation * \brief test class to be able to instantiate the normally abstract (private constructor) mitk::NavigationDataToNavigationDataFilter */ class NavigationDataToNavigationDataFilterTestClass : public mitk::NavigationDataToNavigationDataFilter { public: mitkClassMacro(NavigationDataToNavigationDataFilterTestClass, NavigationDataToNavigationDataFilter); itkFactorylessNewMacro(Self) itkCloneMacro(Self) }; /**Documentation * test for the class "NavigationDataToNavigationDataFilter". */ int mitkNavigationDataToNavigationDataFilterTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("NavigationDataToNavigationDataFilter") // let's create an object of our class mitk::NavigationDataToNavigationDataFilter::Pointer myFilter = NavigationDataToNavigationDataFilterTestClass::New().GetPointer(); // create testing subclass, but treat it like the real NavigationDataToNavigationDataFilter MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */ mitk::NavigationData::PositionType initialPos; mitk::FillVector3D(initialPos, 1.0, 2.0, 3.0); mitk::NavigationData::OrientationType initialOri(0.1, 0.2, 0.3, 0.4); mitk::ScalarType initialError(22.22); bool initialValid(true); mitk::NavigationData::Pointer nd0 = mitk::NavigationData::New(); nd0->SetPosition(initialPos); nd0->SetOrientation(initialOri); nd0->SetPositionAccuracy(initialError); nd0->SetDataValid(initialValid); nd0->SetName("testName"); MITK_TEST_CONDITION(myFilter->GetOutput() != nullptr, "testing GetOutput()"); MITK_TEST_CONDITION(myFilter->GetInput() == nullptr, "testing GetInput() without SetInput()"); MITK_TEST_CONDITION(myFilter->GetInput(0) == nullptr, "testing GetInput(0) without SetInput()"); myFilter->SetInput(nd0); MITK_TEST_CONDITION(myFilter->GetInput() == nd0, "testing Set-/GetInput()"); MITK_TEST_CONDITION(myFilter->GetInput(0) == nd0, "testing Set-/GetInput(0)"); MITK_TEST_CONDITION(myFilter->GetOutput() != nullptr, "testing GetOutput() after SetInput()"); MITK_TEST_CONDITION(myFilter->GetOutput() != nullptr, "testing GetOutput() after SetInput()"); MITK_TEST_CONDITION(myFilter->GetOutput() != nd0, "testing GetOutput() different object than input"); // check getInput() string input MITK_TEST_CONDITION(myFilter->GetInput("invalidName") == nullptr, "testing GetInput(string) invalid string"); MITK_TEST_CONDITION(myFilter->GetInput("testName") == nd0, "testing GetInput(string) valid string"); // check getInputIndex() string input bool throwsException = false; try { myFilter->GetInputIndex("invalidName"); } - catch(std::invalid_argument e) { + catch(std::invalid_argument&) { throwsException = true; } MITK_TEST_CONDITION_REQUIRED(throwsException, "testing GetInputIndex(string) invalid string"); MITK_TEST_CONDITION(myFilter->GetInputIndex("testName") == 0, "testing GetInputIndex(string) valid string"); mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->Graft(nd0); nd1->SetDataValid(false); myFilter->SetInput(1, nd1); MITK_TEST_CONDITION(myFilter->GetInput(1) == nd1, "testing Set-/GetInput(1)"); MITK_TEST_CONDITION(myFilter->GetInput(0) == nd0, "testing Set-/GetInput(0) again"); MITK_TEST_CONDITION(myFilter->GetOutput(1) != nullptr, "testing GetOutput() after SetInput()"); MITK_TEST_CONDITION(myFilter->GetOutput() != myFilter->GetOutput(1), "testing GetOutput() different object than GetOutput(1)"); myFilter->SetInput(10, nd1); MITK_TEST_CONDITION(myFilter->GetNumberOfIndexedInputs() == 11, "testing SetInput(10) produces 11 outputs"); MITK_TEST_CONDITION(myFilter->GetInput(10) == nd1, "testing Set-/GetInput(10)"); myFilter->SetInput(10, nullptr); MITK_TEST_CONDITION(myFilter->GetNumberOfIndexedInputs() == 10, "testing SetInput(10, nullptr) removes output with index 10"); myFilter->SetInput(1, nullptr); MITK_TEST_CONDITION(myFilter->GetNumberOfIndexedInputs() == 10, "testing SetInput(1, nullptr) does not change number of outputs"); // always end with this! MITK_TEST_END(); } diff --git a/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp b/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp index 6fb9372270..18cb04bf57 100644 --- a/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp +++ b/Modules/IGTUI/Qmitk/QmitkIGTPlayerWidget.cpp @@ -1,568 +1,568 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkIGTPlayerWidget.h" //mitk headers #include "mitkTrackingTypes.h" #include #include #include #include #include #include #include #include #include //qt headers #include #include #include QmitkIGTPlayerWidget::QmitkIGTPlayerWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f), m_RealTimePlayer(mitk::NavigationDataPlayer::New()), m_SequentialPlayer(mitk::NavigationDataSequentialPlayer::New()), m_StartTime(-1.0), m_CurrentSequentialPointNumber(0), m_Controls(new Ui::QmitkIGTPlayerWidgetControls) { m_Controls->setupUi(this); m_PlayingTimer = new QTimer(this); // initialize update timer CreateConnections(); m_Controls->samplePositionHorizontalSlider->setVisible(false); this->ResetLCDNumbers(); // reset lcd numbers at start } QmitkIGTPlayerWidget::~QmitkIGTPlayerWidget() { m_PlayingTimer->stop(); delete m_Controls; } void QmitkIGTPlayerWidget::CreateConnections() { connect( (QObject*)(m_Controls->playPushButton), SIGNAL(clicked(bool)), this, SLOT(OnPlayButtonClicked(bool)) ); // play button connect( (QObject*)(m_PlayingTimer), SIGNAL(timeout()), this, SLOT(OnPlaying()) ); // update timer connect( (QObject*) (m_Controls->beginPushButton), SIGNAL(clicked()), this, SLOT(OnGoToBegin()) ); // reset player and go to begin connect( (QObject*) (m_Controls->stopPushButton), SIGNAL(clicked()), this, SLOT(OnGoToEnd()) ); // reset player // pass this widgets protected combobox signal to public signal connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); // pass this widgets protected checkbox signal to public signal connect( m_Controls->splineModeCheckBox, SIGNAL(toggled(bool)), this, SIGNAL(SignalSplineModeToggled(bool)) ); //connect( m_Controls->sequencialModeCheckBox, SIGNAL(toggled(bool)), this, SLOT(OnSequencialModeToggled(bool)) ); connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderPressed()), this, SLOT(OnSliderPressed()) ); connect( m_Controls->samplePositionHorizontalSlider, SIGNAL(sliderReleased()), this, SLOT(OnSliderReleased()) ); connect( m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonPressed()) ); } bool QmitkIGTPlayerWidget::IsTrajectoryInSplineMode() { return m_Controls->splineModeCheckBox->isChecked(); } bool QmitkIGTPlayerWidget::CheckInputFileValid() { QFile file(m_CmpFilename); // check if file exists if(!file.exists()) { QMessageBox::warning(nullptr, "IGTPlayer: Error", "No valid input file was loaded. Please load input file first!"); return false; } return true; } unsigned int QmitkIGTPlayerWidget::GetNumberOfTools() { unsigned int result = 0; if(this->GetCurrentPlaybackMode() == RealTimeMode) { if(m_RealTimePlayer.IsNotNull()) result = m_RealTimePlayer->GetNumberOfOutputs(); } else if(this->GetCurrentPlaybackMode() == SequentialMode) { if(m_SequentialPlayer.IsNotNull()) result = m_SequentialPlayer->GetNumberOfOutputs(); } // at the moment this works only if player is initialized return result; } void QmitkIGTPlayerWidget::SetUpdateRate(unsigned int msecs) { m_PlayingTimer->setInterval((int) msecs); // set update timer update rate } void QmitkIGTPlayerWidget::OnPlayButtonClicked(bool checked) { if ( ! checked ) { if ( this->GetCurrentPlaybackMode() == RealTimeMode ) { m_RealTimePlayer->StopPlaying(); } else if ( this->GetCurrentPlaybackMode() == SequentialMode ) { // m_SequentialPlayer-> } } if(CheckInputFileValid()) // no playing possible without valid input file { switch ( this->GetCurrentPlaybackMode() ) { case RealTimeMode: { break; } case SequentialMode: { break; } } PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; if(checked) // play { if( (isRealTimeMode && m_RealTimePlayer.IsNull()) || (isSequentialMode && m_SequentialPlayer.IsNull())) // start play { mitk::NavigationDataSet::Pointer navigationDataSet; try { navigationDataSet = dynamic_cast (mitk::IOUtil::Load(m_CmpFilename.toStdString())[0].GetPointer()); } - catch(mitk::IGTException) + catch(const mitk::IGTException&) { std::string errormessage = "Error during start playing. Invalid or wrong file?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } if(isRealTimeMode) { m_RealTimePlayer = mitk::NavigationDataPlayer::New(); m_RealTimePlayer->SetNavigationDataSet(navigationDataSet); try { m_RealTimePlayer->StartPlaying(); } - catch(mitk::IGTException) + catch(const mitk::IGTException&) { std::string errormessage = "Error during start playing. Invalid or wrong file?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } } else if(isSequentialMode) { m_SequentialPlayer = mitk::NavigationDataSequentialPlayer::New(); try { m_SequentialPlayer->SetNavigationDataSet(navigationDataSet); } - catch(mitk::IGTException) + catch(const mitk::IGTException&) { std::string errormessage = "Error during start playing. Invalid or wrong file type?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_Controls->playPushButton->setChecked(false); m_RealTimePlayer = nullptr; return; } m_Controls->samplePositionHorizontalSlider->setMinimum(0); m_Controls->samplePositionHorizontalSlider->setMaximum(m_SequentialPlayer->GetNumberOfSnapshots()); m_Controls->samplePositionHorizontalSlider->setEnabled(true); } m_PlayingTimer->start(100); emit SignalPlayingStarted(); } else // resume play { if(isRealTimeMode) m_RealTimePlayer->Resume(); m_PlayingTimer->start(100); emit SignalPlayingResumed(); } } else // pause { if(isRealTimeMode) m_RealTimePlayer->Pause(); m_PlayingTimer->stop(); emit SignalPlayingPaused(); } } else { m_Controls->playPushButton->setChecked(false); // uncheck play button if file unvalid } } QmitkIGTPlayerWidget::PlaybackMode QmitkIGTPlayerWidget::GetCurrentPlaybackMode() { /*if(m_Controls->sequencialModeCheckBox->isChecked()) return SequentialMode; else*/ return RealTimeMode; } QTimer* QmitkIGTPlayerWidget::GetPlayingTimer() { return m_PlayingTimer; } void QmitkIGTPlayerWidget::OnStopPlaying() { this->StopPlaying(); } void QmitkIGTPlayerWidget::StopPlaying() { m_PlayingTimer->stop(); emit SignalPlayingStopped(); if(m_RealTimePlayer.IsNotNull()) m_RealTimePlayer->StopPlaying(); m_StartTime = -1; // set starttime back m_CurrentSequentialPointNumber = 0; m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber); m_Controls->sampleLCDNumber->display(static_cast(m_CurrentSequentialPointNumber)); this->ResetLCDNumbers(); m_Controls->playPushButton->setChecked(false); // set play button unchecked } void QmitkIGTPlayerWidget::OnPlaying() { switch ( this->GetCurrentPlaybackMode() ) { case RealTimeMode: { if ( m_RealTimePlayer.IsNull() ) { return; } if ( m_StartTime < 0 ) { // get playback start time m_StartTime = m_RealTimePlayer->GetOutput()->GetTimeStamp(); } if( ! m_RealTimePlayer->IsAtEnd() ) { m_RealTimePlayer->Update(); // update player int msc = (int) (m_RealTimePlayer->GetOutput()->GetTimeStamp() - m_StartTime); // calculation for playing time display int ms = msc % 1000; msc = (msc - ms) / 1000; int s = msc % 60; int min = (msc-s) / 60; // set lcd numbers m_Controls->msecLCDNumber->display(ms); m_Controls->secLCDNumber->display(s); m_Controls->minLCDNumber->display(min); emit SignalPlayerUpdated(); // player successfully updated } else { this->StopPlaying(); // if player is at EOF } break; } case SequentialMode: { if ( m_SequentialPlayer.IsNull() ) { return; } if ( m_CurrentSequentialPointNumber < m_SequentialPlayer->GetNumberOfSnapshots() ) { m_SequentialPlayer->Update(); // update sequential player m_Controls->samplePositionHorizontalSlider->setSliderPosition(m_CurrentSequentialPointNumber++); // refresh slider position m_Controls->sampleLCDNumber->display(static_cast(m_CurrentSequentialPointNumber)); //for debugging purposes //std::cout << "Sample: " << m_CurrentSequentialPointNumber << " X: " << m_SequentialPlayer->GetOutput()->GetPosition()[0] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[1] << " Y: " << m_SequentialPlayer->GetOutput()->GetPosition()[2] << std::endl; emit SignalPlayerUpdated(); // player successfully updated } else { this->StopPlaying(); // if player is at EOF } break; } } } const std::vector QmitkIGTPlayerWidget::GetNavigationDatas() { std::vector navDatas; if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull()) { for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i) { navDatas.push_back(m_RealTimePlayer->GetOutput(i)); // push back current navigation data for each tool } } else if(this->GetCurrentPlaybackMode() == SequentialMode && m_SequentialPlayer.IsNotNull()) { for(unsigned int i=0; i < m_SequentialPlayer->GetNumberOfOutputs(); ++i) { navDatas.push_back(m_SequentialPlayer->GetOutput(i)); // push back current navigation data for each tool } } return navDatas; } const mitk::PointSet::Pointer QmitkIGTPlayerWidget::GetNavigationDatasPointSet() { mitk::PointSet::Pointer result = mitk::PointSet::New(); mitk::PointSet::PointType pointType; PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull())) { for(unsigned int i=0; i < m_RealTimePlayer->GetNumberOfOutputs(); ++i) { mitk::NavigationData::PositionType position; if(isRealTimeMode) position = m_RealTimePlayer->GetOutput(i)->GetPosition(); else if(isSequentialMode) position = m_SequentialPlayer->GetOutput(i)->GetPosition(); pointType[0] = position[0]; pointType[1] = position[1]; pointType[2] = position[2]; result->InsertPoint(i,pointType); // insert current ND as Pointtype in PointSet for return } } return result; } const mitk::PointSet::PointType QmitkIGTPlayerWidget::GetNavigationDataPoint(unsigned int index) { if( index > this->GetNumberOfTools() ) throw std::out_of_range("Tool Index out of range!"); PlaybackMode currentMode = this->GetCurrentPlaybackMode(); bool isRealTimeMode = currentMode == RealTimeMode; bool isSequentialMode = currentMode == SequentialMode; // create return PointType from current ND for tool index mitk::PointSet::PointType result; if( (isRealTimeMode && m_RealTimePlayer.IsNotNull()) || (isSequentialMode && m_SequentialPlayer.IsNotNull())) { mitk::NavigationData::PositionType position; if(isRealTimeMode) position = m_RealTimePlayer->GetOutput(index)->GetPosition(); else if(isSequentialMode) position = m_SequentialPlayer->GetOutput(index)->GetPosition(); result[0] = position[0]; result[1] = position[1]; result[2] = position[2]; } return result; } /*void QmitkIGTPlayerWidget::SetRealTimePlayer( mitk::NavigationDataPlayer::Pointer player ) { if(player.IsNotNull()) m_RealTimePlayer = player; } void QmitkIGTPlayerWidget::SetSequentialPlayer( mitk::NavigationDataSequentialPlayer::Pointer player ) { if(player.IsNotNull()) m_SequentialPlayer = player; }*/ void QmitkIGTPlayerWidget::OnOpenFileButtonPressed() { QString filename = QFileDialog::getOpenFileName(this, "Load tracking data", QmitkIGTCommonHelper::GetLastFileLoadPath(),"XML files (*.xml)"); QFile file(filename); QmitkIGTCommonHelper::SetLastFileLoadPathByFileName(filename); // if something went wrong or user pressed cancel in the save dialog if ( filename.isEmpty() || ! file.exists() ) { QMessageBox::warning(nullptr, "Warning", QString("Please enter valid path. Using previous path again.")); return; } m_CmpFilename = filename; this->OnGoToEnd(); /// stops playing and resets lcd numbers m_Controls->m_ActiveFileLabel->setText(m_CmpFilename); emit SignalInputFileChanged(); mitk::NavigationDataSet::Pointer navigationDataSet = dynamic_cast (mitk::IOUtil::Load(m_CmpFilename.toStdString())[0].GetPointer()); m_RealTimePlayer->SetNavigationDataSet(navigationDataSet); m_SequentialPlayer->SetNavigationDataSet(navigationDataSet); m_Controls->m_PlayerControlsGroupBox->setEnabled(true); } void QmitkIGTPlayerWidget::OnGoToEnd() { this->StopPlaying(); // reset lcd numbers this->ResetLCDNumbers(); } void QmitkIGTPlayerWidget::OnGoToBegin() { // stop player manual so no PlayingStopped() m_PlayingTimer->stop(); if(this->GetCurrentPlaybackMode() == RealTimeMode && m_RealTimePlayer.IsNotNull()) { m_RealTimePlayer->StopPlaying(); m_RealTimePlayer = nullptr; // set player to nullptr so it can be initialized again if playback is called afterwards } m_StartTime = -1; // set starttime back //reset view elements m_Controls->playPushButton->setChecked(false); this->ResetLCDNumbers(); } void QmitkIGTPlayerWidget::ResetLCDNumbers() { m_Controls->minLCDNumber->display(QString("00")); m_Controls->secLCDNumber->display(QString("00")); m_Controls->msecLCDNumber->display(QString("000")); } void QmitkIGTPlayerWidget::SetTrajectoryNames(const QStringList toolNames) { QComboBox* cBox = m_Controls->trajectorySelectComboBox; if(cBox->count() > 0) this->ClearTrajectorySelectCombobox(); // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); if(!toolNames.isEmpty()) m_Controls->trajectorySelectComboBox->insertItems(0, toolNames); // adding current tool names to combobox // reconnect after performed changes connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); } int QmitkIGTPlayerWidget::GetResolution() { return m_Controls->resolutionSpinBox->value(); // return currently selected trajectory resolution } void QmitkIGTPlayerWidget::ClearTrajectorySelectCombobox() { // before making changed to QComboBox it is recommended to disconnet it's SIGNALS and SLOTS disconnect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); m_Controls->trajectorySelectComboBox->clear(); // reconnect after performed changes connect( (QObject*) (m_Controls->trajectorySelectComboBox), SIGNAL(currentIndexChanged(int)), this, SIGNAL(SignalCurrentTrajectoryChanged(int)) ); } void QmitkIGTPlayerWidget::OnSequencialModeToggled(bool toggled) { this->StopPlaying(); // stop playing when mode is changed if(toggled) { m_Controls->samplePositionHorizontalSlider->setEnabled(true); // enable slider if sequential mode } else if(!toggled) { m_Controls->samplePositionHorizontalSlider->setSliderPosition(0); // set back and disable slider m_Controls->samplePositionHorizontalSlider->setDisabled(true); } } void QmitkIGTPlayerWidget::OnSliderReleased() { int currentSliderValue = m_Controls->samplePositionHorizontalSlider->value(); // current slider value selected through user movement if(currentSliderValue > static_cast(m_CurrentSequentialPointNumber)) // at the moment only forward scrolling is possible { auto snapshotNumber = static_cast(currentSliderValue); m_SequentialPlayer->GoToSnapshot(snapshotNumber); // move player to selected snapshot m_CurrentSequentialPointNumber = currentSliderValue; m_Controls->sampleLCDNumber->display(currentSliderValue); // update lcdnumber in widget } else m_Controls->samplePositionHorizontalSlider->setValue(m_CurrentSequentialPointNumber); } void QmitkIGTPlayerWidget::OnSliderPressed() { if(m_Controls->playPushButton->isChecked()) // check if widget is playing m_Controls->playPushButton->click(); // perform click to pause the play } diff --git a/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.cpp b/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.cpp index 57ff3860c8..cce3c42af6 100644 --- a/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.cpp +++ b/Modules/IGTUI/Qmitk/QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.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. ===================================================================*/ #include "QmitkTrackingDeviceConfigurationWidgetScanPortsWorker.h" #include #include #include #include "mitkUnspecifiedTrackingTypeInformation.h" void QmitkTrackingDeviceConfigurationWidgetScanPortsWorker::ScanPortsThreadFunc() { int Port = -1; int PortType = -1; QString result = "
Found Devices:"; int resultSize = result.size(); //remember size of result: if it stays the same no device were found mitk::TrackingDeviceType scannedPort; #ifdef WIN32 mitk::ProgressBar::GetInstance()->AddStepsToDo(19); QString devName; for (unsigned int i = 1; i < 20; ++i) { QString statusOutput = "Scanning Port #" + QString::number(i); MITK_INFO << statusOutput.toStdString().c_str(); if (i < 10) devName = QString("COM%1").arg(i); else devName = QString("\\\\.\\COM%1").arg(i); // prepend "\\.\ to COM ports >9, to be able to allow connection" scannedPort = ScanPort(devName); if (!(scannedPort == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName())) { result += "
" + devName + ": " + QString::fromStdString(scannedPort); Port = i; } mitk::ProgressBar::GetInstance()->Progress(); } #else //linux systems for(unsigned int i = 1; i < 6; ++i) { QString devName = QString("/dev/ttyS%1").arg(i); mitk::TrackingDeviceType scannedPort = ScanPort(devName); if (!(scannedPort == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName())) { result += "
" + devName + ": " + QString::fromStdString(scannedPort); Port = i; PortType = 1; } } for(unsigned int i = 0; i <7; ++i) { QString devName = QString("/dev/ttyUSB%1").arg(i); mitk::TrackingDeviceType scannedPort = ScanPort(devName); if (!(scannedPort == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName())) { result += "
" + devName + ": " + QString::fromStdString(scannedPort); Port = i; PortType = 0; } } #endif if (result.size() == resultSize) result += "
none"; emit PortsScanned(Port, result, PortType); } mitk::TrackingDeviceType QmitkTrackingDeviceConfigurationWidgetScanPortsWorker::ScanPort(QString port) { mitk::NDITrackingDevice::Pointer tracker = mitk::NDITrackingDevice::New(); tracker->SetDeviceName(port.toStdString()); mitk::TrackingDeviceType returnValue = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); try { returnValue = tracker->TestConnection(); } - catch (mitk::IGTException) + catch (const mitk::IGTException&) { }//do nothing: there is simply no device on this port return returnValue; } diff --git a/Modules/ModelFit/cmdapps/GenericFittingMiniApp.cpp b/Modules/ModelFit/cmdapps/GenericFittingMiniApp.cpp index b37aaf1b2c..a9047570de 100644 --- a/Modules/ModelFit/cmdapps/GenericFittingMiniApp.cpp +++ b/Modules/ModelFit/cmdapps/GenericFittingMiniApp.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. ===================================================================*/ // std includes #include // itk includes #include "itksys/SystemTools.hxx" // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include #include #include #include #include #include #include #include #include #include #include #include std::string inFilename; std::string outFileName; std::string maskFileName; bool verbose(false); bool roibased(false); std::string functionName; std::string formular; mitk::Image::Pointer image; mitk::Image::Pointer mask; void onFitEvent(::itk::Object* caller, const itk::EventObject & event, void* /*data*/) { itk::ProgressEvent progressEvent; if (progressEvent.CheckEvent(&event)) { mitk::ParameterFitImageGeneratorBase* castedReporter = dynamic_cast(caller); std::cout <GetProgress()*100 << "% "; } } void setupParser(mitkCommandLineParser& parser) { // set general information about your MiniApp parser.setCategory("Dynamic Data Analysis Tools"); parser.setTitle("Generic Fitting"); parser.setDescription("MiniApp that allows to make a pixel based fitting on the intensity signal over time for a given model function."); parser.setContributor("DKFZ MIC"); //! [create parser] //! [add arguments] // 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("Model parameters"); parser.addArgument( "function", "f", mitkCommandLineParser::String, "Model function", "Function that should be used to fit the intensity signals. Options are: \"Linear\" or \"\" (for generic formulas).", us::Any(std::string("Linear"))); parser.addArgument( "formular", "y", mitkCommandLineParser::String, "Generic model function formular", "Formular of a generic model (if selected) that will be parsed and fitted.", us::Any()); parser.endGroup(); parser.beginGroup("Required I/O parameters"); parser.addArgument( "input", "i", mitkCommandLineParser::File, "Input file", "input 3D+t image file", us::Any(), false, false, false, mitkCommandLineParser::Input); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file template", "where to save the output parameter images. The specified path will be used as template to determine the format (via extension) and the name \"root\". For each parameter a suffix will be added to the name.", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.endGroup(); parser.beginGroup("Optional parameters"); parser.addArgument( "mask", "m", mitkCommandLineParser::File, "Mask file", "Mask that defines the spatial image region that should be fitted. Must have the same geometry as the input image!", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument( "verbose", "v", mitkCommandLineParser::Bool, "Verbose Output", "Whether to produce verbose output"); parser.addArgument( "roibased", "r", mitkCommandLineParser::Bool, "Roi based fitting", "Will compute a mean intesity signal over the ROI before fitting it. If this mode is used a mask must be specified."); parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.endGroup(); //! [add arguments] } bool configureApplicationSettings(std::map parsedArgs) { if (parsedArgs.size() == 0) return false; // parse, cast and set required arguments functionName = "Linear"; if (parsedArgs.count("function")) { functionName = us::any_cast(parsedArgs["function"]); } if (parsedArgs.count("formular")) { formular = us::any_cast(parsedArgs["formular"]); } inFilename = us::any_cast(parsedArgs["input"]); outFileName = us::any_cast(parsedArgs["output"]); verbose = false; if (parsedArgs.count("verbose")) { verbose = us::any_cast(parsedArgs["verbose"]); } roibased = false; if (parsedArgs.count("roibased")) { roibased = us::any_cast(parsedArgs["roibased"]); } if (parsedArgs.count("mask")) { maskFileName = us::any_cast(parsedArgs["mask"]); } return true; } void configureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) { mitk::GenericParamModelParameterizer* genericParameterizer = dynamic_cast(parameterizer); if (genericParameterizer) { genericParameterizer->SetFunctionString(formular); } } mitk::ModelFitFunctorBase::Pointer createDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(true); return fitFunctor.GetPointer(); } template void generateModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& /*modelFitInfo*/, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); configureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(mask); fitGenerator->SetDynamicImage(image); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); } template void generateModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& /*modelFitInfo*/, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); configureInitialParametersOfParameterizer(modelParameterizer); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(mask); signalGenerator->SetDynamicImage(image); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = createDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(mask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(image)); generator = fitGenerator.GetPointer(); } void doFitting() { mitk::ParameterFitImageGeneratorBase::Pointer generator = NULL; mitk::modelFit::ModelFitInfo::Pointer fitSession = NULL; ::itk::CStyleCommand::Pointer command = ::itk::CStyleCommand::New(); command->SetCallback(onFitEvent); bool isLinearFactory = functionName == "Linear"; if (isLinearFactory) { std::cout << "Model: linear" << std::endl; if (!roibased) { generateModelFit_PixelBased(fitSession, generator); } else { generateModelFit_ROIBased(fitSession, generator); } } else { std::cout << "Model: generic (2 parameter)" << std::endl; if (!roibased) { generateModelFit_PixelBased(fitSession, generator); } else { generateModelFit_ROIBased(fitSession, generator); } } if (generator.IsNotNull() ) { std::cout << "Started fitting process..." << std::endl; generator->AddObserver(::itk::AnyEvent(), command); generator->Generate(); std::cout << std::endl << "Finished fitting process" << std::endl; mitk::storeModelFitGeneratorResults(outFileName, generator, fitSession); } else { mitkThrow() << "Fitting error! Could not initalize fitting job."; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; setupParser(parser); mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" }); const std::map& parsedArgs = parser.parseArguments(argc, argv); if (!configureApplicationSettings(parsedArgs)) { return EXIT_FAILURE; }; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } //! [do processing] try { image = mitk::IOUtil::Load(inFilename, &readerFilterFunctor); std::cout << "Input: " << inFilename << std::endl; if (!maskFileName.empty()) { mask = mitk::IOUtil::Load(maskFileName, &readerFilterFunctor); std::cout << "Mask: " << maskFileName << std::endl; } else { std::cout << "Mask: none" << std::endl; } if (roibased && mask.IsNull()) { mitkThrow() << "Error. Cannot fit. Please specify mask if you select roi based fitting."; } std::cout << "Style: "; if (roibased) { std::cout << "ROI based"; } else { std::cout << "pixel based"; } std::cout << std::endl; doFitting(); std::cout << "Processing finished." << std::endl; return EXIT_SUCCESS; } catch (const itk::ExceptionObject& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } - catch (std::exception e) + catch (const std::exception& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (...) { MITK_ERROR << "Unexpected error encountered."; return EXIT_FAILURE; } } diff --git a/Modules/ModelFit/cmdapps/PixelDumpMiniApp.cpp b/Modules/ModelFit/cmdapps/PixelDumpMiniApp.cpp index b945816bb5..1119b5edd8 100644 --- a/Modules/ModelFit/cmdapps/PixelDumpMiniApp.cpp +++ b/Modules/ModelFit/cmdapps/PixelDumpMiniApp.cpp @@ -1,451 +1,451 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // std includes #include // itk includes #include "itksys/SystemTools.hxx" #include "itkImageRegionConstIteratorWithIndex.h" #include "itkCastImageFilter.h" #include "itkExtractImageFilter.h" // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include #include #include #include "mitkImageAccessByItk.h" #include "mitkImageCast.h" mitkCommandLineParser::StringContainerType inFilenames; std::string outFileName; std::string maskFileName; mitkCommandLineParser::StringContainerType captions; using ImageVectorType = std::vector; ImageVectorType images; mitk::Image::Pointer mask; bool verbose(false); typedef itk::Image InternalImageType; typedef std::map InternalImageMapType; InternalImageMapType internalImages; itk::ImageRegion<3> relevantRegion; InternalImageType::PointType relevantOrigin; InternalImageType::SpacingType relevantSpacing; InternalImageType::DirectionType relevantDirection; typedef itk::Index<3> DumpIndexType; typedef std::vector DumpedValuesType; struct DumpIndexCompare { bool operator() (const DumpIndexType& lhs, const DumpIndexType& rhs) { if (lhs[0] < rhs[0]) { return true; } else if (lhs[0] > rhs[0]) { return false; } if (lhs[1] < rhs[1]) { return true; } else if (lhs[1] > rhs[1]) { return false; } return lhs[2] < rhs[2]; } }; typedef std::map DumpPixelMapType; DumpPixelMapType dumpedPixels; void setupParser(mitkCommandLineParser& parser) { // set general information about your MiniApp parser.setCategory("Generic Analysis Tools"); parser.setTitle("Pixel Dumper"); parser.setDescription("MiniApp that allows to dump the pixel values of all passed files into a csv. The region of dumping can defined by a mask. All images (and mask) must have the same geometrie."); parser.setContributor("DKFZ MIC"); //! [create parser] //! [add arguments] // 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( "inputs", "i", mitkCommandLineParser::StringList, "Input files", "list of the images that should be dumped.", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::File, "Output file", "where to save the csv.", us::Any(), false, false, false, mitkCommandLineParser::Output); parser.endGroup(); parser.beginGroup("Optional parameters"); parser.addArgument( "mask", "m", mitkCommandLineParser::File, "Mask file", "Mask that defines the spatial image region that should be dumped. Must have the same geometry as the input images!", us::Any(), true, false, false, mitkCommandLineParser::Input); parser.addArgument( "captions", "c", mitkCommandLineParser::StringList, "Captions of image columns", "If provided the pixel columns of the csv will be named according to the passed values instead of using the image pathes. Number of images and names must be equal.", us::Any(), false); parser.addArgument("help", "h", mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.endGroup(); //! [add arguments] } bool configureApplicationSettings(std::map parsedArgs) { if (parsedArgs.size() == 0) return false; // parse, cast and set required arguments inFilenames = us::any_cast(parsedArgs["inputs"]); outFileName = us::any_cast(parsedArgs["output"]); if (parsedArgs.count("mask")) { maskFileName = us::any_cast(parsedArgs["mask"]); } captions = inFilenames; if (parsedArgs.count("captions")) { captions = us::any_cast(parsedArgs["captions"]); } return true; } template < typename TPixel, unsigned int VImageDimension > void ExtractRelevantInformation( const itk::Image< TPixel, VImageDimension > *image) { relevantRegion = image->GetLargestPossibleRegion(); relevantOrigin = image->GetOrigin(); relevantSpacing = image->GetSpacing(); relevantDirection = image->GetDirection(); } template < typename TPixel, unsigned int VImageDimension > void DoInternalImageConversion( const itk::Image< TPixel, VImageDimension > *image, InternalImageType::Pointer& internalImage) { typedef itk::Image< TPixel, VImageDimension > ImageType; //check if image fit to geometry // Make sure that spacing are the same typename ImageType::SpacingType imageSpacing = image->GetSpacing(); typename ImageType::PointType zeroPoint; zeroPoint.Fill(0.0); if ((zeroPoint + imageSpacing).SquaredEuclideanDistanceTo((zeroPoint + relevantSpacing)) > 1e-6) // for the dumper we are not as strict as mitk normally would be (mitk::eps) { mitkThrow() << "Images need to have same spacing! (Image spacing: " << imageSpacing << "; relevant spacing: " << relevantSpacing << ")"; } // Make sure that orientation of mask and image are the same typename ImageType::DirectionType imageDirection = image->GetDirection(); for (unsigned int i = 0; i < imageDirection.RowDimensions; ++i) { for (unsigned int j = 0; j < imageDirection.ColumnDimensions; ++j) { double differenceDirection = imageDirection[i][j] - relevantDirection[i][j]; if (fabs(differenceDirection) > 1e-6) // SD: 1e6 wird hier zum zweiten mal als Magic Number benutzt -> Konstante { // for the dumper we are not as strict as mitk normally would be (mitk::eps) mitkThrow() << "Images need to have same direction! (Image direction: " << imageDirection << "; relevant direction: " << relevantDirection << ")"; } } } // Make sure that origin of mask and image are the same typename ImageType::PointType imageOrigin = image->GetOrigin(); if (imageOrigin.SquaredEuclideanDistanceTo(relevantOrigin) > 1e-6) { // for the dumper we are not as strict as mitk normally would be (mitk::eps) mitkThrow() << "Image need to have same spacing! (Image spacing: " << imageSpacing << "; relevant spacing: " << relevantOrigin << ")"; } typename ImageType::RegionType imageRegion = image->GetLargestPossibleRegion(); if (!imageRegion.IsInside(relevantRegion) && imageRegion != relevantRegion) { mitkThrow() << "Images need to have same region! (Image region: " << imageRegion << "; relevant region: " << relevantRegion << ")"; } //convert to internal image typedef itk::ExtractImageFilter ExtractFilterType; typename ExtractFilterType::Pointer extractFilter = ExtractFilterType::New(); typedef itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); extractFilter->SetInput(image); extractFilter->SetExtractionRegion(relevantRegion); castFilter->SetInput(extractFilter->GetOutput()); castFilter->Update(); internalImage = castFilter->GetOutput(); } template < typename TPixel, unsigned int VImageDimension > void DoMaskedCollecting( const itk::Image< TPixel, VImageDimension > *image) { typedef itk::Image< TPixel, VImageDimension > ImageType; itk::ImageRegionConstIteratorWithIndex it(image, relevantRegion); it.GoToBegin(); while (!it.IsAtEnd()) { if (mask.IsNull() || it.Get() > 0) { DumpedValuesType values; const auto index = it.GetIndex(); for (auto& imagePos : internalImages) { double value = imagePos.second->GetPixel(index); values.push_back(value); } dumpedPixels.insert(std::make_pair(index, values)); } ++it; } } InternalImageMapType ConvertImageTimeSteps(mitk::Image* image) { InternalImageMapType map; InternalImageType::Pointer internalImage; for (unsigned int i = 0; i < image->GetTimeSteps(); ++i) { mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(image); imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer imageTimePoint = imageTimeSelector->GetOutput(); AccessFixedDimensionByItk_1(imageTimePoint, DoInternalImageConversion, 3, internalImage); std::stringstream stream; stream << "[" << i << "]"; map.insert(std::make_pair(stream.str(), internalImage)); } return map; } void doDumping() { if (mask.IsNotNull() && mask->GetTimeSteps() > 1) { std::cout << "Pixel Dumper: Selected mask has multiple timesteps. Only use first timestep to mask the pixel dumping." << std::endl; mitk::ImageTimeSelector::Pointer maskTimeSelector = mitk::ImageTimeSelector::New(); maskTimeSelector->SetInput(mask); maskTimeSelector->SetTimeNr(0); maskTimeSelector->UpdateLargestPossibleRegion(); mask = maskTimeSelector->GetOutput(); } try { if (mask.IsNotNull()) { // if mask exist, we use the mask because it could be a sub region. AccessFixedDimensionByItk(mask, ExtractRelevantInformation, 3); } else { AccessFixedDimensionByItk(images.front(), ExtractRelevantInformation, 3); } } catch (const std::exception& e) { std::cerr << "Error extracting image geometry. Error text: " << e.what(); throw; } for (unsigned int index = 0; index < images.size(); ++index) { try { InternalImageMapType conversionMap = ConvertImageTimeSteps(images[index]); if (conversionMap.size() == 1) { internalImages.insert(std::make_pair(captions[index], conversionMap.begin()->second)); } else if (conversionMap.size() > 1) { for (auto& pos : conversionMap) { std::stringstream namestream; namestream << captions[index] << " " << pos.first; internalImages.insert(std::make_pair(namestream.str(), pos.second)); } } } catch (const std::exception& e) { std::stringstream errorStr; errorStr << "Inconsistent image \"" << captions[index] << "\" will be excluded from the collection. Error: " << e.what(); std::cerr << errorStr.str() << std::endl; } } if (mask.IsNotNull()) { // if mask exist, we use the mask because it could be a sub region. AccessFixedDimensionByItk(mask, DoMaskedCollecting, 3); } else { AccessFixedDimensionByItk(images.front(), DoMaskedCollecting, 3); } } void storeCSV() { std::ofstream resultfile; resultfile.open(outFileName.c_str()); resultfile << "x,y,z"; for (auto aImage : internalImages) { resultfile << "," << aImage.first; } resultfile << std::endl; for (auto dumpPos : dumpedPixels) { resultfile << dumpPos.first[0] << "," << dumpPos.first[1] << "," << dumpPos.first[2]; for(auto d : dumpPos.second) { resultfile << "," << d; } resultfile << std::endl; } } int main(int argc, char* argv[]) { mitkCommandLineParser parser; setupParser(parser); const std::map& parsedArgs = parser.parseArguments(argc, argv); mitk::PreferenceListReaderOptionsFunctor readerFilterFunctor = mitk::PreferenceListReaderOptionsFunctor({ "MITK DICOM Reader v2 (classic config)" }, { "MITK DICOM Reader" }); if (!configureApplicationSettings(parsedArgs)) { return EXIT_FAILURE; }; // Show a help message if (parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } if (!captions.empty() && inFilenames.size() != captions.size()) { std::cerr << "Cannot dump images. Number of given captions does not equal number of given images."; return EXIT_FAILURE; }; //! [do processing] try { std::cout << "Load images:" << std::endl; for (auto path : inFilenames) { std::cout << "Input: " << path << std::endl; auto image = mitk::IOUtil::Load(path, &readerFilterFunctor); images.push_back(image); } if (!maskFileName.empty()) { mask = mitk::IOUtil::Load(maskFileName, &readerFilterFunctor); std::cout << "Mask: " << maskFileName << std::endl; } else { std::cout << "Mask: none" << std::endl; } doDumping(); storeCSV(); std::cout << "Processing finished." << std::endl; return EXIT_SUCCESS; } catch (const itk::ExceptionObject& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } - catch (std::exception e) + catch (const std::exception& e) { MITK_ERROR << e.what(); return EXIT_FAILURE; } catch (...) { MITK_ERROR << "Unexpected error encountered."; return EXIT_FAILURE; } } diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.h b/Modules/Python/autoload/PythonService/mitkPythonService.h index 3b99edb1a6..1c810b23f0 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonService.h +++ b/Modules/Python/autoload/PythonService/mitkPythonService.h @@ -1,111 +1,111 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkPythonService_h #define mitkPythonService_h +#include #include "mitkIPythonService.h" #include -#include #include "mitkSurface.h" namespace mitk { /// /// implementation of the IPythonService using ctkabstractpythonmanager /// \see IPythonService class PythonService: public itk::LightObject, public mitk::IPythonService { public: /// /// instantiate python manager here PythonService(); /// /// empty implementation... ~PythonService(); /// /// \see IPythonService::Execute() std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ); /// /// \see IPythonService::ExecuteScript() void ExecuteScript(const std::string &pathToPythonScript); /// /// \see IPythonService::PythonErrorOccured() bool PythonErrorOccured() const; /// /// \see IPythonService::GetVariableStack() std::vector GetVariableStack() const; /// /// \see IPythonService::DoesVariableExist() bool DoesVariableExist(const std::string& name) const; /// /// \see IPythonService::GetVariable() std::string GetVariable(const std::string& name) const; /// /// \see IPythonService::AddPythonCommandObserver() void AddPythonCommandObserver( PythonCommandObserver* observer ); /// /// \see IPythonService::RemovePythonCommandObserver() void RemovePythonCommandObserver( PythonCommandObserver* observer ); /// /// \see IPythonService::NotifyObserver() void NotifyObserver( const std::string& command ); /// /// \see IPythonService::IsItkPythonWrappingAvailable() bool IsSimpleItkPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsItkImage() bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ); /// /// \see IPythonService::CopyItkImageFromPython() mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ); /// /// \see IPythonService::IsOpenCvPythonWrappingAvailable() bool IsOpenCvPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsCvImage() bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ); /// /// \see IPythonService::CopyCvImageFromPython() mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ); /// /// \see IPythonService::IsVtkPythonWrappingAvailable() bool IsVtkPythonWrappingAvailable(); /// /// \see IPythonService::CopyToPythonAsVtkPolyData() bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ); /// /// \see IPythonService::CopyVtkPolyDataFromPython() mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ); /// /// \return the ctk abstract python manager instance ctkAbstractPythonManager* GetPythonManager(); void AddRelativeSearchDirs(std::vector< std::string > dirs); void AddAbsoluteSearchDirs(std::vector< std::string > dirs); protected: private: QList m_Observer; ctkAbstractPythonManager m_PythonManager; bool m_ItkWrappingAvailable; bool m_OpenCVWrappingAvailable; bool m_VtkWrappingAvailable; bool m_ErrorOccured; }; } #endif diff --git a/Modules/US/USModel/mitkUSImage.cpp b/Modules/US/USModel/mitkUSImage.cpp index 20809357c4..9d8a59aa57 100644 --- a/Modules/US/USModel/mitkUSImage.cpp +++ b/Modules/US/USModel/mitkUSImage.cpp @@ -1,73 +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 "mitkUSImage.h" #include #include #include mitk::USImage::USImage() : mitk::Image() { this->SetMetadata(mitk::USImageMetadata::New()); } mitk::USImage::USImage(mitk::Image::Pointer image) : mitk::Image() { try { this->Initialize(image); mitk::ImageReadAccessor imgA(image, image->GetVolumeData(0)); this->SetVolume(imgA.GetData()); } - catch(mitk::Exception e) + catch(mitk::Exception& e) { mitkReThrow(e) << "Cannot access image data while constructing US image"; } } mitk::USImage::~USImage() { } mitk::USImageMetadata::Pointer mitk::USImage::GetMetadata() const { mitk::USImageMetadata::Pointer result = mitk::USImageMetadata::New(); result->SetDeviceManufacturer(this->GetProperty(mitk::USImageMetadata::PROP_DEV_MANUFACTURER)->GetValueAsString()); result->SetDeviceModel( this->GetProperty(mitk::USImageMetadata::PROP_DEV_MODEL)->GetValueAsString()); result->SetDeviceComment( this->GetProperty(mitk::USImageMetadata::PROP_DEV_COMMENT)->GetValueAsString()); result->SetDeviceIsVideoOnly( this->GetProperty(mitk::USImageMetadata::PROP_DEV_ISVIDEOONLY)); result->SetDeviceIsCalibrated(this->GetProperty(mitk::USImageMetadata::PROP_DEV_ISCALIBRATED)); result->SetProbeName( this->GetProperty(mitk::USImageMetadata::PROP_PROBE_NAME)->GetValueAsString()); result->SetProbeFrequency( this->GetProperty(mitk::USImageMetadata::PROP_PROBE_FREQUENCY)->GetValueAsString()); result->SetZoom( this->GetProperty(mitk::USImageMetadata::PROP_ZOOM)->GetValueAsString()); return result; } void mitk::USImage::SetMetadata(mitk::USImageMetadata::Pointer metadata){ this->SetProperty(mitk::USImageMetadata::PROP_DEV_MANUFACTURER, mitk::StringProperty::New(metadata->GetDeviceManufacturer())); this->SetProperty(mitk::USImageMetadata::PROP_DEV_MODEL, mitk::StringProperty::New(metadata->GetDeviceModel())); this->SetProperty(mitk::USImageMetadata::PROP_DEV_COMMENT, mitk::StringProperty::New(metadata->GetDeviceComment())); this->SetProperty(mitk::USImageMetadata::PROP_DEV_ISVIDEOONLY, mitk::BoolProperty::New(metadata->GetDeviceIsVideoOnly())); this->SetProperty(mitk::USImageMetadata::PROP_DEV_ISCALIBRATED, mitk::BoolProperty::New(metadata->GetDeviceIsCalibrated())); this->SetProperty(mitk::USImageMetadata::PROP_PROBE_NAME, mitk::StringProperty::New(metadata->GetProbeName())); this->SetProperty(mitk::USImageMetadata::PROP_PROBE_FREQUENCY, mitk::StringProperty::New(metadata->GetProbeFrequency())); this->SetProperty(mitk::USImageMetadata::PROP_ZOOM, mitk::StringProperty::New(metadata->GetZoom())); } diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp index 132923bbc3..bda7863165 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp @@ -1,181 +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()) { //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) + catch (mitk::Exception&) { 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/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp index 754ced43ea..fff0ae3789 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp @@ -1,1441 +1,1441 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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); //initialize projection buttons //first it is disabled when the tool is connected check box for projection and axis is enabled m_Controls->showHideToolAxisCheckBox->setEnabled(false); m_Controls->showHideToolProjectionCheckBox->setEnabled(false); m_Controls->m_toolselector->setEnabled(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) + 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->GetNumberOfInputs()) { 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->GetNumberOfInputs()) { 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] //enable checkboxes for projection and tool axis m_Controls->showHideToolAxisCheckBox->setEnabled(true); m_Controls->showHideToolProjectionCheckBox->setEnabled(true); m_Controls->m_toolselector->setEnabled(true); //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(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) + 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", 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 e) + catch (const mitk::IGTException& e) { 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.viewnavigator/src/QmitkViewNavigatorWidget.cpp b/Plugins/org.mitk.gui.qt.viewnavigator/src/QmitkViewNavigatorWidget.cpp index 4df8ae6609..8df6937384 100644 --- a/Plugins/org.mitk.gui.qt.viewnavigator/src/QmitkViewNavigatorWidget.cpp +++ b/Plugins/org.mitk.gui.qt.viewnavigator/src/QmitkViewNavigatorWidget.cpp @@ -1,701 +1,701 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY 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 headers #include "QmitkViewNavigatorWidget.h" // Blueberry #include #include #include #include #include #include #include #include #include #include // MITK #include // Qt #include #include #include #include #include class KeywordRegistry { public: KeywordRegistry() { berry::IExtensionRegistry* extensionPointService = berry::Platform::GetExtensionRegistry(); auto keywordExts = extensionPointService->GetConfigurationElementsFor("org.blueberry.ui.keywords"); for (auto keywordExtsIt = keywordExts.begin(); keywordExtsIt != keywordExts.end(); ++keywordExtsIt) { QString keywordId = (*keywordExtsIt)->GetAttribute("id"); QString keywordLabels = (*keywordExtsIt)->GetAttribute("label"); m_Keywords[keywordId].push_back(keywordLabels); } } QStringList GetKeywords(const QString& id) { return m_Keywords[id]; } QStringList GetKeywords(const QStringList& ids) { QStringList result; for (int i = 0; i < ids.size(); ++i) { result.append(this->GetKeywords(ids[i])); } return result; } private: QHash m_Keywords; }; class ClassFilterProxyModel : public QSortFilterProxyModel { private : bool hasToBeDisplayed(const QModelIndex index) const; bool displayElement(const QModelIndex index) const; public: ClassFilterProxyModel(QObject *parent = nullptr); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; }; ClassFilterProxyModel::ClassFilterProxyModel(QObject *parent): QSortFilterProxyModel(parent) { } bool ClassFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); return hasToBeDisplayed(index); } bool ClassFilterProxyModel::displayElement(const QModelIndex index) const { bool result = false; QString type = sourceModel()->data(index, Qt::DisplayRole).toString(); QStandardItem * item = dynamic_cast(sourceModel())->itemFromIndex(index); if (type.contains(filterRegExp())) { return true; } { mitk::QtViewItem* viewItem = dynamic_cast(item); if (viewItem) { for (int i = 0; i < viewItem->m_Tags.size(); ++i) { if (viewItem->m_Tags[i].contains(filterRegExp())) { return true; } } if (viewItem->m_Description.contains(filterRegExp())) { return true; } } } { mitk::QtPerspectiveItem* viewItem = dynamic_cast(item); if (viewItem) { for (int i = 0; i < viewItem->m_Tags.size(); ++i) { if (viewItem->m_Tags[i].contains(filterRegExp())) { return true; } } if (viewItem->m_Description.contains(filterRegExp())) { return true; } } } return result; } bool ClassFilterProxyModel::hasToBeDisplayed(const QModelIndex index) const { bool result = false; if ( sourceModel()->rowCount(index) > 0 ) { for( int ii = 0; ii < sourceModel()->rowCount(index); ii++) { QModelIndex childIndex = sourceModel()->index(ii,0,index); if ( ! childIndex.isValid() ) break; result = hasToBeDisplayed(childIndex); result |= displayElement(index); if (result) { break; } } } else { result = displayElement(index); } return result; } class ViewNavigatorPerspectiveListener: public berry::IPerspectiveListener { public: ViewNavigatorPerspectiveListener(QmitkViewNavigatorWidget* p) : parentWidget(p) { } Events::Types GetPerspectiveEventTypes() const override { return Events::ACTIVATED | Events::SAVED_AS | Events::DEACTIVATED // remove the following line when command framework is finished | Events::CLOSED | Events::OPENED | Events::PART_CHANGED; } void PerspectiveActivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& perspective) override { parentWidget->m_ActivePerspective = perspective; parentWidget->UpdateTreeList(); } void PerspectiveSavedAs(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*oldPerspective*/, const berry::IPerspectiveDescriptor::Pointer& newPerspective) override { parentWidget->m_ActivePerspective = newPerspective; parentWidget->UpdateTreeList(); } void PerspectiveDeactivated(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { parentWidget->m_ActivePerspective = nullptr; parentWidget->UpdateTreeList(); } void PerspectiveOpened(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { parentWidget->UpdateTreeList(); } void PerspectiveClosed(const berry::IWorkbenchPage::Pointer& /*page*/, const berry::IPerspectiveDescriptor::Pointer& /*perspective*/) override { parentWidget->m_ActivePerspective = nullptr; parentWidget->UpdateTreeList(); } using IPerspectiveListener::PerspectiveChanged; void PerspectiveChanged(const berry::IWorkbenchPage::Pointer&, const berry::IPerspectiveDescriptor::Pointer&, const berry::IWorkbenchPartReference::Pointer& partRef, const std::string& changeId) { if (changeId=="viewHide" && partRef->GetId()=="org.mitk.views.viewnavigatorview") berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->RemovePerspectiveListener(parentWidget->m_PerspectiveListener.data()); else parentWidget->UpdateTreeList(nullptr, partRef.GetPointer(), changeId); } private: QmitkViewNavigatorWidget* parentWidget; }; bool compareViews(const berry::IViewDescriptor::Pointer& a, const berry::IViewDescriptor::Pointer& b) { if (a.IsNull() || b.IsNull()) return false; return a->GetLabel().compare(b->GetLabel()) < 0; } bool comparePerspectives(const berry::IPerspectiveDescriptor::Pointer& a, const berry::IPerspectiveDescriptor::Pointer& b) { if (a.IsNull() || b.IsNull()) return false; return a->GetLabel().compare(b->GetLabel()) < 0; } bool compareQStandardItems(const QStandardItem* a, const QStandardItem* b) { if (a==nullptr || b==nullptr) return false; return a->text().compare(b->text()) < 0; } QmitkViewNavigatorWidget::QmitkViewNavigatorWidget(berry::IWorkbenchWindow::Pointer window, QWidget * parent, Qt::WindowFlags ) : QWidget(parent) , m_Window(window) { m_Generated = false; this->CreateQtPartControl(this); } QmitkViewNavigatorWidget::~QmitkViewNavigatorWidget() { m_Window->RemovePerspectiveListener(m_PerspectiveListener.data()); } void QmitkViewNavigatorWidget::setFocus() { m_Controls.lineEdit->setFocus(); } void QmitkViewNavigatorWidget::CreateQtPartControl( QWidget *parent ) { // create GUI widgets from the Qt Designer's .ui file m_PerspectiveListener.reset(new ViewNavigatorPerspectiveListener(this)); m_Window->AddPerspectiveListener(m_PerspectiveListener.data()); m_Parent = parent; m_Controls.setupUi( parent ); connect( m_Controls.m_PluginTreeView, SIGNAL(customContextMenuRequested(QPoint)), SLOT(CustomMenuRequested(QPoint))); connect( m_Controls.m_PluginTreeView, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(ItemClicked(const QModelIndex&))); connect( m_Controls.lineEdit, SIGNAL(textChanged(QString)), SLOT(FilterChanged())); m_ContextMenu = new QMenu(m_Controls.m_PluginTreeView); m_Controls.m_PluginTreeView->setContextMenuPolicy(Qt::CustomContextMenu); // Create a new TreeModel for the data m_TreeModel = new QStandardItemModel(); m_FilterProxyModel = new ClassFilterProxyModel(this); m_FilterProxyModel->setSourceModel(m_TreeModel); //proxyModel->setFilterFixedString("Diff"); m_Controls.m_PluginTreeView->setModel(m_FilterProxyModel); this->UpdateTreeList(); } void QmitkViewNavigatorWidget::UpdateTreeList(QStandardItem* root, berry::IWorkbenchPartReference *partRef, const std::string &changeId) { berry::IWorkbenchPage::Pointer page = m_Window->GetActivePage(); if (page.IsNull()) return; if( !m_Generated ) { m_Generated = FillTreeList(); } if (root==nullptr) root = m_TreeModel->invisibleRootItem(); for (int i=0; irowCount(); i++) { QStandardItem* item = root->child(i); QFont font; if (dynamic_cast(item)) { mitk::QtPerspectiveItem* pItem = dynamic_cast(item); berry::IPerspectiveDescriptor::Pointer currentPersp = page->GetPerspective(); if (currentPersp.IsNotNull() && currentPersp->GetId()==pItem->m_Perspective->GetId()) font.setBold(true); pItem->setFont(font); } mitk::QtViewItem* vItem = dynamic_cast(item); if (vItem) { QList viewParts(page->GetViews()); for (int i=0; iGetPartName()==vItem->m_View->GetLabel()) { font.setBold(true); break; } if( partRef!=nullptr && partRef->GetId()==vItem->m_View->GetId() && changeId=="viewHide") font.setBold(false); vItem->setFont(font); } UpdateTreeList(item, partRef, changeId); } } bool QmitkViewNavigatorWidget::FillTreeList() { // active workbench window available? if (m_Window.IsNull()) return false; // active page available? berry::IWorkbenchPage::Pointer page = m_Window->GetActivePage(); if (page.IsNull()) return false; // everything is fine and we can remove the window listener if (m_WindowListener != nullptr) berry::PlatformUI::GetWorkbench()->RemoveWindowListener(m_WindowListener.data()); // initialize tree model m_TreeModel->clear(); QStandardItem *treeRootItem = m_TreeModel->invisibleRootItem(); // get all available perspectives berry::IPerspectiveRegistry* perspRegistry = berry::PlatformUI::GetWorkbench()->GetPerspectiveRegistry(); QList perspectiveDescriptors(perspRegistry->GetPerspectives()); qSort(perspectiveDescriptors.begin(), perspectiveDescriptors.end(), comparePerspectives); // get all Keywords KeywordRegistry keywordRegistry; berry::IPerspectiveDescriptor::Pointer currentPersp = page->GetPerspective(); //QStringList perspectiveExcludeList = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetPerspectiveExcludeList(); std::vector< QStandardItem* > categoryItems; QStandardItem *perspectiveRootItem = new QStandardItem("Perspectives"); perspectiveRootItem->setEditable(false); perspectiveRootItem->setFont(QFont("", 12, QFont::Normal)); treeRootItem->appendRow(perspectiveRootItem); for (int i=0; iGetId()) { skipPerspective = true; break; } if (skipPerspective) continue; */ //QIcon* pIcon = static_cast(p->GetImageDescriptor()->CreateImage()); mitk::QtPerspectiveItem* pItem = new mitk::QtPerspectiveItem(p->GetLabel()); pItem->m_Perspective = p; pItem->m_Description = p->GetDescription(); QStringList keylist = p->GetKeywordReferences(); pItem->m_Tags = keywordRegistry.GetKeywords(keylist); pItem->setEditable(false); QFont font; font.setBold(true); if (currentPersp.IsNotNull() && currentPersp->GetId()==p->GetId()) pItem->setFont(font); QStringList catPath = p->GetCategoryPath(); if (catPath.isEmpty()) { perspectiveRootItem->appendRow(pItem); } else { QStandardItem* categoryItem = nullptr; for (unsigned int c=0; ctext() == catPath.front()) { categoryItem = categoryItems.at(c); break; } } if (categoryItem==nullptr) { categoryItem = new QStandardItem(QIcon(),catPath.front()); categoryItems.push_back(categoryItem); } categoryItem->setEditable(false); categoryItem->appendRow(pItem); categoryItem->setFont(QFont("", 12, QFont::Normal)); } } std::sort(categoryItems.begin(), categoryItems.end(), compareQStandardItems); for (unsigned int i=0; iappendRow(categoryItems.at(i)); // get all available views berry::IViewRegistry* viewRegistry = berry::PlatformUI::GetWorkbench()->GetViewRegistry(); QList viewDescriptors(viewRegistry->GetViews()); QList viewParts(page->GetViews()); qSort(viewDescriptors.begin(), viewDescriptors.end(), compareViews); auto emptyItem = new QStandardItem(); emptyItem->setFlags(Qt::ItemIsEnabled); treeRootItem->appendRow(emptyItem); //QStringList viewExcludeList = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetViewExcludeList(); //There currently is no way to get the list of excluded views at application start QStringList viewExcludeList; // internal view used for the intro screen, will crash when opened directly, see T22352 viewExcludeList.append(QString("org.blueberry.ui.internal.introview")); viewExcludeList.append(QString("org.mitk.views.controlvisualizationpropertiesview")); viewExcludeList.append(QString("org.mitk.views.modules")); viewExcludeList.append(QString("org.mitk.views.viewnavigatorview")); QStandardItem* viewRootItem = new QStandardItem(QIcon(),"Views"); viewRootItem->setFont(QFont("", 12, QFont::Normal)); viewRootItem->setEditable(false); treeRootItem->appendRow(viewRootItem); categoryItems.clear(); QStandardItem* noCategoryItem = new QStandardItem(QIcon(),"Miscellaneous"); noCategoryItem->setEditable(false); noCategoryItem->setFont(QFont("", 12, QFont::Normal)); for (int i = 0; i < viewDescriptors.size(); ++i) { berry::IViewDescriptor::Pointer v = viewDescriptors[i]; bool skipView = false; for(int e=0; eGetId()) { skipView = true; break; } if (skipView) continue; QStringList catPath = v->GetCategoryPath(); QIcon icon = v->GetImageDescriptor(); mitk::QtViewItem* vItem = new mitk::QtViewItem(icon, v->GetLabel()); vItem->m_View = v; vItem->setToolTip(v->GetDescription()); vItem->m_Description = v->GetDescription(); QStringList keylist = v->GetKeywordReferences(); vItem->m_Tags = keywordRegistry.GetKeywords(keylist); vItem->setEditable(false); for (int i=0; iGetPartName()==v->GetLabel()) { QFont font; font.setBold(true); vItem->setFont(font); break; } if (catPath.empty()) noCategoryItem->appendRow(vItem); else { QStandardItem* categoryItem = nullptr; for (unsigned int c=0; ctext() == catPath.front()) { categoryItem = categoryItems.at(c); break; } if (categoryItem==nullptr) { categoryItem = new QStandardItem(QIcon(),catPath.front()); categoryItems.push_back(categoryItem); } categoryItem->setEditable(false); categoryItem->appendRow(vItem); categoryItem->setFont(QFont("", 12, QFont::Normal)); } } std::sort(categoryItems.begin(), categoryItems.end(), compareQStandardItems); for (unsigned int i=0; iappendRow(categoryItems.at(i)); if (noCategoryItem->hasChildren()) viewRootItem->appendRow(noCategoryItem); m_Controls.m_PluginTreeView->expandAll(); return true; } void QmitkViewNavigatorWidget::FilterChanged() { QString filterString = m_Controls.lineEdit->text(); // if (filterString.size() > 0 ) m_Controls.m_PluginTreeView->expandAll(); // else // m_Controls.m_PluginTreeView->collapseAll(); // QRegExp::PatternSyntax syntax = QRegExp::RegExp; Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; QString strPattern = "^*" + filterString; QRegExp regExp(strPattern, caseSensitivity); m_FilterProxyModel->setFilterRegExp(regExp); } void QmitkViewNavigatorWidget::ItemClicked(const QModelIndex &index) { QStandardItem* item = m_TreeModel->itemFromIndex(m_FilterProxyModel->mapToSource(index)); if ( dynamic_cast< mitk::QtPerspectiveItem* >(item) ) { try { mitk::QtPerspectiveItem* pItem = dynamic_cast< mitk::QtPerspectiveItem* >(item); berry::PlatformUI::GetWorkbench()->ShowPerspective( pItem->m_Perspective->GetId(), berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow() ); } catch (...) { QMessageBox::critical(nullptr, "Opening Perspective Failed", QString("The requested perspective could not be opened.\nSee the log for details.")); } } else if ( dynamic_cast< mitk::QtViewItem* >(item) ) { berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); if (page.IsNotNull()) { try { mitk::QtViewItem* vItem = dynamic_cast< mitk::QtViewItem* >(item); page->ShowView(vItem->m_View->GetId()); } - catch (berry::PartInitException e) + catch (const berry::PartInitException& e) { BERRY_ERROR << "Error: " << e.what() << std::endl; } } } } void QmitkViewNavigatorWidget::SaveCurrentPerspectiveAs() { berry::IHandlerService* handlerService = m_Window->GetService(); try { handlerService->ExecuteCommand(berry::IWorkbenchCommandConstants::WINDOW_SAVE_PERSPECTIVE_AS, berry::UIElement::Pointer()); FillTreeList(); } - catch(const berry::NotHandledException) + catch(const berry::NotHandledException&) {} catch(const berry::CommandException& e) { MITK_ERROR << e.what(); } } void QmitkViewNavigatorWidget::ResetCurrentPerspective() { if (QMessageBox::Yes == QMessageBox(QMessageBox::Question, "Please confirm", "Do you really want to reset the current perspective?", QMessageBox::Yes|QMessageBox::No).exec()) berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage()->ResetPerspective(); } void QmitkViewNavigatorWidget::ClosePerspective() { if (QMessageBox::Yes == QMessageBox(QMessageBox::Question, "Please confirm", "Do you really want to close the current perspective?", QMessageBox::Yes|QMessageBox::No).exec()) { berry::IWorkbenchPage::Pointer page = m_Window->GetActivePage(); page->ClosePerspective(page->GetPerspective(), true, true); // if ( page->GetPerspective().IsNull() ) // { // berry::IPerspectiveRegistry* perspRegistry = berry::PlatformUI::GetWorkbench()->GetPerspectiveRegistry(); // berry::PlatformUI::GetWorkbench()->ShowPerspective( perspRegistry->GetDefaultPerspective(), berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow() ); // } } } void QmitkViewNavigatorWidget::CloseAllPerspectives() { if (QMessageBox::Yes == QMessageBox(QMessageBox::Question, "Please confirm", "Do you really want to close all perspectives?", QMessageBox::Yes|QMessageBox::No).exec()) { berry::IWorkbenchPage::Pointer page = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow()->GetActivePage(); page->CloseAllPerspectives(true, true); // berry::IPerspectiveRegistry* perspRegistry = berry::PlatformUI::GetWorkbench()->GetPerspectiveRegistry(); // berry::PlatformUI::GetWorkbench()->ShowPerspective( perspRegistry->GetDefaultPerspective(), berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow() ); } } void QmitkViewNavigatorWidget::ExpandAll() { m_Controls.m_PluginTreeView->expandAll(); } void QmitkViewNavigatorWidget::CollapseAll() { m_Controls.m_PluginTreeView->collapseAll(); } void QmitkViewNavigatorWidget::CustomMenuRequested(QPoint pos) { QModelIndex index = m_Controls.m_PluginTreeView->indexAt(pos); QStandardItem* item = m_TreeModel->itemFromIndex(m_FilterProxyModel->mapToSource(index)); if (m_ContextMenu==nullptr) return; m_ContextMenu->clear(); QAction* expandAction = new QAction("Expand tree", this); m_ContextMenu->addAction(expandAction); connect(expandAction, SIGNAL(triggered()), SLOT(ExpandAll())); QAction* collapseAction = new QAction("Collapse tree", this); m_ContextMenu->addAction(collapseAction); connect(collapseAction, SIGNAL(triggered()), SLOT(CollapseAll())); m_ContextMenu->addSeparator(); if ( item!=nullptr && dynamic_cast< mitk::QtPerspectiveItem* >(item) ) { berry::IPerspectiveDescriptor::Pointer persp = dynamic_cast< mitk::QtPerspectiveItem* >(item)->m_Perspective; if (this->m_ActivePerspective.IsNotNull() && this->m_ActivePerspective == persp) { //m_ContextMenu->addSeparator(); QAction* saveAsAction = new QAction("Save As...", this); m_ContextMenu->addAction(saveAsAction); connect(saveAsAction, SIGNAL(triggered()), SLOT(SaveCurrentPerspectiveAs())); m_ContextMenu->addSeparator(); } } QAction* resetAction = new QAction("Reset current perspective", this); m_ContextMenu->addAction(resetAction); connect(resetAction, SIGNAL(triggered()), SLOT(ResetCurrentPerspective())); QAction* closeAction = new QAction("Close perspective", this); m_ContextMenu->addAction(closeAction); connect(closeAction, SIGNAL(triggered()), SLOT(ClosePerspective())); m_ContextMenu->addSeparator(); QAction* closeAllAction = new QAction("Close all perspectives", this); m_ContextMenu->addAction(closeAllAction); connect(closeAllAction, SIGNAL(triggered()), SLOT(CloseAllPerspectives())); m_ContextMenu->popup(m_Controls.m_PluginTreeView->viewport()->mapToGlobal(pos)); }