diff --git a/Applications/PluginGenerator/CMakeLists.txt b/Applications/PluginGenerator/CMakeLists.txt index aebbe5def5..0fa99551a6 100644 --- a/Applications/PluginGenerator/CMakeLists.txt +++ b/Applications/PluginGenerator/CMakeLists.txt @@ -1,73 +1,73 @@ if (${CMAKE_SOURCE_DIR} EQUAL ${PROJECT_SOURCE_DIR}) - cmake_minimum_required(VERSION 3.14.5 FATAL_ERROR) + cmake_minimum_required(VERSION 3.18 FATAL_ERROR) endif() project(MitkPluginGenerator) set(VERSION_MAJOR 1) set(VERSION_MINOR 5) set(VERSION_PATCH 0) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(standalone_build 1) else() set(standalone_build 0) endif() #----------------------------------------------------------------------------- # Prerequisites #----------------------------------------------------------------------------- find_package(Qt5Core REQUIRED) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/PluginGeneratorConfig.h.in" "${CMAKE_CURRENT_BINARY_DIR}/PluginGeneratorConfig.h" @ONLY) include_directories("${CMAKE_CURRENT_BINARY_DIR}") #----------------------------------------------------------------------------- # Executable #----------------------------------------------------------------------------- set(src_files PluginGenerator.cpp ctkCommandLineParser.cpp ) qt5_wrap_cpp(src_files ctkCommandLineParser.h OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) qt5_add_resources(src_files plugin_template.qrc project_template.qrc) set(exec_target ${PROJECT_NAME}) add_executable(${exec_target} ${src_files}) set_property(TARGET ${exec_target} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Applications/PluginGenerator") target_link_libraries(${exec_target} Qt5::Core) #----------------------------------------------------------------------------- # Win32 Convenience #----------------------------------------------------------------------------- if(WIN32 AND NOT standalone_build) file(TO_NATIVE_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}" native_runtime_dir) add_custom_target(NewPlugin start "MITK PluginGenerator" /D "${native_runtime_dir}" cmd /K ${exec_target}.exe -h DEPENDS ${exec_target}) set_property(TARGET NewPlugin PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Applications/PluginGenerator") endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(NOT standalone_build) # Test the plugin generator include(mitkTestPluginGenerator) endif() #----------------------------------------------------------------------------- # Packaging support #----------------------------------------------------------------------------- if(standalone_build) include(SetupPackaging.cmake) endif() diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt index 1618e04c80..572d4ebd54 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt @@ -1,329 +1,329 @@ -cmake_minimum_required(VERSION 3.14.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.18 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(CTest) 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) # 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 (const std::exception& e) { fprintf(stderr, \"%s\\n\", e.what()); return EXIT_FAILURE; } catch (...) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; }") endif() #----------------------------------------------------------------------------- # ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR isn't defined, it means this project is # *NOT* build using Superbuild. In that specific case, ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR # should default to PROJECT_BINARY_DIR if(NOT DEFINED ${PROJECT_NAME}_SUPERBUILD_BINARY_DIR) set(${PROJECT_NAME}_SUPERBUILD_BINARY_DIR ${PROJECT_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK modules #----------------------------------------------------------------------------- #add_subdirectory(Modules) #----------------------------------------------------------------------------- # CTK plugins #----------------------------------------------------------------------------- # The CMake code in this section *must* be in the top-level CMakeLists.txt file macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^$(project-plugin-base)_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() include(${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Plugins.cmake) ctkMacroSetupPlugins(${PROJECT_PLUGINS} BUILD_OPTION_PREFIX ${MY_PROJECT_NAME}_ BUILD_ALL ${${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS}) #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Apps/$(project-app-name)) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables include(mitkSetupCPack) # Customize CPack variables for this project include(CPackSetup) list(APPEND CPACK_CREATE_DESKTOP_LINKS "${MY_APP_NAME}") configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake") # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- diff --git a/CMake/BuildConfigurations/All.cmake b/CMake/BuildConfigurations/All.cmake index 2bbbfaf858..6a3b24125e 100644 --- a/CMake/BuildConfigurations/All.cmake +++ b/CMake/BuildConfigurations/All.cmake @@ -1,51 +1,45 @@ set(MITK_CONFIG_PACKAGES ) set(_apple_package_excludes) set(_package_excludes ${_apple_package_excludes} OpenCL OpenMP SYSTEM_Boost Boost_LIBRARIES SYSTEM_PYTHON SUPERBUILD - BiophotonicsHardware_SpectroCam POLHEMUS_TRACKER - - US_DiPhAS_SDK - GALIL_HARDWARE - OPHIR_PYRO_HARDWARE - MICROBIRD_TRACKER MICROBIRD_TRACKER_INCLUDE_DIR MICROBIRD_TRACKER_LIB MICRON_TRACKER OPTITRACK_TRACKER SPACENAVIGATOR TOF_KINECT TOF_KINECTV2 TOF_MESASR4000 TOF_PMDCAMBOARD TOF_PMDCAMCUBE TOF_PMDO3 US_TELEMED_SDK videoInput WIIMOTE ) get_cmake_property(_cache_vars CACHE_VARIABLES) foreach(_cache_var ${_cache_vars}) string(REGEX REPLACE "MITK_USE_(.+)" "\\1" _package "${_cache_var}") if(_package AND NOT _package STREQUAL _cache_var) list(FIND _package_excludes ${_package} _index) if(_index EQUAL -1) list(APPEND MITK_CONFIG_PACKAGES ${_package}) endif() endif() endforeach() set(MITK_BUILD_ALL_APPS ON CACHE BOOL "Build all MITK applications" FORCE) set(MITK_BUILD_ALL_PLUGINS ON CACHE BOOL "Build all MITK plugins" FORCE) set(MITK_BUILD_EXAMPLES ON CACHE BOOL "Build the MITK examples" FORCE) set(BLUEBERRY_BUILD_ALL_PLUGINS ON CACHE BOOL "Build all BlueBerry plugins" FORCE) diff --git a/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake b/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake deleted file mode 100644 index 4a881e5fb6..0000000000 --- a/CMake/BuildConfigurations/camiPhotoacousticsSetup.cmake +++ /dev/null @@ -1,25 +0,0 @@ -message(STATUS "Configuring MITK Photoacoustics Setup Build") - -# Enable open cv and open igt link, which is a necessary configuration -set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) -set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) -set(MITK_USE_US_DiPhAS_SDK ON CACHE BOOL "Use DiPhAS SDK" FORCE) -set(MITK_US_DiPhAS_SDK_PATH "C:/Users/dkfz/Source/Repos/UltrasoundResearchPlatform_SDK/UltrasoundResearchPlatformSDK_Cpp/x64" CACHE PATH "DiPhAS SDK Path") - -set(MITK_USE_OPHIR_PYRO_HARDWARE ON CACHE BOOL "Use the Ophir sensor build-in in OPOTEK Phocus Mobile" FORCE) -set(MITK_OPHIR_API_PATH "C:/OphirCppWrapper" CACHE PATH "Ophir API Path") - -set(MITK_USE_GALIL_HARDWARE ON CACHE BOOL "Use hardware build-in in OPOTEK Phocus Mobile" FORCE) -set(MITK_GALIL_API_PATH "C:/Program Files (x86)/Galil/gclib" CACHE PATH "Galil API Path") - -# Enable default plugins and the navigation modules -set(MITK_CONFIG_PLUGINS - org.mitk.gui.qt.datamanager - org.mitk.gui.qt.stdmultiwidgeteditor - org.mitk.gui.qt.imagenavigator - org.mitk.gui.qt.properties - org.mitk.gui.qt.viewnavigator - org.mitk.gui.qt.ultrasound - org.mitk.gui.qt.lasercontrol -) - diff --git a/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake b/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake deleted file mode 100644 index 0b05599c4e..0000000000 --- a/CMake/BuildConfigurations/camiPhotoacousticsWorkstation.cmake +++ /dev/null @@ -1,22 +0,0 @@ -message(STATUS "Configuring MITK Photoacoustics Setup Build") - -# Enable open cv and open igt link, which is a necessary configuration -set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) -set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) - -set(MITK_USE_OpenCL ON CACHE BOOL "MITK Use OpenCL Library" FORCE) - -# Also enable plugins often used in photoacoustics -set(MITK_CONFIG_PLUGINS - org.mitk.gui.qt.datamanager - org.mitk.gui.qt.stdmultiwidgeteditor - org.mitk.gui.qt.imagenavigator - org.mitk.gui.qt.properties - org.mitk.gui.qt.viewnavigator - org.mitk.gui.qt.ultrasound - org.mitk.gui.qt.photoacoustics.imageprocessing - org.mitk.gui.qt.measurementtoolbox - org.mitk.gui.qt.pointsetinteraction -) - -set(BUILD_PhotoacousticBeamformingTool ON CACHE BOOL "Build commandline tools for Beamforming" FORCE) diff --git a/CMake/MITKDashboardScript.download.cmake b/CMake/MITKDashboardScript.download.cmake index 7ff24c8582..a6f9daa5b3 100644 --- a/CMake/MITKDashboardScript.download.cmake +++ b/CMake/MITKDashboardScript.download.cmake @@ -1,698 +1,698 @@ #[============================================================================[ Helper functions ]============================================================================] function(get_macos_codename) set(macos_codename "") set(software_license_file "\ /System/Library/CoreServices/Setup Assistant.app\ /Contents/Resources/en.lproj/OSXSoftwareLicense.rtf") if(EXISTS "${software_license_file}") file(READ "${software_license_file}" software_license) if(software_license MATCHES "SOFTWARE LICENSE AGREEMENT FOR macOS ([^\n]+)") set(macos_codename "${CMAKE_MATCH_1}") endif() endif() set(${ARGV0} ${macos_codename} PARENT_SCOPE) endfunction() function(get_macos_name) set(macos_name "macOS") get_macos_codename(macos_codename) if(macos_codename) set(macos_name "${macos_name} ${macos_codename}") endif() execute_process( RESULT_VARIABLE error_code OUTPUT_VARIABLE version OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND "sw_vers" "-productVersion") if(0 EQUAL error_code AND version) set(macos_name "${macos_name} ${version}") endif() set(${ARGV0} ${macos_name} PARENT_SCOPE) endfunction() function(get_linux_name) set(linux_name "Linux") set(os_release_file "/etc/os-release") if(EXISTS "${os_release_file}") file(STRINGS "${os_release_file}" os_release) set(name "") set(version_id "") foreach(line ${os_release}) if(NOT name AND line MATCHES "^NAME=[\"]?([^\"]+)") set(name "${CMAKE_MATCH_1}") continue() endif() if(NOT version_id AND line MATCHES "^VERSION_ID=\"?([^\"]+)") set(version_id "${CMAKE_MATCH_1}") continue() endif() if(name AND version_id) break() endif() endforeach() if(name) set(linux_name "${name}") endif() if(version_id) set(linux_name "${linux_name} ${version_id}") endif() endif() set(${ARGV0} ${linux_name} PARENT_SCOPE) endfunction() function(get_windows_name) set(windows_name "Windows") execute_process( RESULT_VARIABLE error_code OUTPUT_VARIABLE version OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND "wmic" "os" "get" "Version" "-value") if(0 EQUAL error_code AND version) if(version MATCHES "Version=([0-9]+)\\.([0-9]+)") set(windows_name "${windows_name} ${CMAKE_MATCH_1}") if(NOT 0 EQUAL CMAKE_MATCH_2) set(windows_name "${windows_name}.${CMAKE_MATCH_2}") endif() endif() endif() set(${ARGV0} ${windows_name} PARENT_SCOPE) endfunction() function(get_os_name) set(os_name "") if(APPLE) get_macos_name(os_name) elseif(UNIX) get_linux_name(os_name) elseif(WIN32) get_windows_name(os_name) endif() set(${ARGV0} ${os_name} PARENT_SCOPE) endfunction() function(download_string) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "URL;OUTPUT_VARIABLE" "") get_temp_directory(temp_dir) string(RANDOM random_filename) while(EXISTS "${temp_dir}/${random_filename}") string(RANDOM random_filename) endwhile() set(temp_output_file "${temp_dir}/${random_filename}") download_file( URL ${ARG_URL} OUTPUT_FILE ${temp_output_file} ERROR_CODE error_code) set(output "") if(EXISTS "${temp_output_file}") file(READ "${temp_output_file}" output) file(REMOVE "${temp_output_file}") endif() set(${ARG_OUTPUT_VARIABLE} ${output} PARENT_SCOPE) endfunction() function(find_vswhere) get_temp_directory(temp_dir) set(latest_vswhere "${temp_dir}/vswhere.exe") set(vswhere "vswhere.exe-NOTFOUND") if(EXISTS "${latest_vswhere}") set(vswhere "${latest_vswhere}") else() set(program_files_x86 "PROGRAMFILES(X86)") set(program_files_x86 "$ENV{${program_files_x86}}") set(system_vswhere "${program_files_x86}/Microsoft Visual Studio/Installer/vswhere.exe") if(EXISTS "${system_vswhere}") set(vswhere "${system_vswhere}") else() download_string( URL "https://api.github.com/repos/microsoft/vswhere/releases/latest" OUTPUT_VARIABLE latest_vswhere_json) if(latest_vswhere_json MATCHES "\"browser_download_url\": *\"([^\"]*)\"") download_file( URL "${CMAKE_MATCH_1}" OUTPUT_FILE "${latest_vswhere}" ERROR_CODE error_code) if (0 EQUAL error_code) set(vswhere "${latest_vswhere}") endif() endif() endif() endif() set(${ARGV0} "${vswhere}" PARENT_SCOPE) endfunction() function(vswhere) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "PROPERTY;OUTPUT_VARIABLE" "") set(property_value "") if(CTEST_CMAKE_GENERATOR MATCHES "^Visual Studio ([0-9]+)") set(major_version "${CMAKE_MATCH_1}") math(EXPR next_major_version "${major_version} + 1") find_vswhere(vswhere) if (vswhere) execute_process( OUTPUT_VARIABLE property_value OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND ${vswhere} "-requires" "Microsoft.VisualStudio.Workload.NativeDesktop" "-version" "[${major_version},${next_major_version})" "-property" "${ARG_PROPERTY}" "-format" "value") endif() endif() set(${ARG_OUTPUT_VARIABLE} ${property_value} PARENT_SCOPE) endfunction() function(get_visual_studio_name) set(visual_studio_name "Visual Studio") if(CTEST_CMAKE_GENERATOR MATCHES "^Visual Studio [0-9]+ ([0-9]+)") set(product_line_version "${CMAKE_MATCH_1}") set(visual_studio_name "${visual_studio_name} ${product_line_version}") vswhere(PROPERTY "catalog_productDisplayVersion" OUTPUT_VARIABLE product_display_version) if(product_display_version) set(visual_studio_name "${visual_studio_name} ${product_display_version}") endif() endif() set(${ARGV0} ${visual_studio_name} PARENT_SCOPE) endfunction() function(get_compiler_name) set(compiler_name "") if(CTEST_CMAKE_GENERATOR MATCHES "^Visual Studio") get_visual_studio_name(compiler_name) else() get_temp_directory(temp_dir) file(WRITE "${temp_dir}/src/CMakeLists.txt" "\ project(probe C) message(STATUS \"CMAKE_C_COMPILER_ID=\\\"\${CMAKE_C_COMPILER_ID}\\\"\") message(STATUS \"CMAKE_C_COMPILER_VERSION=\\\"\${CMAKE_C_COMPILER_VERSION}\\\"\")") file(REMOVE_RECURSE "${temp_dir}/build") unset(options) foreach(option ${MITK_SUPERBUILD_OPTIONS}) list(APPEND options "-D" "${option}") endforeach() execute_process( RESULT_VARIABLE error_code OUTPUT_VARIABLE compiler ERROR_QUIET COMMAND ${CMAKE_COMMAND} "-S" "${temp_dir}/src" "-B" "${temp_dir}/build" "-G" "${CTEST_CMAKE_GENERATOR}" ${options}) if(0 EQUAL error_code) if(compiler MATCHES "CMAKE_C_COMPILER_ID=\"([^\"]*)\"") set(compiler_name "${CMAKE_MATCH_1}") if(compiler MATCHES "CMAKE_C_COMPILER_VERSION=\"([^\"]*)\"") set(version "${CMAKE_MATCH_1}") if(version MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)") set(version "${CMAKE_MATCH_1}") endif() string(REGEX REPLACE "\\.0$" "" version "${version}") set(compiler_name "${compiler_name} ${version}") endif() endif() endif() endif() set(${ARGV0} ${compiler_name} PARENT_SCOPE) endfunction() function(get_default_build_name) get_os_name(default_build_name) get_compiler_name(compiler_name) if(compiler_name) set(default_build_name "${default_build_name} ${compiler_name}") endif() set(default_build_name "${default_build_name} ${CTEST_BUILD_CONFIGURATION}") if(MITK_BUILD_CONFIGURATION) set(default_build_name "${default_build_name} ${MITK_BUILD_CONFIGURATION}") endif() if(MITK_BUILD_NAME_SUFFIX) set(default_build_name "${default_build_name} ${MITK_BUILD_NAME_SUFFIX}") endif() set(${ARGV0} ${default_build_name} PARENT_SCOPE) endfunction() function(git) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "WORKING_DIRECTORY;OUTPUT_VARIABLE;RESULT_VARIABLE" "") if(NOT ARG_WORKING_DIRECTORY) set(ARG_WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}") endif() get_filename_component(ARG_WORKING_DIRECTORY "${ARG_WORKING_DIRECTORY}" ABSOLUTE) execute_process( WORKING_DIRECTORY "${ARG_WORKING_DIRECTORY}" RESULT_VARIABLE error_code OUTPUT_VARIABLE output OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND "${CTEST_GIT_COMMAND}" ${ARG_UNPARSED_ARGUMENTS}) if(ARG_OUTPUT_VARIABLE) set(${ARG_OUTPUT_VARIABLE} ${output} PARENT_SCOPE) endif() if(ARG_RESULT_VARIABLE) set(${ARG_RESULT_VARIABLE} ${error_code} PARENT_SCOPE) endif() endfunction() function(git_log) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "WORKING_DIRECTORY;COMMIT_HASH;COMMITTER;SUBJECT" "") if(NOT ARG_WORKING_DIRECTORY) set(ARG_WORKING_DIRECTORY "${CTEST_SOURCE_DIRECTORY}") endif() get_filename_component(ARG_WORKING_DIRECTORY "${ARG_WORKING_DIRECTORY}" ABSOLUTE) set(args WORKING_DIRECTORY "${ARG_WORKING_DIRECTORY}" "log" "-1") if(ARG_COMMIT_HASH) unset(commit_hash) git(OUTPUT_VARIABLE commit_hash ${args} "--pretty=%h" ) if(commit_hash) set(${ARG_COMMIT_HASH} ${commit_hash} PARENT_SCOPE) endif() endif() if(ARG_COMMITTER) unset(committer) git(OUTPUT_VARIABLE committer ${args} "--pretty=%cn" ) if(committer) set(${ARG_COMMITTER} ${committer} PARENT_SCOPE) endif() endif() if(ARG_SUBJECT) unset(subject) git(OUTPUT_VARIABLE subject ${args} "--pretty=%s" ) if(subject) set(${ARG_SUBJECT} ${subject} PARENT_SCOPE) endif() endif() endfunction() function(rm) execute_process(COMMAND ${CMAKE_COMMAND} "-E" "rm" "-rf" ${ARGN}) endfunction() function(submit) cmake_parse_arguments(PARSE_ARGV 0 ARG "" "" "PARTS") if(MITK_SUBMIT_URL) set(submit_url "SUBMIT_URL" "${MITK_SUBMIT_URL}") else() unset(submit_url) endif() if(MITK_AUTH_TOKEN) set(http_header HTTPHEADER "Authorization: Bearer ${MITK_AUTH_TOKEN}") else() unset(http_header) endif() ctest_submit(${submit_url} ${http_header} RETRY_COUNT 3 RETRY_DELAY 5 PARTS ${ARG_PARTS}) endfunction() #[============================================================================[ Actual script ]============================================================================] -cmake_minimum_required(VERSION 3.15 FATAL_ERROR) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) find_program(CTEST_GIT_COMMAND git) if(NOT CTEST_GIT_COMMAND) message(FATAL_ERROR "Git not found") endif() if(NOT CTEST_CMAKE_GENERATOR MATCHES "^Visual Studio") unset(CTEST_CMAKE_GENERATOR_PLATFORM) endif() if(CTEST_CMAKE_GENERATOR MATCHES "^(Unix Makefiles|Ninja)$") set(CTEST_USE_LAUNCHERS ON) endif() if(NOT CTEST_SITE) unset(CTEST_SITE) site_name(CTEST_SITE) endif() if(NOT CTEST_BUILD_NAME) get_default_build_name(CTEST_BUILD_NAME) endif() set(CTEST_SOURCE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/MITK") set(CTEST_BINARY_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build") set(indent " ") message("CTest settings") if(MITK_SUBMIT_URL) message("${indent}Submit URL: ${MITK_SUBMIT_URL}") endif() message("\ ${indent}Dashboard model: ${CTEST_DASHBOARD_MODEL} ${indent}Build name: ${CTEST_BUILD_NAME} ${indent}Site: ${CTEST_SITE}") if(MITK_CLEAN_SOURCE_DIR OR MITK_CLEAN_BINARY_DIR) message("Clean") if(MITK_CLEAN_SOURCE_DIR) set(clean_dir "${CMAKE_CURRENT_SOURCE_DIR}/src") message("${indent}Source directory: ${clean_dir}") rm("${clean_dir}") endif() if(MITK_CLEAN_BINARY_DIR) set(clean_dir "${CMAKE_CURRENT_SOURCE_DIR}/build") message("${indent}Binary directory: ${clean_dir}") rm("${clean_dir}") endif() endif() message("MITK repository") if(NOT EXISTS "${CTEST_SOURCE_DIRECTORY}") message("\ ${indent}Clone repository: ${MITK_REPOSITORY} ${indent}Branch: ${MITK_BRANCH}") set(CTEST_CHECKOUT_COMMAND "\"${CTEST_GIT_COMMAND}\" clone --branch=${MITK_BRANCH} -- ${MITK_REPOSITORY} MITK") ctest_start(${CTEST_DASHBOARD_MODEL}) else() git_log(COMMIT_HASH old_revision COMMITTER committer SUBJECT subject) message("\ ${indent}Update repository: ${CTEST_SOURCE_DIRECTORY} ${indent}Branch: ${MITK_BRANCH} ${indent}Old revision: ${old_revision} (committed by ${committer}) ${indent}${indent}${subject}") ctest_start(${CTEST_DASHBOARD_MODEL}) - set(CTEST_UPDATE_OPTIONS "origin ${MITK_BRANCH}") + set(CTEST_UPDATE_OPTIONS "--tags origin ${MITK_BRANCH}") ctest_update(RETURN_VALUE return_value) if(-1 EQUAL return_value) return() endif() git_log(COMMIT_HASH new_revision) if(new_revision STREQUAL old_revision) message("${indent}New revision: up-to-date") else() git_log(COMMITTER committer SUBJECT subject) message("\ ${indent}New revision: ${new_revision} (committed by ${committer}) ${indent}${indent}${subject}") endif() endif() unset(extension_dirs) if(MITK_EXTENSIONS) list(LENGTH MITK_EXTENSIONS mitk_extensions_size) math(EXPR max_index "${mitk_extensions_size} - 1") foreach(name_index RANGE 0 ${max_index} 3) list(GET MITK_EXTENSIONS ${name_index} name) math(EXPR url_index "${name_index} + 1") list(GET MITK_EXTENSIONS ${url_index} url) math(EXPR branch_index "${name_index} + 2") list(GET MITK_EXTENSIONS ${branch_index} branch) message("${name} repository") set(extension_dir "${CMAKE_CURRENT_SOURCE_DIR}/src/${name}") list(APPEND extension_dirs "${extension_dir}") if(NOT EXISTS "${extension_dir}") message("\ ${indent}Clone repository: ${url} ${indent}Branch: ${branch}") git("clone" "--quiet" "--branch=${branch}" "${url}" "${name}" WORKING_DIRECTORY "${extension_dir}/..") else() git_log(COMMIT_HASH old_revision COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${extension_dir}") message("\ ${indent}Update repository: ${extension_dir} ${indent}Branch: ${branch} ${indent}Old revision: ${old_revision} (committed by ${committer}) ${indent}${indent}${subject}") - git("fetch" "--quiet" "origin" "${branch}" + git("fetch" "--quiet" "--tags" "origin" "${branch}" WORKING_DIRECTORY "${extension_dir}") git("diff" "--quiet" "HEAD" "FETCH_HEAD" WORKING_DIRECTORY "${extension_dir}" RESULT_VARIABLE error_code) if(NOT error_code EQUAL 0) git("reset" "--quiet" "--hard" "FETCH_HEAD" WORKING_DIRECTORY "${extension_dir}") endif() git_log(COMMIT_HASH new_revision WORKING_DIRECTORY "${extension_dir}") if(new_revision STREQUAL old_revision) message("${indent}New revision: up-to-date") else() git_log(COMMITTER committer SUBJECT subject WORKING_DIRECTORY "${extension_dir}") message("\ ${indent}New revision: ${new_revision} (committed by ${committer}) ${indent}${indent}${subject}") endif() endif() endforeach() endif() submit(PARTS Update) set(options "-D" "MITK_CTEST_SCRIPT_MODE:STRING=${CTEST_DASHBOARD_MODEL}" # "-D" "SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE" ) if(extension_dirs) string (REPLACE ";" "\\\;" extension_dirs "${extension_dirs}") list(APPEND options "-D" "MITK_EXTENSION_DIRS:STRING=${extension_dirs}") endif() if(MITK_BUILD_CONFIGURATION) list(APPEND options "-D" "MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION}") endif() if(MITK_BUILD_OPTIONS) get_temp_directory(temp_dir) set(mitk_initial_cache_file "${temp_dir}/MITKInitialCache.cmake") file(WRITE "${mitk_initial_cache_file}" "") foreach(mitk_option ${MITK_BUILD_OPTIONS}) if(mitk_option MATCHES "^([^:]+):([^=]+)=(.*)") set(var "${CMAKE_MATCH_1}") set(type "${CMAKE_MATCH_2}") set(value "${CMAKE_MATCH_3}") file(APPEND "${mitk_initial_cache_file}" "set(${var} \"${value}\" CACHE ${type} \"\" FORCE)\n") endif() endforeach() list(APPEND options "-D" "MITK_INITIAL_CACHE_FILE:FILEPATH=${mitk_initial_cache_file}") endif() foreach(option ${MITK_SUPERBUILD_OPTIONS}) list(APPEND options "-D" "${option}") endforeach() ctest_configure(OPTIONS "${options}" RETURN_VALUE return_value) submit(PARTS Configure) if(NOT 0 EQUAL return_value) submit(PARTS Done) return() endif() include("${CTEST_BINARY_DIRECTORY}/SuperBuildTargets.cmake") if(NOT SUPERBUILD_TARGETS) submit(PARTS Done) message(FATAL_ERROR "SUPERBUILD_TARGETS variable not set in SuperBuildTargets.cmake") else() set(mitk_targets MITK-Data MITK-Utilities MITK-Configure MITK-build ) list(LENGTH SUPERBUILD_TARGETS n) list(LENGTH mitk_targets num_mitk_targets) math(EXPR n "${n} + ${num_mitk_targets}") set(i 1) unset(append) foreach(target ${SUPERBUILD_TARGETS} ${mitk_targets}) message("MITK superbuild - [${i}/${n}] Build ${target}") if(NOT target IN_LIST mitk_targets) list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION ".*") set(pop_warning_exception TRUE) else() set(pop_warning_exception FALSE) endif() ctest_build(TARGET ${target} NUMBER_ERRORS num_build_errors NUMBER_WARNINGS num_build_warnings RETURN_VALUE return_value ${append}) if(pop_warning_exception) list(POP_BACK CTEST_CUSTOM_WARNING_EXCEPTION) endif() submit(PARTS Build) if(0 LESS num_build_warnings) message("${indent}${num_build_warnings} warning(s)") endif() if(NOT (0 EQUAL return_value AND 0 EQUAL num_build_errors)) submit(PARTS Done) message("${indent}${num_build_errors} error(s)") return() else() message("${indent}${target} was built successfully") endif() if(NOT append) set(append APPEND) endif() math(EXPR i "${i} + 1") endforeach() endif() if(MITK_BUILD_DOCUMENTATION) message("MITK build - Build documentation") list(APPEND CTEST_CUSTOM_WARNING_EXCEPTION ".*") ctest_build(TARGET doc BUILD "${CTEST_BINARY_DIRECTORY}/MITK-build" NUMBER_ERRORS num_doc_errors NUMBER_WARNINGS num_doc_warnings RETURN_VALUE return_value APPEND ) list(POP_BACK CTEST_CUSTOM_WARNING_EXCEPTION) submit(PARTS Build) if(0 LESS num_doc_warnings) message("${indent}${num_doc_warnings} warning(s)") endif() if(NOT (0 EQUAL return_value AND 0 EQUAL num_doc_errors)) submit(PARTS Done) message("${indent}${num_doc_errors} error(s)") return() else() message("${indent}Documentation was built successfully") endif() endif() message("Run unit tests...") set(CTEST_CONFIGURATION_TYPE "${CTEST_BUILD_CONFIGURATION}") ctest_test( BUILD "${CTEST_BINARY_DIRECTORY}/MITK-build" PARALLEL_LEVEL 4) submit(PARTS Test Done) message("Done") diff --git a/CMake/NSIS.template.in b/CMake/NSIS.template.in index f111eadbc1..47f5d675ff 100644 --- a/CMake/NSIS.template.in +++ b/CMake/NSIS.template.in @@ -1,1086 +1,1014 @@ ; CPack install script designed for a nmake build ;-------------------------------- ; You must define these values !define VERSION "@CPACK_PACKAGE_VERSION@" !define PATCH "@CPACK_PACKAGE_VERSION_PATCH@" !define INST_DIR "@CPACK_TEMPORARY_DIRECTORY@" ;-------------------------------- ;Variables Var MUI_TEMP Var STARTMENU_FOLDER Var SV_ALLUSERS Var START_MENU Var DO_NOT_ADD_TO_PATH Var ADD_TO_PATH_ALL_USERS Var ADD_TO_PATH_CURRENT_USER Var INSTALL_DESKTOP Var IS_DEFAULT_INSTALLDIR ;-------------------------------- ;Include Modern UI !include "MUI.nsh" ;Default installation folder InstallDir "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ;Allow for very long title on the welcome page !define MUI_WELCOMEPAGE_TITLE_3LINES ;-------------------------------- ;General ;Name and file Name "@CPACK_NSIS_PACKAGE_NAME@" OutFile "@CPACK_TOPLEVEL_DIRECTORY@/@CPACK_OUTPUT_FILE_NAME@" ;Set compression SetCompressor @CPACK_NSIS_COMPRESSOR@ RequestExecutionLevel user @CPACK_NSIS_DEFINES@ !include Sections.nsh ;--- Component support macros: --- ; The code for the add/remove functionality is from: ; http://nsis.sourceforge.net/Add/Remove_Functionality ; It has been modified slightly and extended to provide ; inter-component dependencies. Var AR_SecFlags Var AR_RegFlags @CPACK_NSIS_SECTION_SELECTED_VARS@ ; Loads the "selected" flag for the section named SecName into the ; variable VarName. !macro LoadSectionSelectedIntoVar SecName VarName SectionGetFlags ${${SecName}} $${VarName} IntOp $${VarName} $${VarName} & ${SF_SELECTED} ;Turn off all other bits !macroend ; Loads the value of a variable... can we get around this? !macro LoadVar VarName IntOp $R0 0 + $${VarName} !macroend ; Sets the value of a variable !macro StoreVar VarName IntValue IntOp $${VarName} 0 + ${IntValue} !macroend !macro InitSection SecName ; This macro reads component installed flag from the registry and ;changes checked state of the section on the components page. ;Input: section index constant name specified in Section command. ClearErrors ;Reading component status from registry ReadRegDWORD $AR_RegFlags HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" "Installed" IfErrors "default_${SecName}" ;Status will stay default if registry value not found ;(component was never installed) IntOp $AR_RegFlags $AR_RegFlags & ${SF_SELECTED} ;Turn off all other bits SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading default section flags IntOp $AR_SecFlags $AR_SecFlags & 0xFFFE ;Turn lowest (enabled) bit off IntOp $AR_SecFlags $AR_RegFlags | $AR_SecFlags ;Change lowest bit ; Note whether this component was installed before !insertmacro StoreVar ${SecName}_was_installed $AR_RegFlags IntOp $R0 $AR_RegFlags & $AR_RegFlags ;Writing modified flags SectionSetFlags ${${SecName}} $AR_SecFlags "default_${SecName}:" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected !macroend !macro FinishSection SecName ; This macro reads section flag set by user and removes the section ;if it is not selected. ;Then it writes component installed flag to registry ;Input: section index constant name specified in Section command. SectionGetFlags ${${SecName}} $AR_SecFlags ;Reading section flags ;Checking lowest bit: IntOp $AR_SecFlags $AR_SecFlags & ${SF_SELECTED} IntCmp $AR_SecFlags 1 "leave_${SecName}" ;Section is not selected: ;Calling Section uninstall macro and writing zero installed flag !insertmacro "Remove_${${SecName}}" WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \ "Installed" 0 Goto "exit_${SecName}" "leave_${SecName}:" ;Section is selected: WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@\Components\${SecName}" \ "Installed" 1 "exit_${SecName}:" !macroend ; NSIS example code to only include some code if a file exists at compile time (whereas IfFileExists works at runtime) ; See http://nsis.sourceforge.net/Check_if_a_file_exists_at_compile_time for documentation !macro !defineifexist _VAR_NAME _FILE_NAME !tempfile _TEMPFILE !system 'if exist "${_FILE_NAME}" echo !define ${_VAR_NAME} > "${_TEMPFILE}"' !include '${_TEMPFILE}' !delfile '${_TEMPFILE}' !undef _TEMPFILE !macroend !define !defineifexist "!insertmacro !defineifexist" ; Determine whether the selection of SecName changed !macro MaybeSelectionChanged SecName !insertmacro LoadVar ${SecName}_selected SectionGetFlags ${${SecName}} $R1 IntOp $R1 $R1 & ${SF_SELECTED} ;Turn off all other bits ; See if the status has changed: IntCmp $R0 $R1 "${SecName}_unchanged" !insertmacro LoadSectionSelectedIntoVar ${SecName} ${SecName}_selected IntCmp $R1 ${SF_SELECTED} "${SecName}_was_selected" !insertmacro "Deselect_required_by_${SecName}" goto "${SecName}_unchanged" "${SecName}_was_selected:" !insertmacro "Select_${SecName}_depends" "${SecName}_unchanged:" !macroend ;--- End of Add/Remove macros --- ;-------------------------------- ;Interface Settings !define MUI_HEADERIMAGE !define MUI_ABORTWARNING ;-------------------------------- ; path functions !verbose 3 !include "WinMessages.NSH" !verbose 4 ;---------------------------------------- ; based upon a script of "Written by KiCHiK 2003-01-18 05:57:02" ;---------------------------------------- !verbose 3 !include "WinMessages.NSH" !verbose 4 ;==================================================== ; get_NT_environment ; Returns: the selected environment ; Output : head of the stack ;==================================================== !macro select_NT_profile UN Function ${UN}select_NT_profile StrCmp $ADD_TO_PATH_ALL_USERS "1" 0 environment_single DetailPrint "Selected environment for all users" Push "all" Return environment_single: DetailPrint "Selected environment for current user only." Push "current" Return FunctionEnd !macroend !insertmacro select_NT_profile "" !insertmacro select_NT_profile "un." ;---------------------------------------------------- !define NT_current_env 'HKCU "Environment"' !define NT_all_env 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !ifndef WriteEnvStr_RegKey !ifdef ALL_USERS !define WriteEnvStr_RegKey \ 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' !else !define WriteEnvStr_RegKey 'HKCU "Environment"' !endif !endif ; AddToPath - Adds the given dir to the search path. ; Input - head of the stack ; Note - Win9x systems requires reboot Function AddToPath Exch $0 Push $1 Push $2 Push $3 # don't add if the path doesn't exist IfFileExists "$0\*.*" "" AddToPath_done ReadEnvStr $1 PATH ; if the path is too long for a NSIS variable NSIS will return a 0 ; length string. If we find that, then warn and skip any path ; modification as it will trash the existing path. StrLen $2 $1 IntCmp $2 0 CheckPathLength_ShowPathWarning CheckPathLength_Done CheckPathLength_Done CheckPathLength_ShowPathWarning: DetailPrint "Warning: Could not modify PATH variable - current PATH is too long.\n\ This does not impact the functionality of MITK itself, but you will not be able to start\ it from anywhere via command line." ; The message box is probably too much of an escalation, most users won't care or notice ;Messagebox MB_OK|MB_ICONEXCLAMATION "Warning! PATH too long installer unable to modify PATH!" Goto AddToPath_done CheckPathLength_Done: Push "$1;" Push "$0;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$0\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done GetFullPathName /SHORT $3 $0 Push "$1;" Push "$3;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Push "$1;" Push "$3\;" Call StrStr Pop $2 StrCmp $2 "" "" AddToPath_done Call IsNT Pop $1 StrCmp $1 1 AddToPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" a FileSeek $1 -1 END FileReadByte $1 $2 IntCmp $2 26 0 +2 +2 # DOS EOF FileSeek $1 -1 END # write over EOF FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" FileClose $1 SetRebootFlag true Goto AddToPath_done AddToPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" ReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto DoTrim ReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" DoTrim: StrCmp $1 "" AddToPath_NTdoIt Push $1 Call Trim Pop $1 StrCpy $0 "$1;$0" AddToPath_NTdoIt: StrCmp $ADD_TO_PATH_ALL_USERS "1" WriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $0 Goto DoSend WriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $0 DoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 AddToPath_done: Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ; RemoveFromPath - Remove a given dir from the path ; Input: head of the stack Function un.RemoveFromPath Exch $0 Push $1 Push $2 Push $3 Push $4 Push $5 Push $6 IntFmt $6 "%c" 26 # DOS EOF Call un.IsNT Pop $1 StrCmp $1 1 unRemoveFromPath_NT ; Not on NT StrCpy $1 $WINDIR 2 FileOpen $1 "$1\autoexec.bat" r GetTempFileName $4 FileOpen $2 $4 w GetFullPathName /SHORT $0 $0 StrCpy $0 "SET PATH=%PATH%;$0" Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoop: FileRead $1 $3 StrCpy $5 $3 1 -1 # read last char StrCmp $5 $6 0 +2 # if DOS EOF StrCpy $3 $3 -1 # remove DOS EOF so we can compare StrCmp $3 "$0$\r$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0$\n" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "$0" unRemoveFromPath_dosLoopRemoveLine StrCmp $3 "" unRemoveFromPath_dosLoopEnd FileWrite $2 $3 Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopRemoveLine: SetRebootFlag true Goto unRemoveFromPath_dosLoop unRemoveFromPath_dosLoopEnd: FileClose $2 FileClose $1 StrCpy $1 $WINDIR 2 Delete "$1\autoexec.bat" CopyFiles /SILENT $4 "$1\autoexec.bat" Delete $4 Goto unRemoveFromPath_done unRemoveFromPath_NT: StrCmp $ADD_TO_PATH_ALL_USERS "1" unReadAllKey ReadRegStr $1 ${NT_current_env} "PATH" Goto unDoTrim unReadAllKey: ReadRegStr $1 ${NT_all_env} "PATH" unDoTrim: StrCpy $5 $1 1 -1 # copy last char StrCmp $5 ";" +2 # if last char != ; StrCpy $1 "$1;" # append ; Push $1 Push "$0;" Call un.StrStr ; Find `$0;` in $1 Pop $2 ; pos of our dir StrCmp $2 "" unRemoveFromPath_done ; else, it is in path # $0 - path to add # $1 - path var StrLen $3 "$0;" StrLen $4 $2 StrCpy $5 $1 -$4 # $5 is now the part before the path to remove StrCpy $6 $2 "" $3 # $6 is now the part after the path to remove StrCpy $3 $5$6 StrCpy $5 $3 1 -1 # copy last char StrCmp $5 ";" 0 +2 # if last char == ; StrCpy $3 $3 -1 # remove last char StrCmp $ADD_TO_PATH_ALL_USERS "1" unWriteAllKey WriteRegExpandStr ${NT_current_env} "PATH" $3 Goto unDoSend unWriteAllKey: WriteRegExpandStr ${NT_all_env} "PATH" $3 unDoSend: SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 unRemoveFromPath_done: Pop $6 Pop $5 Pop $4 Pop $3 Pop $2 Pop $1 Pop $0 FunctionEnd ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Uninstall stuff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ########################################### # Utility Functions # ########################################### ;==================================================== ; IsNT - Returns 1 if the current system is NT, 0 ; otherwise. ; Output: head of the stack ;==================================================== ; IsNT ; no input ; output, top of the stack = 1 if NT or 0 if not ; ; Usage: ; Call IsNT ; Pop $R0 ; ($R0 at this point is 1 or 0) !macro IsNT un Function ${un}IsNT Push $0 ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion StrCmp $0 "" 0 IsNT_yes ; we are not NT. Pop $0 Push 0 Return IsNT_yes: ; NT!!! Pop $0 Push 1 FunctionEnd !macroend !insertmacro IsNT "" !insertmacro IsNT "un." ; StrStr ; input, top of stack = string to search for ; top of stack-1 = string to search in ; output, top of stack (replaces with the portion of the string remaining) ; modifies no other variables. ; ; Usage: ; Push "this is a long ass string" ; Push "ass" ; Call StrStr ; Pop $R0 ; ($R0 at this point is "ass string") !macro StrStr un Function ${un}StrStr Exch $R1 ; st=haystack,old$R1, $R1=needle Exch ; st=old$R1,haystack Exch $R2 ; st=old$R1,old$R2, $R2=haystack Push $R3 Push $R4 Push $R5 StrLen $R3 $R1 StrCpy $R4 0 ; $R1=needle ; $R2=haystack ; $R3=len(needle) ; $R4=cnt ; $R5=tmp loop: StrCpy $R5 $R2 $R3 $R4 StrCmp $R5 $R1 done StrCmp $R5 "" done IntOp $R4 $R4 + 1 Goto loop done: StrCpy $R1 $R2 "" $R4 Pop $R5 Pop $R4 Pop $R3 Pop $R2 Exch $R1 FunctionEnd !macroend !insertmacro StrStr "" !insertmacro StrStr "un." Function Trim ; Added by Pelaca Exch $R1 Push $R2 Loop: StrCpy $R2 "$R1" 1 -1 StrCmp "$R2" " " RTrim StrCmp "$R2" "$\n" RTrim StrCmp "$R2" "$\r" RTrim StrCmp "$R2" ";" RTrim GoTo Done RTrim: StrCpy $R1 "$R1" -1 Goto Loop Done: Pop $R2 Exch $R1 FunctionEnd Function ConditionalAddToRegisty Pop $0 Pop $1 StrCmp "$0" "" ConditionalAddToRegisty_EmptyString WriteRegStr SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" \ "$1" "$0" ;MessageBox MB_OK "Set Registry: '$1' to '$0'" DetailPrint "Set install registry entry: '$1' to '$0'" ConditionalAddToRegisty_EmptyString: FunctionEnd ;-------------------------------- !ifdef CPACK_USES_DOWNLOAD Function DownloadFile IfFileExists $INSTDIR\* +2 CreateDirectory $INSTDIR Pop $0 ; Skip if already downloaded IfFileExists $INSTDIR\$0 0 +2 Return StrCpy $1 "@CPACK_DOWNLOAD_SITE@" try_again: NSISdl::download "$1/$0" "$INSTDIR\$0" Pop $1 StrCmp $1 "success" success StrCmp $1 "Cancelled" cancel MessageBox MB_OK "Download failed: $1" cancel: Return success: FunctionEnd !endif ;-------------------------------- ; Installation types @CPACK_NSIS_INSTALLATION_TYPES@ ;-------------------------------- ; Component sections @CPACK_NSIS_COMPONENT_SECTIONS@ ;-------------------------------- ; Define some macro setting for the gui @CPACK_NSIS_INSTALLER_MUI_ICON_CODE@ @CPACK_NSIS_INSTALLER_ICON_CODE@ @CPACK_NSIS_INSTALLER_MUI_COMPONENTS_DESC@ @CPACK_NSIS_INSTALLER_MUI_FINISHPAGE_RUN_CODE@ ;-------------------------------- ;Pages !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "@CPACK_RESOURCE_FILE_LICENSE@" Page custom InstallOptionsPage !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_REGISTRY_ROOT "SHCTX" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder" !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER @CPACK_NSIS_PAGE_COMPONENTS@ !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;-------------------------------- ;Languages !insertmacro MUI_LANGUAGE "English" ;first language is the default language !insertmacro MUI_LANGUAGE "Albanian" !insertmacro MUI_LANGUAGE "Arabic" !insertmacro MUI_LANGUAGE "Basque" !insertmacro MUI_LANGUAGE "Belarusian" !insertmacro MUI_LANGUAGE "Bosnian" !insertmacro MUI_LANGUAGE "Breton" !insertmacro MUI_LANGUAGE "Bulgarian" !insertmacro MUI_LANGUAGE "Croatian" !insertmacro MUI_LANGUAGE "Czech" !insertmacro MUI_LANGUAGE "Danish" !insertmacro MUI_LANGUAGE "Dutch" !insertmacro MUI_LANGUAGE "Estonian" !insertmacro MUI_LANGUAGE "Farsi" !insertmacro MUI_LANGUAGE "Finnish" !insertmacro MUI_LANGUAGE "French" !insertmacro MUI_LANGUAGE "German" !insertmacro MUI_LANGUAGE "Greek" !insertmacro MUI_LANGUAGE "Hebrew" !insertmacro MUI_LANGUAGE "Hungarian" !insertmacro MUI_LANGUAGE "Icelandic" !insertmacro MUI_LANGUAGE "Indonesian" !insertmacro MUI_LANGUAGE "Irish" !insertmacro MUI_LANGUAGE "Italian" !insertmacro MUI_LANGUAGE "Japanese" !insertmacro MUI_LANGUAGE "Korean" !insertmacro MUI_LANGUAGE "Kurdish" !insertmacro MUI_LANGUAGE "Latvian" !insertmacro MUI_LANGUAGE "Lithuanian" !insertmacro MUI_LANGUAGE "Luxembourgish" !insertmacro MUI_LANGUAGE "Macedonian" !insertmacro MUI_LANGUAGE "Malay" !insertmacro MUI_LANGUAGE "Mongolian" !insertmacro MUI_LANGUAGE "Norwegian" !insertmacro MUI_LANGUAGE "Polish" !insertmacro MUI_LANGUAGE "Portuguese" !insertmacro MUI_LANGUAGE "PortugueseBR" !insertmacro MUI_LANGUAGE "Romanian" !insertmacro MUI_LANGUAGE "Russian" !insertmacro MUI_LANGUAGE "Serbian" !insertmacro MUI_LANGUAGE "SerbianLatin" !insertmacro MUI_LANGUAGE "SimpChinese" !insertmacro MUI_LANGUAGE "Slovak" !insertmacro MUI_LANGUAGE "Slovenian" !insertmacro MUI_LANGUAGE "Spanish" !insertmacro MUI_LANGUAGE "Swedish" !insertmacro MUI_LANGUAGE "Thai" !insertmacro MUI_LANGUAGE "TradChinese" !insertmacro MUI_LANGUAGE "Turkish" !insertmacro MUI_LANGUAGE "Ukrainian" !insertmacro MUI_LANGUAGE "Welsh" ;-------------------------------- ;Reserve Files ;These files should be inserted before other files in the data block ;Keep these lines before any File command ;Only for solid compression (by default, solid compression is enabled for BZIP2 and LZMA) ReserveFile "NSIS.InstallOptions.ini" !insertmacro MUI_RESERVEFILE_INSTALLOPTIONS ;-------------------------------- ;Installer Sections Section "-Core installation" ;Use the entire tree produced by the INSTALL target. Keep the ;list of directories here in sync with the RMDir commands below. SetOutPath "$INSTDIR" @CPACK_NSIS_FULL_INSTALL@ - ; Check whether redistributables need to be installed - Call RedistributablePage - ;Store installation folder WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Create uninstaller WriteUninstaller "$INSTDIR\Uninstall.exe" Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty Push "DisplayVersion" Push "@CPACK_PACKAGE_VERSION@" Call ConditionalAddToRegisty Push "Publisher" Push "@CPACK_PACKAGE_VENDOR@" Call ConditionalAddToRegisty Push "UninstallString" Push "$INSTDIR\Uninstall.exe" Call ConditionalAddToRegisty Push "NoRepair" Push "1" Call ConditionalAddToRegisty !ifdef CPACK_NSIS_ADD_REMOVE ;Create add/remove functionality Push "ModifyPath" Push "$INSTDIR\AddRemove.exe" Call ConditionalAddToRegisty !else Push "NoModify" Push "1" Call ConditionalAddToRegisty !endif ; Optional registration Push "DisplayIcon" Push "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@" Call ConditionalAddToRegisty Push "HelpLink" Push "@CPACK_NSIS_HELP_LINK@" Call ConditionalAddToRegisty Push "URLInfoAbout" Push "@CPACK_NSIS_URL_INFO_ABOUT@" Call ConditionalAddToRegisty Push "Contact" Push "@CPACK_NSIS_CONTACT@" Call ConditionalAddToRegisty !insertmacro MUI_INSTALLOPTIONS_READ $INSTALL_DESKTOP "NSIS.InstallOptions.ini" "Field 5" "State" !insertmacro MUI_STARTMENU_WRITE_BEGIN Application ;Create shortcuts CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" @CPACK_NSIS_CREATE_ICONS@ @CPACK_NSIS_CREATE_ICONS_EXTRA@ CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe" ;Read a value from an InstallOptions INI file !insertmacro MUI_INSTALLOPTIONS_READ $DO_NOT_ADD_TO_PATH "NSIS.InstallOptions.ini" "Field 2" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_ALL_USERS "NSIS.InstallOptions.ini" "Field 3" "State" !insertmacro MUI_INSTALLOPTIONS_READ $ADD_TO_PATH_CURRENT_USER "NSIS.InstallOptions.ini" "Field 4" "State" ; Write special uninstall registry entries Push "StartMenu" Push "$STARTMENU_FOLDER" Call ConditionalAddToRegisty Push "DoNotAddToPath" Push "$DO_NOT_ADD_TO_PATH" Call ConditionalAddToRegisty Push "AddToPathAllUsers" Push "$ADD_TO_PATH_ALL_USERS" Call ConditionalAddToRegisty Push "AddToPathCurrentUser" Push "$ADD_TO_PATH_CURRENT_USER" Call ConditionalAddToRegisty Push "InstallToDesktop" Push "$INSTALL_DESKTOP" Call ConditionalAddToRegisty !insertmacro MUI_STARTMENU_WRITE_END @CPACK_NSIS_EXTRA_INSTALL_COMMANDS@ SectionEnd Section "-Add to path" Push $INSTDIR\bin StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0 Call AddToPath doNotAddToPath: SectionEnd ;-------------------------------- ; Create custom pages Function InstallOptionsPage !insertmacro MUI_HEADER_TEXT "Install Options" "Choose options for installing @CPACK_NSIS_PACKAGE_NAME@" !insertmacro MUI_INSTALLOPTIONS_DISPLAY "NSIS.InstallOptions.ini" FunctionEnd ; Author: Lilla (lilla@earthlink.net) 2003-06-13 ; function IsUserAdmin uses plugin \NSIS\PlusgIns\UserInfo.dll ; This function is based upon code in \NSIS\Contrib\UserInfo\UserInfo.nsi ; This function was tested under NSIS 2 beta 4 (latest CVS as of this writing). ; ; Usage: ; Call IsUserAdmin ; Pop $R0 ; at this point $R0 is "true" or "false" ; Function IsUserAdmin Push $R0 Push $R1 Push $R2 ClearErrors UserInfo::GetName IfErrors Win9x Pop $R1 UserInfo::GetAccountType Pop $R2 StrCmp $R2 "Admin" 0 Continue ; Observation: I get here when running Win98SE. (Lilla) ; The functions UserInfo.dll looks for are there on Win98 too, ; but just don't work. So UserInfo.dll, knowing that admin isn't required ; on Win98, returns admin anyway. (per kichik) ; MessageBox MB_OK 'User "$R1" is in the Administrators group' StrCpy $R0 "true" Goto Done Continue: ; You should still check for an empty string because the functions ; UserInfo.dll looks for may not be present on Windows 95. (per kichik) StrCmp $R2 "" Win9x StrCpy $R0 "false" ;MessageBox MB_OK 'User "$R1" is in the "$R2" group' Goto Done Win9x: ; comment/message below is by UserInfo.nsi author: ; This one means you don't need to care about admin or ; not admin because Windows 9x doesn't either ;MessageBox MB_OK "Error! This DLL can't run under Windows 9x!" StrCpy $R0 "true" Done: ;MessageBox MB_OK 'User= "$R1" AccountType= "$R2" IsUserAdmin= "$R0"' Pop $R2 Pop $R1 Exch $R0 FunctionEnd -Function RedistributablePage - ; Check whether the appropriate redistributable for this installer has been installed - StrCmp '@CPACK_LIBRARY_ARCHITECTURE@' 'x64' 0 +3 - SetRegView 64 - Goto done - StrCmp '@CPACK_LIBRARY_ARCHITECTURE@' 'x86' 0 +3 - SetRegView 32 - Goto done - ; The following line should not be reached, use for debugging - ; MessageBox MB_OK "Could not determine x86/x64 architecture during CPack installer configuration." - done: - ReadRegDword $1 HKLM "SOFTWARE\Microsoft\DevDiv\vc\Servicing\@CPACK_VISUAL_STUDIO_VERSION_MAJOR@.0\RuntimeMinimum" "Install" - - ; If installed show installed, else offer installation - StrCmp $1 1 RedistInstalled - - ; Offer Installation - ; MessageBox MB_YESNO "MITK requires the @CPACK_VISUAL_STUDIO_PRODUCT_NAME@ Redistributable to function. Do you wish to install it?" /SD IDYES IDNO endInstallationMissingRedist - - ; Verify that user has admin privileges - ; Otherwise they are not able to install the redistributable - Call IsUserAdmin - Exch $R0 - StrCmp $R0 "false" NoAdminRights - Pop $R0 - - SetOutPath $INSTDIR\thirdpartyinstallers - - ; We need compile time information on whether the redistributable installer exists. - ; If it does not exist using the "File" command will lead to errors. - ${!defineifexist} REDIST_INSTALLER_PRESENT @CPACK_PACKAGE_FILE_NAME@\thirdpartyinstallers\@CPACK_REDISTRIBUTABLE_FILE_NAME@ - - !ifdef REDIST_INSTALLER_PRESENT - ; Check at runtime whether the redistributable installer is available - IfFileExists $INSTDIR\thirdpartyinstallers\@CPACK_REDISTRIBUTABLE_FILE_NAME@ InstallRedist NoRedistInstaller - - InstallRedist: - - ClearErrors - File "@CPACK_PACKAGE_FILE_NAME@\thirdpartyinstallers\@CPACK_REDISTRIBUTABLE_FILE_NAME@" - ExecWait '"$INSTDIR\thirdpartyinstallers\@CPACK_REDISTRIBUTABLE_FILE_NAME@" /passive /norestart' - IfErrors endInstallationMissingRedist - - Goto RedistInstalled - - endInstallationMissingRedist: - Abort "Installation aborted. Missing required @CPACK_VISUAL_STUDIO_PRODUCT_NAME@ @CPACK_LIBRARY_ARCHITECTURE@ Redistributable" - !endif - - ; We are missing the redistributable installer, inform the user - NoRedistInstaller: - MessageBox MB_OK "Missing required @CPACK_VISUAL_STUDIO_PRODUCT_NAME@ @CPACK_LIBRARY_ARCHITECTURE@ Redistributable. You need to install it to use MITK." - Goto End - - ; The user does not have the required rights to install redistributables - NoAdminRights: - MessageBox MB_OK|MB_ICONSTOP "This MITK version requires the @CPACK_VISUAL_STUDIO_PRODUCT_NAME@ @CPACK_LIBRARY_ARCHITECTURE@ Redistributable.$\r$\n\ - Your user account does not have administrator privileges.$\r$\n\ - Please ask your system administrator to install the @CPACK_VISUAL_STUDIO_PRODUCT_NAME@ @CPACK_LIBRARY_ARCHITECTURE@ Redistributable." - Pop $R0 - Goto End - - ; No need to do anything - RedistInstalled: - Goto End - - End: -FunctionEnd - ;-------------------------------- ; determine admin versus local install Function un.onInit ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' Goto done noLM: ;Get installation folder from registry if available done: FunctionEnd ;--- Add/Remove callback functions: --- !macro SectionList MacroName ;This macro used to perform operation on multiple sections. ;List all of your components in following manner here. @CPACK_NSIS_COMPONENT_SECTION_LIST@ !macroend Section -FinishComponents ;Removes unselected components and writes component status to registry !insertmacro SectionList "FinishSection" !ifdef CPACK_NSIS_ADD_REMOVE ; Get the name of the installer executable System::Call 'kernel32::GetModuleFileNameA(i 0, t .R0, i 1024) i r1' StrCpy $R3 $R0 ; Strip off the last 13 characters, to see if we have AddRemove.exe StrLen $R1 $R0 IntOp $R1 $R0 - 13 StrCpy $R2 $R0 13 $R1 StrCmp $R2 "AddRemove.exe" addremove_installed ; We're not running AddRemove.exe, so install it CopyFiles $R3 $INSTDIR\AddRemove.exe addremove_installed: !endif SectionEnd ;--- End of Add/Remove callback functions --- ;-------------------------------- ; Component dependencies Function .onSelChange !insertmacro SectionList MaybeSelectionChanged FunctionEnd ;-------------------------------- ;Uninstaller Section Section "Uninstall" ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "StartMenu" ;MessageBox MB_OK "Start menu is in: $START_MENU" ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "DoNotAddToPath" ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathAllUsers" ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "AddToPathCurrentUser" ;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS" ReadRegStr $INSTALL_DESKTOP SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" "InstallToDesktop" ;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP " @CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS@ ;Remove files we installed. ;Keep the list of directories here in sync with the File commands above. @CPACK_NSIS_DELETE_FILES@ @CPACK_NSIS_DELETE_DIRECTORIES@ !ifdef CPACK_NSIS_ADD_REMOVE ;Remove the add/remove program Delete "$INSTDIR\AddRemove.exe" !endif ;Remove the uninstaller itself. Delete "$INSTDIR\Uninstall.exe" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_NAME@" ;Remove the installation directory if it is empty. RMDir "$INSTDIR" ; Remove the registry entries. DeleteRegKey SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" ; Removes all optional components !insertmacro SectionList "RemoveSection" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS@ @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" startMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors startMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" startMenuDeleteLoopDone startMenuDeleteLoop startMenuDeleteLoopDone: ; If the user changed the shortcut, then untinstall may not work. This should ; try to fix it. StrCpy $MUI_TEMP "$START_MENU" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" @CPACK_NSIS_DELETE_ICONS_EXTRA@ ;Delete empty start menu parent diretories StrCpy $MUI_TEMP "$SMPROGRAMS\$MUI_TEMP" secondStartMenuDeleteLoop: ClearErrors RMDir $MUI_TEMP GetFullPathName $MUI_TEMP "$MUI_TEMP\.." IfErrors secondStartMenuDeleteLoopDone StrCmp "$MUI_TEMP" "$SMPROGRAMS" secondStartMenuDeleteLoopDone secondStartMenuDeleteLoop secondStartMenuDeleteLoopDone: DeleteRegKey /ifempty SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" Push $INSTDIR\bin StrCmp $DO_NOT_ADD_TO_PATH_ "1" doNotRemoveFromPath 0 Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd ;-------------------------------- ; determine admin versus local install ; Is install for "AllUsers" or "JustMe"? ; Default to "JustMe" - set to "AllUsers" if admin or on Win9x ; This function is used for the very first "custom page" of the installer. ; This custom page does not show up visibly, but it executes prior to the ; first visible page and sets up $INSTDIR properly... ; Choose different default installation folder based on SV_ALLUSERS... ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit ; Reads components status for registry !insertmacro SectionList "InitSection" ; check to see if /D has been used to change ; the install directory by comparing it to the ; install directory that is expected to be the ; default StrCpy $IS_DEFAULT_INSTALLDIR 0 StrCmp "$INSTDIR" "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" 0 +2 StrCpy $IS_DEFAULT_INSTALLDIR 1 StrCpy $SV_ALLUSERS "JustMe" ; if default install dir then change the default ; if it is installed for JustMe StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@" ClearErrors UserInfo::GetName IfErrors noLM Pop $0 UserInfo::GetAccountType Pop $1 StrCmp $1 "Admin" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Admin group' StrCpy $SV_ALLUSERS "AllUsers" Goto done StrCmp $1 "Power" 0 +3 SetShellVarContext all ;MessageBox MB_OK 'User "$0" is in the Power Users group' StrCpy $SV_ALLUSERS "AllUsers" Goto done noLM: StrCpy $SV_ALLUSERS "AllUsers" ;Get installation folder from registry if available done: StrCmp $SV_ALLUSERS "AllUsers" 0 +3 StrCmp "$IS_DEFAULT_INSTALLDIR" "1" 0 +2 StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@" StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 noOptionsPage !insertmacro MUI_INSTALLOPTIONS_EXTRACT "NSIS.InstallOptions.ini" noOptionsPage: FunctionEnd diff --git a/CMake/PackageDepends/MITK_Boost_Config.cmake b/CMake/PackageDepends/MITK_Boost_Config.cmake index 967e1e8124..b152bfa4f5 100644 --- a/CMake/PackageDepends/MITK_Boost_Config.cmake +++ b/CMake/PackageDepends/MITK_Boost_Config.cmake @@ -1,17 +1,13 @@ -if(MITK_USE_Boost_LIBRARIES) - find_package(Boost 1.68.0 REQUIRED COMPONENTS ${MITK_USE_Boost_LIBRARIES} QUIET) -else() - find_package(Boost 1.68.0 REQUIRED QUIET) +find_package(Boost REQUIRED COMPONENTS ${Boost_REQUIRED_COMPONENTS_BY_MODULE}) + +if(Boost_REQUIRED_COMPONENTS_BY_MODULE) + foreach(boost_component ${Boost_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "Boost::${boost_component}") + endforeach() endif() -list(APPEND ALL_INCLUDE_DIRECTORIES ${Boost_INCLUDE_DIRS}) +list(APPEND ALL_LIBRARIES "Boost::boost") -if(Boost_LIBRARIES) - if(WIN32) - # Force dynamic linking - list(APPEND ALL_COMPILE_OPTIONS -DBOOST_ALL_DYN_LINK) - else() - # Boost has an auto link feature (pragma comment lib) for Windows - list(APPEND ALL_LIBRARIES ${Boost_LIBRARIES}) - endif() +if(MSVC) + list(APPEND ALL_LIBRARIES "Boost::dynamic_linking" "bcrypt") endif() diff --git a/CMake/PackageDepends/MITK_ITK_Config.cmake b/CMake/PackageDepends/MITK_ITK_Config.cmake index 7daf7b4d65..1e2b401f82 100644 --- a/CMake/PackageDepends/MITK_ITK_Config.cmake +++ b/CMake/PackageDepends/MITK_ITK_Config.cmake @@ -1,4 +1,16 @@ -find_package(ITK COMPONENTS ${ITK_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED) +foreach(itk_component ${ITK_REQUIRED_COMPONENTS_BY_MODULE}) + if(NOT itk_component MATCHES "^ITK") + set(itk_component "ITK${itk_component}") + endif() + list(APPEND _itk_required_components_by_module ${itk_component}) +endforeach() -list(APPEND ALL_LIBRARIES ${ITK_LIBRARIES}) -list(APPEND ALL_INCLUDE_DIRECTORIES ${ITK_INCLUDE_DIRS}) +find_package(ITK COMPONENTS ${_itk_required_components_by_module} REQUIRED) + +foreach(itk_component ${_itk_required_components_by_module}) + if(${itk_component}_LIBRARIES) + list(APPEND ALL_LIBRARIES ${${itk_component}_LIBRARIES}) + else() + list(APPEND ALL_LIBRARIES ${itk_component}) + endif() +endforeach() diff --git a/CMake/PackageDepends/MITK_OpenGL_Config.cmake b/CMake/PackageDepends/MITK_OpenGL_Config.cmake index a322942bd5..0925ef472b 100644 --- a/CMake/PackageDepends/MITK_OpenGL_Config.cmake +++ b/CMake/PackageDepends/MITK_OpenGL_Config.cmake @@ -1,5 +1,3 @@ set(OpenGL_GL_PREFERENCE LEGACY) find_package(OpenGL REQUIRED) -list(APPEND ALL_INCLUDE_DIRECTORIES ${OPENGL_INCLUDE_DIR}) -list(APPEND ALL_LIBRARIES ${OPENGL_LIBRARIES}) - +list(APPEND ALL_LIBRARIES OpenGL::GL) diff --git a/CMake/PackageDepends/MITK_OpenMP_Config.cmake b/CMake/PackageDepends/MITK_OpenMP_Config.cmake index e69de29bb2..8ca95d08c1 100644 --- a/CMake/PackageDepends/MITK_OpenMP_Config.cmake +++ b/CMake/PackageDepends/MITK_OpenMP_Config.cmake @@ -0,0 +1 @@ +set(ALL_LIBRARIES OpenMP::OpenMP_CXX) diff --git a/CMake/PackageDepends/MITK_OpenMesh_Config.cmake b/CMake/PackageDepends/MITK_OpenMesh_Config.cmake index e69de29bb2..85d06a71dd 100644 --- a/CMake/PackageDepends/MITK_OpenMesh_Config.cmake +++ b/CMake/PackageDepends/MITK_OpenMesh_Config.cmake @@ -0,0 +1,7 @@ +find_package(OpenMesh COMPONENTS ${OpenMesh_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED) + +foreach(openmesh_component ${OpenMesh_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "OpenMesh${openmesh_component}") +endforeach() + +set(ALL_COMPILE_DEFINITIONS -D_USE_MATH_DEFINES) diff --git a/CMake/PackageDepends/MITK_OpenSSL_Config.cmake b/CMake/PackageDepends/MITK_OpenSSL_Config.cmake new file mode 100644 index 0000000000..ade27a6dc0 --- /dev/null +++ b/CMake/PackageDepends/MITK_OpenSSL_Config.cmake @@ -0,0 +1,5 @@ +find_package(OpenSSL COMPONENTS ${OpenSSL_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED) + +foreach(openssl_component ${OpenSSL_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "OpenSSL::${openssl_component}") +endforeach() diff --git a/CMake/PackageDepends/MITK_Poco_Config.cmake b/CMake/PackageDepends/MITK_Poco_Config.cmake index cf5397f2d7..96f8a3c19d 100644 --- a/CMake/PackageDepends/MITK_Poco_Config.cmake +++ b/CMake/PackageDepends/MITK_Poco_Config.cmake @@ -1,7 +1,9 @@ -set(Poco_LIBRARIES) if(NOT Poco_REQUIRED_COMPONENTS_BY_MODULE) set(Poco_REQUIRED_COMPONENTS_BY_MODULE Foundation) endif() + find_package(Poco PATHS ${Poco_DIR} COMPONENTS ${Poco_REQUIRED_COMPONENTS_BY_MODULE} CONFIG REQUIRED) -list(APPEND ALL_LIBRARIES ${Poco_LIBRARIES}) +foreach(poco_component ${Poco_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "Poco::${poco_component}") +endforeach() diff --git a/CMake/PackageDepends/MITK_Python3_Config.cmake b/CMake/PackageDepends/MITK_Python3_Config.cmake index e69de29bb2..7324aa0d44 100644 --- a/CMake/PackageDepends/MITK_Python3_Config.cmake +++ b/CMake/PackageDepends/MITK_Python3_Config.cmake @@ -0,0 +1,3 @@ +foreach(python3_component ${Python3_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "Python3::${python3_component}") +endforeach() diff --git a/CMake/PackageDepends/MITK_Qt5_Config.cmake b/CMake/PackageDepends/MITK_Qt5_Config.cmake index 37f08b5160..cda0e217cd 100644 --- a/CMake/PackageDepends/MITK_Qt5_Config.cmake +++ b/CMake/PackageDepends/MITK_Qt5_Config.cmake @@ -1,4 +1,5 @@ find_package(Qt5 COMPONENTS ${Qt5_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED QUIET) -foreach(_component ${Qt5_REQUIRED_COMPONENTS_BY_MODULE}) - list(APPEND ALL_LIBRARIES ${Qt5${_component}_LIBRARIES}) + +foreach(qt5_component ${Qt5_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES Qt5::${qt5_component}) endforeach() diff --git a/CMake/PackageDepends/MITK_VPX_Config.cmake b/CMake/PackageDepends/MITK_VPX_Config.cmake deleted file mode 100644 index ec51ff8dc7..0000000000 --- a/CMake/PackageDepends/MITK_VPX_Config.cmake +++ /dev/null @@ -1,9 +0,0 @@ -set( VPX_LIB "" CACHE FILEPATH "Search for the vpx library file" ) -set( VPX_HEADER_DIR "" CACHE PATH "The path containing vpy headers" ) -set( VPX_FOUND FALSE ) - -if(VPX_LIB AND VPX_HEADER_DIR) - list(APPEND ALL_LIBRARIES ${VPX_LIB}) - list(APPEND ALL_INCLUDE_DIRECTORIES ${VPX_HEADER_DIR}) - set( VPX_FOUND TRUE ) -endif() diff --git a/CMake/PackageDepends/MITK_VTK_Config.cmake b/CMake/PackageDepends/MITK_VTK_Config.cmake index f13834dd55..74a9a3be22 100644 --- a/CMake/PackageDepends/MITK_VTK_Config.cmake +++ b/CMake/PackageDepends/MITK_VTK_Config.cmake @@ -1,8 +1,9 @@ find_package(VTK COMPONENTS ${VTK_REQUIRED_COMPONENTS_BY_MODULE} REQUIRED) -if(MITK_USE_Qt5) - find_package(Qt5Widgets REQUIRED QUIET) -endif() +foreach(vtk_module ${VTK_REQUIRED_COMPONENTS_BY_MODULE}) + list(APPEND ALL_LIBRARIES "VTK::${vtk_module}") +endforeach() -list(APPEND ALL_INCLUDE_DIRECTORIES ${VTK_INCLUDE_DIRS}) -list(APPEND ALL_LIBRARIES ${VTK_LIBRARIES}) +if(ALL_LIBRARIES) + vtk_module_autoinit(TARGETS ${MODULE_NAME} MODULES ${ALL_LIBRARIES}) +endif() diff --git a/CMake/PackageDepends/MITK_cpprestsdk_Config.cmake b/CMake/PackageDepends/MITK_cpprestsdk_Config.cmake index e69de29bb2..7764cec563 100644 --- a/CMake/PackageDepends/MITK_cpprestsdk_Config.cmake +++ b/CMake/PackageDepends/MITK_cpprestsdk_Config.cmake @@ -0,0 +1 @@ +set(ALL_LIBRARIES cpprestsdk::cpprest) diff --git a/CMake/PackageDepends/MITK_tinyxml2_Config.cmake b/CMake/PackageDepends/MITK_tinyxml2_Config.cmake new file mode 100644 index 0000000000..b08632d240 --- /dev/null +++ b/CMake/PackageDepends/MITK_tinyxml2_Config.cmake @@ -0,0 +1 @@ +set(ALL_LIBRARIES "tinyxml2::tinyxml2") diff --git a/CMake/PackageDepends/MITK_tinyxml_Config.cmake b/CMake/PackageDepends/MITK_tinyxml_Config.cmake deleted file mode 100644 index ee84a8ae1a..0000000000 --- a/CMake/PackageDepends/MITK_tinyxml_Config.cmake +++ /dev/null @@ -1,4 +0,0 @@ -list(APPEND ALL_LIBRARIES ${tinyxml_LIBRARIES}) -if(tinyxml_INCLUDE_DIRS) - list(APPEND ALL_INCLUDE_DIRECTORIES ${tinyxml_INCLUDE_DIRS}) -endif() diff --git a/CMake/RunInstalledApp.bat b/CMake/RunInstalledApp.bat new file mode 100644 index 0000000000..8ca0361f5c --- /dev/null +++ b/CMake/RunInstalledApp.bat @@ -0,0 +1 @@ +start "" /B /D bin bin/%~n0.exe %* diff --git a/CMake/mitkFunctionCreateBlueBerryApplication.cmake b/CMake/mitkFunctionCreateBlueBerryApplication.cmake index 9f4001b778..8869470500 100644 --- a/CMake/mitkFunctionCreateBlueBerryApplication.cmake +++ b/CMake/mitkFunctionCreateBlueBerryApplication.cmake @@ -1,229 +1,231 @@ #! #! Create a BlueBerry application. #! #! \brief This function will create a BlueBerry application together with all #! necessary provisioning and configuration data and install support. #! #! \param NAME (required) The name of the executable. #! \param DESCRIPTION (optional) A human-readable description of your application. #! The usage depends on the CPack generator (on Windows, this is a descriptive #! text for the created shortcuts). #! \param SOURCES (optional) A list of source files to compile into your executable. Defaults #! to .cpp. #! \param PLUGINS (optional) A list of required plug-ins. Defaults to all known plug-ins. #! \param EXCLUDE_PLUGINS (optional) A list of plug-ins which should not be used. Mainly #! useful if PLUGINS was not used. #! \param LINK_LIBRARIES A list of libraries to be linked with the executable. #! \param LIBRARY_DIRS A list of directories to pass through to MITK_INSTALL_TARGETS #! \param NO_PROVISIONING (option) Do not create provisioning files. #! \param NO_INSTALL (option) Do not install this executable #! #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateBlueBerryApplication( #! NAME MyApp #! DESCRIPTION "MyApp - New ways to explore medical data" #! EXCLUDE_PLUGINS org.mitk.gui.qt.extapplication #! ) #! \endcode #! function(mitkFunctionCreateBlueBerryApplication) cmake_parse_arguments(_APP "NO_PROVISIONING;NO_INSTALL" "NAME;DESCRIPTION" "SOURCES;PLUGINS;EXCLUDE_PLUGINS;LINK_LIBRARIES;LIBRARY_DIRS" ${ARGN}) if(NOT _APP_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() if(NOT _APP_SOURCES) set(_APP_SOURCES ${_APP_NAME}.cpp) endif() if(NOT _APP_PLUGINS) ctkFunctionGetAllPluginTargets(_APP_PLUGINS) else() set(_plugins ${_APP_PLUGINS}) set(_APP_PLUGINS) foreach(_plugin ${_plugins}) string(REPLACE "." "_" _plugin_target ${_plugin}) list(APPEND _APP_PLUGINS ${_plugin_target}) endforeach() # get all plug-in dependencies ctkFunctionGetPluginDependencies(_plugin_deps PLUGINS ${_APP_PLUGINS} ALL) # add the dependencies to the list of application plug-ins list(APPEND _APP_PLUGINS ${_plugin_deps}) endif() # ----------------------------------------------------------------------- # Set up include and link dirs for the executable # ----------------------------------------------------------------------- include_directories( ${org_blueberry_core_runtime_INCLUDE_DIRS} ) # ----------------------------------------------------------------------- # Add executable icon (Windows) # ----------------------------------------------------------------------- set(WINDOWS_ICON_RESOURCE_FILE "") if(WIN32) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") set(WINDOWS_ICON_RESOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") endif() endif() # ----------------------------------------------------------------------- # Create the executable and link libraries # ----------------------------------------------------------------------- set(_app_compile_flags ) if(WIN32) set(_app_compile_flags "${_app_compile_flags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") endif() if(MITK_SHOW_CONSOLE_WINDOW) add_executable(${_APP_NAME} MACOSX_BUNDLE ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) else() add_executable(${_APP_NAME} MACOSX_BUNDLE WIN32 ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) endif() if(NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_SOURCE_DIR}.*") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) if(CMAKE_CURRENT_SOURCE_DIR MATCHES "^${MITK_EXTENSION_DIR}.*") get_filename_component(MITK_EXTENSION_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_EXTENSION_ROOT_FOLDER}/Applications") break() endif() endforeach() else() set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Applications") endif() mitk_use_modules(TARGET ${_APP_NAME} MODULES MitkAppUtil) set_target_properties(${_APP_NAME} PROPERTIES COMPILE_FLAGS "${_app_compile_flags}") target_link_libraries(${_APP_NAME} PRIVATE org_blueberry_core_runtime ${_APP_LINK_LIBRARIES}) if(WIN32) target_link_libraries(${_APP_NAME} PRIVATE ${QT_QTMAIN_LIBRARY}) endif() # ----------------------------------------------------------------------- # Add executable icon and bundle name (Mac) # ----------------------------------------------------------------------- if(APPLE) if( _APP_DESCRIPTION) set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_DESCRIPTION}") else() set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_NAME}") endif() set(icon_name "icon.icns") set(icon_full_path "${CMAKE_CURRENT_SOURCE_DIR}/icons/${icon_name}") if(EXISTS "${icon_full_path}") set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE "${icon_name}") file(COPY ${icon_full_path} DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.app/Contents/Resources/") INSTALL (FILES ${icon_full_path} DESTINATION "${_APP_NAME}.app/Contents/Resources/") endif() endif() # ----------------------------------------------------------------------- # Set build time dependencies # ----------------------------------------------------------------------- # This ensures that all enabled plug-ins are up-to-date when the # executable is build. if(_APP_PLUGINS) ctkMacroGetAllProjectTargetLibraries("${_APP_PLUGINS}" _project_plugins) if(_APP_EXCLUDE_PLUGINS AND _project_plugins) set(_exclude_targets) foreach(_exclude_plugin ${_APP_EXCLUDE_PLUGINS}) string(REPLACE "." "_" _exclude_target ${_exclude_plugin}) list(APPEND _exclude_targets ${_exclude_target}) endforeach() list(REMOVE_ITEM _project_plugins ${_exclude_targets}) endif() if(_project_plugins) add_dependencies(${_APP_NAME} ${_project_plugins}) endif() endif() # ----------------------------------------------------------------------- # Additional files needed for the executable # ----------------------------------------------------------------------- if(NOT _APP_NO_PROVISIONING) # Create a provisioning file, listing all plug-ins set(_prov_file "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.provisioning") mitkFunctionCreateProvisioningFile(FILE ${_prov_file} PLUGINS ${_APP_PLUGINS} EXCLUDE_PLUGINS ${_APP_EXCLUDE_PLUGINS} ) endif() # Create a .ini file for initial parameters if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_APP_NAME}.ini") configure_file(${_APP_NAME}.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.ini) endif() # Create batch and VS user files for Windows platforms include(mitkFunctionCreateWindowsBatchScript) if(WIN32) set(template_name "start${_APP_NAME}.bat.in") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${template_name}") foreach(BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript(${template_name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/start${_APP_NAME}_${BUILD_TYPE}.bat ${BUILD_TYPE}) endforeach() endif() mitkFunctionConfigureVisualStudioUserProjectFile( NAME ${_APP_NAME} ) endif(WIN32) # ----------------------------------------------------------------------- # Install support # ----------------------------------------------------------------------- if(NOT _APP_NO_INSTALL) # This installs all third-party CTK plug-ins mitkFunctionInstallThirdPartyCTKPlugins(${_APP_PLUGINS} EXCLUDE ${_APP_EXCLUDE_PLUGINS}) if(COMMAND BlueBerryApplicationInstallHook) set(_real_app_plugins ${_APP_PLUGINS}) if(_APP_EXCLUDE_PLUGINS) list(REMOVE_ITEM _real_app_plugins ${_APP_EXCLUDE_PLUGINS}) endif() BlueBerryApplicationInstallHook(APP_NAME ${_APP_NAME} PLUGINS ${_real_app_plugins}) endif() # Install the executable MITK_INSTALL_TARGETS(EXECUTABLES ${_APP_NAME} LIBRARY_DIRS ${_APP_LIBRARY_DIRS} GLOB_PLUGINS ) if(NOT _APP_NO_PROVISIONING) # Install the provisioning file mitkFunctionInstallProvisioningFiles(${_prov_file}) endif() # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${_APP_NAME}.sh) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME "${_APP_NAME}.sh") + elseif(WIN32) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.bat" DESTINATION "." RENAME "${_APP_NAME}.bat") endif() # Tell cpack the executables that you want in the start menu as links set(MITK_CPACK_PACKAGE_EXECUTABLES ${MITK_CPACK_PACKAGE_EXECUTABLES} "${_APP_NAME};${_APP_DESCRIPTION}" CACHE INTERNAL "Collecting windows shortcuts to executables") endif() endfunction() function(FunctionCreateBlueBerryApplication) message(SEND_ERROR "The function FunctionCreateBlueBerryApplication was renamed to mitkFunctionCreateBlueBerryApplication in MITK 2015.05") endfunction() diff --git a/CMake/mitkFunctionCreateCommandLineApp.cmake b/CMake/mitkFunctionCreateCommandLineApp.cmake index 139d6d53ef..949e57e848 100644 --- a/CMake/mitkFunctionCreateCommandLineApp.cmake +++ b/CMake/mitkFunctionCreateCommandLineApp.cmake @@ -1,55 +1,58 @@ #! #! Create a Command Line App. #! #! \brief This function will create a command line executable and the scripts required to run it #! #! \param NAME (required) Name of the command line app #! \param DEPENDS (optional) Required MITK modules beyond MitkCommandLine #! \param PACKAGE_DEPENDS (optional) list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) +#! \param TARGET_DEPENDS (optional) list of additional CMake targets this command line app depends on #! \param CPP_FILES (optional) list of cpp files, if it is not given NAME.cpp is assumed #! #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateCommandLineApp( #! NAME MyApp #! DEPENDS MitkCore MitkPlanarFigure #! PACKAGE_DEPENDS ITK VTK #! ) #! \endcode #! function(mitkFunctionCreateCommandLineApp) set(_function_params NAME # Name of the command line app ) set(_function_multiparams DEPENDS # list of modules this command line app depends on PACKAGE_DEPENDS # list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) + TARGET_DEPENDS # list of additional CMake targets this command line app depends on CPP_FILES # (optional) list of cpp files, if it is not given NAME.cpp is assumed ) set(_function_options WARNINGS_NO_ERRORS ) cmake_parse_arguments(CMDAPP "${_function_options}" "${_function_params}" "${_function_multiparams}" ${ARGN}) if(NOT CMDAPP_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() if(NOT CMDAPP_CPP_FILES) set(CMDAPP_CPP_FILES ${CMDAPP_NAME}.cpp) endif() if(CMDAPP_WARNINGS_NO_ERRORS) LIST(APPEND _CMDAPP_OPTIONS WARNINGS_NO_ERRORS) endif() mitk_create_executable(${CMDAPP_NAME} DEPENDS MitkCommandLine ${CMDAPP_DEPENDS} PACKAGE_DEPENDS ${CMDAPP_PACKAGE_DEPENDS} + TARGET_DEPENDS ${TARGET_DEPENDS} CPP_FILES ${CMDAPP_CPP_FILES} ${_CMDAPP_OPTIONS} ) endfunction() diff --git a/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake b/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake index 85ea849bb2..7478718143 100644 --- a/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake +++ b/CMake/mitkFunctionCreateMatchPointDeployedAlgorithm.cmake @@ -1,108 +1,114 @@ #! #! Create a Command Line App. #! #! \brief This function will create a command line executable and the scripts required to run it #! #! \param NAME (required) Name of the algorithm / cmake target #! \param DEPENDS (optional) Required MITK modules beyond MitkCommandLine #! \param PACKAGE_DEPENDS (optional) list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) +#! \param TARGET_DEPENDS (optional) list of additional CMake targets this command line app depends on #! \param CPP_FILES (optional) list of cpp files, if it is not given NAME.cpp is assumed #! \param INCLUDE_DIRS (optional): All directories that should be added as include dirs to the project #! \param PROFILE (optional): The profile file that should be used for the algorithm. If not set it is "./.profile". #! \param NO_PROFILE_GEN (optional): Flag. If set no profile resource will be generated. #! \param ADDITIONAL_LIBS (optional) 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 H_FILES (optional) List of public header files for this module. #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateCommandLineApp( #! NAME MyApp #! DEPENDS MitkCore MitkPlanarFigure #! PACKAGE_DEPENDS ITK VTK #! ) #! \endcode #! function(mitkFunctionCreateMatchPointDeployedAlgorithm) set(_function_params NAME # Name of the algorithm/target PROFILE # Profile of the algorithm that should be used ) set(_function_multiparams DEPENDS # list of modules this command line app depends on PACKAGE_DEPENDS # list of "packages" this command line app depends on (e.g. ITK, VTK, etc.) + TARGET_DEPENDS # list of CMake targets this command line app depends on CPP_FILES # (optional) list of cpp files, if it is not given NAME.cpp is assumed INCLUDE_DIRS # include directories: [PUBLIC|PRIVATE|INTERFACE] ADDITIONAL_LIBS # list of addidtional private libraries linked to this module. H_FILES # list of header files: [PUBLIC|PRIVATE] ) set(_function_options NO_PROFILE_GEN #Flag that indicates that no profile resource should be generated. ) cmake_parse_arguments(ALG "${_function_options}" "${_function_params}" "${_function_multiparams}" ${ARGN}) if( NOT (DEFINED MITK_USE_MatchPoint) OR NOT (${MITK_USE_MatchPoint})) message(FATAL_ERROR "Need package Matchpoint to deploy MatchPoint Algorithms.") endif() if(NOT ALG_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() SET(ALG_TARGET "MDRA_${ALG_NAME}") if(NOT ALG_CPP_FILES) set(ALG_CPP_FILES "${ALG_NAME}.cpp") endif() IF(NOT ALG_PROFILE) set(ALG_PROFILE "${ALG_NAME}.profile") ENDIF(NOT ALG_PROFILE) IF(NOT ALG_NO_PROFILE_GEN) MESSAGE(STATUS "... generate MDRA profile for ${ALG_NAME} (from ${ALG_PROFILE})...") include(${MatchPoint_SOURCE_DIR}/CMake/mapFunctionCreateAlgorithmProfile.cmake) CREATE_ALGORITHM_PROFILE(${ALG_NAME} ${ALG_PROFILE}) MESSAGE(STATUS "... algorithm UID: ${ALGORITHM_PROFILE_UID}") ENDIF(NOT ALG_NO_PROFILE_GEN) MESSAGE(STATUS "... deploy MDRA algorithm ${ALG_NAME}...") ADD_LIBRARY(${ALG_TARGET} SHARED ${ALG_CPP_FILES} ${ALGORITHM_PROFILE_FILE}) SET_TARGET_PROPERTIES(${ALG_TARGET} PROPERTIES OUTPUT_NAME "mdra-${MatchPoint_VERSION_MAJOR}-${MatchPoint_VERSION_MINOR}_${ALG_NAME}" OUTPUT_NAME_DEBUG "mdra-D-${MatchPoint_VERSION_MAJOR}-${MatchPoint_VERSION_MINOR}_${ALG_NAME}" PREFIX "" FOLDER "${MITK_ROOT_FOLDER}/Modules/MatchPointAlgorithms") mitk_use_modules(TARGET ${ALG_TARGET} MODULES ${ALG_DEPENDS} - PACKAGES PRIVATE ITK MatchPoint ${ALG_PACKAGE_DEPENDS} + PACKAGES PRIVATE MatchPoint ${ALG_PACKAGE_DEPENDS} ) + if(ALG_TARGET_DEPENDS) + target_link_libraries(${ALG_TARGET} ${ALG_TARGET_DEPENDS}) + endif() + target_include_directories(${ALG_TARGET} PRIVATE ${ALG_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) if(ALG_ADDITIONAL_LIBS) target_link_libraries(${ALG_TARGET} PRIVATE ${ALG_ADDITIONAL_LIBS}) get_property(_mitk_additional_library_search_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) foreach(_lib_filepath ${ALG_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() MITK_INSTALL(TARGETS ${ALG_TARGET}) endfunction() diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index 4fe684de2f..f7b334c80b 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,651 +1,651 @@ ################################################################## # # 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 +#! PUBLIC ITK|Watersheds #! \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 #! #! \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 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 (deprecated) 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 + TARGET_DEPENDS # list of CMake targets this module should depend on: [PUBLIC|PRIVATE|INTERFACE] 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) + set(_deprecated_args INTERNAL_INCLUDE_DIRS DEPENDS_INTERNAL EXPORT_DEFINE 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() # ----------------------------------------------------------------- # 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() foreach(dep ${MODULE_DEPENDS}) if(TARGET ${dep}) get_target_property(AUTLOAD_DEP ${dep} MITK_AUTOLOAD_DIRECTORY) if (AUTLOAD_DEP) message(SEND_ERROR "Module \"${MODULE_NAME}\" has an invalid dependency on autoload module \"${dep}\". Check MITK_CREATE_MODULE usage for \"${MODULE_NAME}\".") endif() endif() endforeach(dep) 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}) set_property(TARGET ${_module_autoload_meta_target} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Autoload") 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) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=type-limits" 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}) # --------------------------------------------------------------- # Create the actual module target if(MODULE_HEADERS_ONLY) add_library(${MODULE_TARGET} INTERFACE) # INTERFACE_LIBRARY targets may only have whitelisted properties. The property "FOLDER" is not allowed. # set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules") else() if(MODULE_EXECUTABLE) if(MITK_SHOW_CONSOLE_WINDOW) set(_SHOW_CONSOLE_OPTION "") else() set(_SHOW_CONSOLE_OPTION WIN32) endif() add_executable(${MODULE_TARGET} ${_SHOW_CONSOLE_OPTION} ${MODULE_CPP_FILES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES} ${WINDOWS_ICON_RESOURCE_FILE}) set_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Executables") 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_property(TARGET ${MODULE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules") 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}) + target_link_libraries(${MODULE_TARGET} ${MODULE_TARGET_DEPENDS}) 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) endfunction() diff --git a/CMake/mitkFunctionCreatePlugin.cmake b/CMake/mitkFunctionCreatePlugin.cmake index d73c102897..d0da785c81 100644 --- a/CMake/mitkFunctionCreatePlugin.cmake +++ b/CMake/mitkFunctionCreatePlugin.cmake @@ -1,350 +1,356 @@ #! \brief Creates a MITK CTK plugin. #! #! This function should be called from the plugins CMakeLists.txt file. #! The target name is available after the macro call as ${PLUGIN_TARGET} #! to add additional libraries in your CMakeLists.txt. Include paths and link #! libraries are set depending on the value of the Required-Plugins header #! in your manifest_headers.cmake file. #! #! This function internally calls ctkMacroBuildPlugin() and adds support #! for Qt Help files and installers. #! #! Options: #! \param TEST_PLUGIN Mark this plug-in as a testing plug-in. #! \param NO_INSTALL Don't install this plug-in. #! #! Parameters: #! #! \param EXPORT_DIRECTIVE (required) The export directive to use in the generated #! _Exports.h file. #! #! Multi-value parameters (all optional): #! #! \param EXPORTED_INCLUDE_SUFFIXES A list of sub-directories which should #! be added to the current source directory. The resulting directories #! will be available in the set of include directories of depending plug-ins. #! \param MODULE_DEPENDS (optional) A list of Modules this plug-in depends on. #! \param PACKAGE_DEPENDS (optional) A list of external packages this plug-in depends on. +#! \param TARGET_DEPENDS (optional) A list of CMake targets this plug-in depends on. #! \param DOXYGEN_TAGFILES (optional) Which external tag files should be available for the plugin documentation #! \param MOC_OPTIONS (optional) Additional options to pass to the Qt MOC compiler #! \param WARNINGS_NO_ERRORS (optional) Do not handle compiler warnings as errors function(mitk_create_plugin) # options set(arg_options TEST_PLUGIN # Mark this plug-in as a testing plug-in NO_INSTALL # Don't install this plug-in NO_QHP_TRANSFORM WARNINGS_NO_ERRORS ) # single value arguments set(arg_single EXPORT_DIRECTIVE # (required) TODO: could be generated via CMake as it is done for MITK modules already ) # multiple value arguments set(arg_multiple EXPORTED_INCLUDE_SUFFIXES # (optional) additional public include directories MODULE_DEPENDS # (optional) PACKAGE_DEPENDS + TARGET_DEPENDS DOXYGEN_TAGFILES MOC_OPTIONS SUBPROJECTS # deprecated ) cmake_parse_arguments(_PLUGIN "${arg_options}" "${arg_single}" "${arg_multiple}" ${ARGN}) if(_PLUGIN_TEST_PLUGIN) set(_PLUGIN_NO_INSTALL 1) set(is_test_plugin "TEST_PLUGIN") else() set(is_test_plugin) endif() set(_PLUGIN_MOC_OPTIONS "-DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED ${_PLUGIN_MOC_OPTIONS}") set(PLUGIN_TARGET ${PROJECT_NAME}) mitk_check_module_dependencies(MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} MISSING_DEPENDENCIES_VAR _missing_deps MODULE_DEPENDENCIES_VAR _module_deps PACKAGE_DEPENDENCIES_VAR _package_deps) if(_missing_deps) if(NOT MITK_BUILD_ALL_PLUGINS) message(SEND_ERROR "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") else() message(STATUS "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") endif() return() endif() foreach(_module_dep ${_PLUGIN_MODULE_DEPENDS}) if(TARGET ${_module_dep}) get_target_property(AUTLOAD_DEP ${_module_dep} MITK_AUTOLOAD_DIRECTORY) if (AUTLOAD_DEP) message(SEND_ERROR "Plugin \"${PROJECT_NAME}\" has an invalid dependency on autoload module \"${_module_dep}\". Check MITK_CREATE_PLUGIN usage for \"${PROJECT_NAME}\".") endif() endif() endforeach() # -------------- All dependencies are resolved ------------------ message(STATUS "Creating CTK plugin ${PROJECT_NAME}") include(files.cmake) set(_PLUGIN_CPP_FILES ${CPP_FILES}) set(_PLUGIN_MOC_H_FILES ${MOC_H_FILES}) set(_PLUGIN_UI_FILES ${UI_FILES}) set(_PLUGIN_CACHED_RESOURCE_FILES ${CACHED_RESOURCE_FILES}) set(_PLUGIN_TRANSLATION_FILES ${TRANSLATION_FILES}) set(_PLUGIN_QRC_FILES ${QRC_FILES}) set(_PLUGIN_H_FILES ${H_FILES}) set(_PLUGIN_TXX_FILES ${TXX_FILES}) set(_PLUGIN_DOX_FILES ${DOX_FILES}) set(_PLUGIN_CMAKE_FILES ${CMAKE_FILES} files.cmake) set(_PLUGIN_FILE_DEPENDENCIES ${FILE_DEPENDENCIES}) if(CTK_PLUGINS_OUTPUT_DIR) set(_output_dir "${CTK_PLUGINS_OUTPUT_DIR}") else() set(_output_dir "") endif() # Compute the plugin dependencies ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries "") #------------------------------------------------------------# #------------------ Qt Help support -------------------------# set(PLUGIN_GENERATED_QCH_FILES ) if(BLUEBERRY_USE_QT_HELP AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/documentation/UserManual") # Create a list of Doxygen tag files from the plug-in dependencies set(PLUGIN_DOXYGEN_TAGFILES) foreach(_dep_target ${_PLUGIN_target_libraries}) string(REPLACE _ . _dep ${_dep_target}) get_target_property(_is_imported ${_dep_target} IMPORTED) if(_is_imported) get_target_property(_import_loc_debug ${_dep_target} IMPORTED_LOCATION_DEBUG) get_target_property(_import_loc_release ${_dep_target} IMPORTED_LOCATION_RELEASE) # There is not necessarily a debug and release build if(_import_loc_release) set(_import_loc ${_import_loc_release}) else() set(_import_loc ${_import_loc_debug}) endif() get_filename_component(_target_filename "${_import_loc}" NAME) # on windows there might be a Debug or Release subdirectory string(REGEX REPLACE "/bin/plugins/(Debug/|Release/)?${_target_filename}" "/Plugins/${_dep}/documentation/UserManual" plugin_tag_dir "${_import_loc}" ) else() set(plugin_tag_dir "${CMAKE_BINARY_DIR}/Plugins/${_dep}/documentation/UserManual") endif() set(_tag_file "${plugin_tag_dir}/${_dep_target}.tag") if(EXISTS ${_tag_file}) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} \"${_tag_file}=qthelp://${_dep}/bundle/\"") endif() endforeach() if(_PLUGIN_DOXYGEN_TAGFILES) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_PLUGIN_DOXYGEN_TAGFILES}") endif() #message("PLUGIN_DOXYGEN_TAGFILES: ${PLUGIN_DOXYGEN_TAGFILES}") if(_PLUGIN_NO_QHP_TRANSFORM) set(_use_qhp_xsl 0) else() set(_use_qhp_xsl 1) endif() _FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP(PLUGIN_GENERATED_QCH_FILES ${_use_qhp_xsl}) list(APPEND _PLUGIN_CACHED_RESOURCE_FILES ${PLUGIN_GENERATED_QCH_FILES}) endif() #------------------------------------------------------------# #------------------ Create Plug-in --------------------------# mitkFunctionOrganizeSources( SOURCE ${_PLUGIN_CPP_FILES} HEADER ${_PLUGIN_H_FILES} TXX ${_PLUGIN_TXX_FILES} DOC ${_PLUGIN_DOX_FILES} UI ${_PLUGIN_UI_FILES} QRC ${_PLUGIN_QRC_FILES} ${_PLUGIN_CACHED_RESOURCE_FILES} META ${_PLUGIN_META_FILES} MOC ${MY_MOC_CPP} GEN_UI ${MY_UI_CPP} GEN_QRC ${MY_QRC_SRCS} ) ctkMacroBuildPlugin( NAME ${PLUGIN_TARGET} EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} SRCS ${_PLUGIN_CPP_FILES} ${_PLUGIN_H_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} MOC_SRCS ${_PLUGIN_MOC_H_FILES} MOC_OPTIONS ${_PLUGIN_MOC_OPTIONS} UI_FORMS ${_PLUGIN_UI_FILES} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} RESOURCES ${_PLUGIN_QRC_FILES} TARGET_LIBRARIES ${_PLUGIN_target_libraries} CACHED_RESOURCEFILES ${_PLUGIN_CACHED_RESOURCE_FILES} TRANSLATIONS ${_PLUGIN_TRANSLATION_FILES} OUTPUT_DIR ${_output_dir} NO_INSTALL # we install the plug-in ourselves ${is_test_plugin} ) mitk_use_modules(TARGET ${PLUGIN_TARGET} MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} ) + if(_PLUGIN_TARGET_DEPENDS) + target_link_libraries(${PLUGIN_TARGET} ${_PLUGIN_TARGET_DEPENDS}) + endif() + set_property(TARGET ${PLUGIN_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${PLUGIN_TARGET}) set_property(TARGET ${PLUGIN_TARGET} PROPERTY US_MODULE_NAME ${PLUGIN_TARGET}) if(NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_SOURCE_DIR}.*") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) if(CMAKE_CURRENT_SOURCE_DIR MATCHES "^${MITK_EXTENSION_DIR}.*") get_filename_component(MITK_EXTENSION_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set_property(TARGET ${PLUGIN_TARGET} PROPERTY FOLDER "${MITK_EXTENSION_ROOT_FOLDER}/Plugins") break() endif() endforeach() else() set_property(TARGET ${PLUGIN_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Plugins") endif() set(plugin_c_flags) set(plugin_cxx_flags) if(NOT _PLUGIN_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" plugin_c_flags plugin_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=cast-function-type" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" plugin_c_flags plugin_cxx_flags) endif() endif() if(plugin_c_flags) string(REPLACE " " ";" plugin_c_flags "${plugin_c_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_c_flags}) endif() if(plugin_cxx_flags) string(REPLACE " " ";" plugin_cxx_flags "${plugin_cxx_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_cxx_flags}) endif() if(_PLUGIN_TEST_PLUGIN) find_package(CppUnit REQUIRED) target_include_directories(${PLUGIN_TARGET} PRIVATE ${CppUnit_INCLUDE_DIRS}) target_link_libraries(${PLUGIN_TARGET} PRIVATE ${CppUnit_LIBRARIES}) endif() if(mbilog_FOUND) target_link_libraries(${PLUGIN_TARGET} PRIVATE mbilog) endif() set(_PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") list(APPEND _PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") endif() set(PLUGIN_TARGET ${PLUGIN_TARGET} PARENT_SCOPE) #------------------------------------------------------------# #------------------ Installer support -----------------------# if(NOT _PLUGIN_NO_INSTALL) set(install_directories "") if(NOT MACOSX_BUNDLE_NAMES) set(install_directories bin/plugins) else(NOT MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND install_directories ${bundle_name}.app/Contents/MacOS/plugins) endforeach(bundle_name) endif(NOT MACOSX_BUNDLE_NAMES) foreach(install_subdir ${install_directories}) mitkFunctionInstallCTKPlugin(TARGETS ${PLUGIN_TARGET} DESTINATION ${install_subdir}) endforeach() set(_autoload_targets ) foreach(_dependency ${_module_deps}) get_target_property(_dep_autoloads ${_dependency} MITK_AUTOLOAD_TARGETS) if (_dep_autoloads) list(APPEND _autoload_targets ${_dep_autoloads}) endif() endforeach() # The MITK_AUTOLOAD_TARGETS property is used in the mitkFunctionInstallAutoLoadModules # macro which expects a list of plug-in targets. if (_autoload_targets) list(REMOVE_DUPLICATES _autoload_targets) set_target_properties(${PLUGIN_TARGET} PROPERTIES MITK_AUTOLOAD_TARGETS "${_autoload_targets}") endif() endif() endfunction() function(_FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP qch_file use_xsl) set(_manifest_path "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(NOT EXISTS ${_manifest_path}) message(FATAL_ERROR "${_manifest_path} not found") endif() include(${_manifest_path}) string(REPLACE "_" "." Plugin-SymbolicName "${PLUGIN_TARGET}") configure_file(${MITK_SOURCE_DIR}/Documentation/doxygen_plugin_manual.conf.in ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ) set(_qhp_xsl_file "${MITK_SOURCE_DIR}/Documentation/qhp_toc.xsl") set(_generated_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/index.qhp") set(_transformed_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/${PLUGIN_TARGET}.qhp") set(${qch_file} "${CMAKE_CURRENT_BINARY_DIR}/resources/${PLUGIN_TARGET}.qch") set(_xsl_command ) if(use_xsl) set(_xsl_command COMMAND ${QT_XMLPATTERNS_EXECUTABLE} ${_qhp_xsl_file} ${_generated_qhp_file} -output ${_transformed_qhp_file}) endif() file(GLOB _file_dependencies "${PLUGIN_DOXYGEN_INPUT_DIR}/*") add_custom_command(OUTPUT ${${qch_file}} # Generate a Qt help project (index.qhp) with doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf # Use a XSL transformation to get rid of the top-level entry ${_xsl_command} # Generate the final Qt compressed help file (.qch) COMMAND ${QT_HELPGENERATOR_EXECUTABLE} ${_transformed_qhp_file} -o ${${qch_file}} DEPENDS ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ${_file_dependencies} ) #set_source_files_properties(${qch_file} PROPERTIES GENERATED 1) set(${qch_file} ${${qch_file}} PARENT_SCOPE) endfunction() function(MACRO_CREATE_MITK_CTK_PLUGIN) message(SEND_ERROR "The function MACRO_CREATE_MITK_CTK_PLUGIN was renamed to mitk_create_plugin in MITK 2015.05.") endfunction() diff --git a/CMake/mitkFunctionUseModules.cmake b/CMake/mitkFunctionUseModules.cmake index 0654f319be..173e0a5a95 100644 --- a/CMake/mitkFunctionUseModules.cmake +++ b/CMake/mitkFunctionUseModules.cmake @@ -1,173 +1,163 @@ function(_mitk_parse_package_args) set(package_list ${ARGN}) set(PUBLIC_PACKAGE_NAMES ) set(PRIVATE_PACKAGE_NAMES ) set(INTERFACE_PACKAGE_NAMES ) set(_package_visibility PRIVATE) foreach(_package ${package_list}) if(_package STREQUAL "PUBLIC" OR _package STREQUAL "PRIVATE" OR _package STREQUAL "INTERFACE") set(_package_visibility ${_package}) else() list(APPEND packages ${_package}) set(_package_name ) set(_package_components_list ) string(REPLACE "|" ";" _package_list ${_package}) if("${_package_list}" STREQUAL "${_package}") set(_package_name ${_package}) else() list(GET _package_list 0 _package_name) list(GET _package_list 1 _package_components) string(REPLACE "+" ";" _package_components_list "${_package_components}") if(NOT _package_name OR NOT _package_components) message(SEND_ERROR "PACKAGE argument syntax wrong. ${_package} is not of the form PACKAGE[|COMPONENT1[+COMPONENT2]...]") endif() endif() list(APPEND ${_package_visibility}_PACKAGE_NAMES ${_package_name}) list(APPEND ${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS ${_package_components_list}) endif() endforeach() # remove duplicates and set package components in parent scope foreach(_package_visibility PUBLIC PRIVATE INTERFACE) foreach(_package_name ${${_package_visibility}_PACKAGE_NAMES}) if(${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS) list(REMOVE_DUPLICATES ${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS) endif() set(${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS ${${_package_visibility}_${_package_name}_REQUIRED_COMPONENTS} PARENT_SCOPE) endforeach() endforeach() set(PUBLIC_PACKAGE_NAMES ${PUBLIC_PACKAGE_NAMES} PARENT_SCOPE) set(PRIVATE_PACKAGE_NAMES ${PRIVATE_PACKAGE_NAMES} PARENT_SCOPE) set(INTERFACE_PACKAGE_NAMES ${INTERFACE_PACKAGE_NAMES} PARENT_SCOPE) set(PACKAGE_NAMES ${PUBLIC_PACKAGE_NAMES} ${PRIVATE_PACKAGE_NAMES} ${INTERFACE_PACKAGE_NAMES} PARENT_SCOPE) endfunction() function(_include_package_config pkg_config_file) # wrap the inclusion of the MITK__Config.cmake file in a # function to create a scope for its variables; this allows # multiple inclusions of the file in the parent scope include(${pkg_config_file}) set(ALL_INCLUDE_DIRECTORIES ${ALL_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(ALL_LIBRARIES ${ALL_LIBRARIES} PARENT_SCOPE) set(ALL_COMPILE_DEFINITIONS ${ALL_COMPILE_DEFINITIONS} PARENT_SCOPE) set(ALL_COMPILE_OPTIONS ${ALL_COMPILE_OPTIONS} PARENT_SCOPE) endfunction() #! This CMake function sets up the necessary include directories, #! linker dependencies, and compile flags for a given target which #! depends on a set of MITK modules or packages. #! #! A package argument is of the form #! #! [PUBLIC|PRIVATE|INTERFACE] PACKAGE[|COMPONENT1[+COMPONENT2]...] #! #! where PACKAGE is the package name (e.g. VTK) and components are #! the names of required package components or libraries. #! #! If a dependency is not available, an error is thrown. function(mitk_use_modules) set(_macro_params TARGET # The target name (required) ) set(_macro_multiparams MODULES # MITK modules which the given TARGET uses PACKAGES # MITK packages which the given TARGET uses ) set(_macro_options ) cmake_parse_arguments(USE "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) # Sanity checks if(NOT USE_TARGET) message(SEND_ERROR "Required TARGET argument missing.") elseif(NOT TARGET ${USE_TARGET}) message(SEND_ERROR "The given TARGET argument ${USE_TARGET} is not a valid target") endif() set(depends ${USE_MODULES}) set(package_depends ${USE_PACKAGES}) if(depends) # Iterate over all module dependencies foreach(dependency ${depends}) if(TARGET ${dependency} AND NOT MODULE_IS_DEPRECATED) get_target_property(_is_interface_lib ${dependency} TYPE) if(NOT _is_interface_lib) get_target_property(_dependency_deprecated_since ${dependency} MITK_MODULE_DEPRECATED_SINCE) if(_dependency_deprecated_since) message(WARNING "Module ${dependency} is deprecated since ${_dependency_deprecated_since}") endif() endif() endif() endforeach() target_link_libraries(${USE_TARGET} PUBLIC ${depends}) endif() # Parse package dependencies if(package_depends) _mitk_parse_package_args(${package_depends}) # Some package config files like MITK_Qt5_Config.cmake rely on a # properly set "MODULE_NAME" variable for the current target. set(MODULE_NAME ${USE_TARGET}) # Read all package information foreach(_package_visibility INTERFACE PUBLIC PRIVATE) foreach(_package ${${_package_visibility}_PACKAGE_NAMES}) set(ALL_INCLUDE_DIRECTORIES) set(ALL_LIBRARIES) set(ALL_COMPILE_DEFINITIONS) set(ALL_COMPILE_OPTIONS) set(${_package}_REQUIRED_COMPONENTS_BY_MODULE ${${_package_visibility}_${_package}_REQUIRED_COMPONENTS}) set(_package_found 0) foreach(dir ${MODULES_PACKAGE_DEPENDS_DIRS}) if((NOT DEFINED MITK_USE_${_package} OR MITK_USE_${_package}) AND EXISTS "${dir}/MITK_${_package}_Config.cmake") _include_package_config("${dir}/MITK_${_package}_Config.cmake") set(_package_found 1) break() endif() endforeach() if(_package_found) if(ALL_INCLUDE_DIRECTORIES) list(REMOVE_DUPLICATES ALL_INCLUDE_DIRECTORIES) target_include_directories(${USE_TARGET} SYSTEM ${_package_visibility} ${ALL_INCLUDE_DIRECTORIES}) endif() if(ALL_LIBRARIES) # Don't remove "duplicats" because ALL_LIBRARIES may be of the form: # "general;bla;debug;blad;general;foo;debug;food" target_link_libraries(${USE_TARGET} ${_package_visibility} ${ALL_LIBRARIES}) endif() if(ALL_COMPILE_DEFINITIONS) list(REMOVE_DUPLICATES ALL_COMPILE_DEFINITIONS) # Compile definitions are always added "PRIVATE" to avoid multiple definitions # on the command line due to transitive and direct dependencies adding the # same definitions. target_compile_definitions(${USE_TARGET} PRIVATE ${ALL_COMPILE_DEFINITIONS}) endif() if(ALL_COMPILE_OPTIONS) list(REMOVE_DUPLICATES ALL_COMPILE_OPTIONS) target_compile_options(${USE_TARGET} ${_package_visibility} ${ALL_COMPILE_OPTIONS}) endif() - if("VTK" STREQUAL _package) - # VTK module autoinit - unset(_vtk_modules) - foreach(_vtk_module ${VTK_REQUIRED_COMPONENTS_BY_MODULE}) - list(APPEND _vtk_modules "VTK::${_vtk_module}") - endforeach() - if(_vtk_modules) - vtk_module_autoinit(TARGETS ${USE_TARGET} MODULES ${_vtk_modules}) - endif() - endif() else() message(SEND_ERROR "Missing package: ${_package}") endif() endforeach() endforeach() endif() endfunction() diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index 5ce1789fdc..c9ae3f0b51 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,170 +1,172 @@ # Install MITK icon and logo MITK_INSTALL(FILES "${MITK_SOURCE_DIR}/mitk.ico" "${MITK_SOURCE_DIR}/mitk.bmp") # Helper vars if(WIN32) set(_prefix "") set(_ext ".dll") elseif(UNIX) set(_prefix "lib") if(APPLE) set(_ext ".dylib") else() set(_ext ".so") endif() endif() # Install MITK executables including auto-load modules get_property(_mitk_executable_targets GLOBAL PROPERTY MITK_EXECUTABLE_TARGETS) if(_mitk_executable_targets) get_property(_mitk_module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) foreach(_mitk_module_target ${_mitk_module_targets}) if(TARGET ${_mitk_module_target}) get_target_property(_mitk_autoload_targets ${_mitk_module_target} MITK_AUTOLOAD_TARGETS) if (_mitk_autoload_targets) foreach(_mitk_autoload_target ${_mitk_autoload_targets}) get_target_property(_mitk_autoload_directory ${_mitk_autoload_target} MITK_AUTOLOAD_DIRECTORY) if (_mitk_autoload_directory) if(WIN32) get_target_property(_target_location ${_mitk_autoload_target} RUNTIME_OUTPUT_DIRECTORY) else() get_target_property(_target_location ${_mitk_autoload_target} LIBRARY_OUTPUT_DIRECTORY) endif() if(NOT CMAKE_CFG_INTDIR STREQUAL ".") set(_target_location "${_target_location}/Release") endif() set(_mitk_autoload_target_filename "${_prefix}${_mitk_autoload_target}${_ext}") set(_mitk_autoload_target_filepath "${_target_location}/${_mitk_autoload_target_filename}") set(_install_DESTINATION "${_mitk_autoload_directory}") MITK_INSTALL(FILES ${_mitk_autoload_target_filepath}) if(UNIX AND NOT APPLE) install(CODE "file(RPATH_REMOVE FILE \"\${CMAKE_INSTALL_PREFIX}/bin/${_mitk_autoload_directory}/${_mitk_autoload_target_filename}\")") endif() endif() endforeach() endif() endif() endforeach() set(_install_DESTINATION "") foreach(_mitk_executable_target ${_mitk_executable_targets}) get_target_property(_no_install ${_mitk_executable_target} NO_INSTALL) if(_no_install) continue() endif() MITK_INSTALL_TARGETS(EXECUTABLES ${_mitk_executable_target} GLOB_PLUGINS) if(UNIX AND NOT APPLE) - install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${_mitk_executable_target}.sh) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME "${_mitk_executable_target}.sh") + elseif(WIN32) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.bat" DESTINATION "." RENAME "${_mitk_executable_target}.bat") endif() endforeach() endif() # Install PythonQt if(MITK_USE_Python3 AND PythonQt_DIR) set(_python_qt_lib "${PythonQt_DIR}/") if(WIN32) set(_python_qt_lib "${_python_qt_lib}bin") else() set(_python_qt_lib "${_python_qt_lib}lib") endif() set(_python_qt_lib "${_python_qt_lib}/${_prefix}PythonQt${_ext}") MITK_INSTALL(FILES ${_python_qt_lib}) endif() # Install Qt plugins if(MITK_USE_Qt5) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path ${_qmake_location} DIRECTORY) set(_install_DESTINATION "plugins/sqldrivers") MITK_INSTALL(FILES "${_qmake_path}/../plugins/sqldrivers/${_prefix}qsqlite${_ext}") set(_install_DESTINATION "plugins/imageformats") MITK_INSTALL(FILES "${_qmake_path}/../plugins/imageformats/${_prefix}qsvg${_ext}") set(_install_DESTINATION "plugins/iconengines") MITK_INSTALL(FILES "${_qmake_path}/../plugins/iconengines/${_prefix}qsvgicon${_ext}") # Install platform-specific Qt plugins set(_install_DESTINATION "plugins/platforms") if(WIN32) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/qwindows.dll") elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqcocoa.dylib") elseif(UNIX) MITK_INSTALL(FILES "${_qmake_path}/../plugins/platforms/libqxcb.so") set(_install_DESTINATION "plugins/xcbglintegrations") MITK_INSTALL(FILES "${_qmake_path}/../plugins/xcbglintegrations/libqxcb-glx-integration.so") endif() # Install platform-specific Qt styles set(_install_DESTINATION "plugins/styles") if(WIN32) MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/qwindowsvistastyle.dll") elseif(APPLE) MITK_INSTALL(FILES "${_qmake_path}/../plugins/styles/libqmacstyle.dylib") endif() # Install Qt WebEngine if(APPLE) set(_install_DESTINATION "../Frameworks/QtWebEngineCore.framework") get_filename_component(_real_path "${_qmake_path}/../lib/QtWebEngineCore.framework/Helpers" REALPATH) MITK_INSTALL(DIRECTORY ${_real_path} USE_SOURCE_PERMISSIONS) # Translations are included in the Resources directory of # QtWebEngineCore.framework and are installed by default. else() set(_install_DESTINATION "") if(WIN32) MITK_INSTALL(PROGRAMS "${_qmake_path}/QtWebEngineProcess.exe") elseif(UNIX) MITK_INSTALL(PROGRAMS "${_qmake_path}/../libexec/QtWebEngineProcess") endif() # make sure resources and translations exist and try system location as well if(EXISTS "${_qmake_path}/../resources") MITK_INSTALL(DIRECTORY "${_qmake_path}/../resources") elseif(EXISTS "/usr/share/qt5/resources") MITK_INSTALL(DIRECTORY "/usr/share/qt5/resources") else() message(WARNING "No webengine resources found!") endif() set(_install_DESTINATION "translations") if(EXISTS "${_qmake_path}/../translations/qtwebengine_locales") MITK_INSTALL(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales") elseif(EXISTS "/usr/share/qt5/translations/qtwebengine_locales") MITK_INSTALL(DIRECTORY "/usr/share/qt5/translations/qtwebengine_locales") else() message(WARNING "No webengine translations found!") endif() endif() endif() set(_install_DESTINATION "") # Install MatchPoint binaries that are not auto-detected if(MITK_USE_MatchPoint) MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapUtilities*") MITK_INSTALL(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" FILES_MATCHING PATTERN "MapAlgorithms*") endif() # IMPORTANT: Restore default install destination! Do not edit this file beyond this line! set(_install_DESTINATION "") diff --git a/CMake/mitkMacroCreateModuleTests.cmake b/CMake/mitkMacroCreateModuleTests.cmake index 3dc3e7aa4f..f6f8a94b00 100644 --- a/CMake/mitkMacroCreateModuleTests.cmake +++ b/CMake/mitkMacroCreateModuleTests.cmake @@ -1,106 +1,107 @@ # # Create tests and testdriver for this module # # Usage: MITK_CREATE_MODULE_TESTS( [EXTRA_DRIVER_INIT init_code] ) # # EXTRA_DRIVER_INIT is inserted as c++ code in the testdriver and will be executed before each test # macro(MITK_CREATE_MODULE_TESTS) cmake_parse_arguments(MODULE_TEST - "US_MODULE;NO_INIT" "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE" "EXTRA_DEPENDS;DEPENDS;PACKAGE_DEPENDS" ${ARGN}) + "US_MODULE;NO_INIT" "EXTRA_DRIVER_INIT;EXTRA_DRIVER_INCLUDE" "EXTRA_DEPENDS;DEPENDS;PACKAGE_DEPENDS;TARGET_DEPENDS" ${ARGN}) if(BUILD_TESTING AND MODULE_IS_ENABLED) include(files.cmake) include_directories(.) set(TESTDRIVER ${MODULE_NAME}TestDriver) set(MODULE_TEST_EXTRA_DRIVER_INIT "${MODULE_TEST_EXTRA_DRIVER_INIT}") if(MITK_XVFB_TESTING) set(xvfb_run ${MITK_XVFB_TESTING_COMMAND}) else() set(xvfb_run ) endif() if(MODULE_TEST_US_MODULE) message(WARNING "The US_MODULE argument is deprecated and should be removed") endif() if(MODULE_TEST_US_MODULE AND MODULE_TEST_NO_INIT) message(WARNING "Conflicting arguments US_MODULE and NO_INIT: NO_INIT wins.") endif() set(_no_init) if(MODULE_TEST_NO_INIT) set(_no_init NO_INIT) endif() set(MITK_MODULE_NAME_REGEX_MATCH ) set(MITK_MODULE_NAME_REGEX_NOT_MATCH ) set(_testdriver_file_list ${CMAKE_CURRENT_BINARY_DIR}/testdriver_files.cmake) configure_file(${MITK_CMAKE_DIR}/mitkTestDriverFiles.cmake.in ${_testdriver_file_list} @ONLY) mitk_create_executable(${TESTDRIVER} DEPENDS ${MODULE_NAME} ${MODULE_TEST_DEPENDS} ${MODULE_TEST_EXTRA_DEPENDS} MitkTestingHelper PACKAGE_DEPENDS ${MODULE_TEST_PACKAGE_DEPENDS} + TARGET_DEPENDS ${MODULE_TEST_TARGET_DEPENDS} FILES_CMAKE ${_testdriver_file_list} NO_FEATURE_INFO NO_BATCH_FILE NO_INSTALL ${_no_init}) set_property(TARGET ${EXECUTABLE_TARGET} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Tests") # # Now tell CMake which tests should be run. This is done automatically # for all tests in ${KITNAME}_TESTS and ${KITNAME}_IMAGE_TESTS. The IMAGE_TESTS # are run for each image in the TESTIMAGES list. # include(files.cmake) foreach(test ${MODULE_TESTS} ${MODULE_RENDERING_TESTS}) get_filename_component(TName ${test} NAME_WE) add_test(NAME ${TName} COMMAND ${xvfb_run} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName}) mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_RELEASE release RELEASE) mitkFunctionGetLibrarySearchPaths(MITK_RUNTIME_PATH_DEBUG debug DEBUG) set(test_env_path ${MITK_RUNTIME_PATH_RELEASE} ${MITK_RUNTIME_PATH_DEBUG} $ENV{PATH}) list(REMOVE_DUPLICATES test_env_path) string (REGEX REPLACE "\;" "\\\;" test_env_path "${test_env_path}") set_property(TEST ${TName} PROPERTY ENVIRONMENT "PATH=${test_env_path}" APPEND) set_property(TEST ${TName} PROPERTY SKIP_RETURN_CODE 77) endforeach() foreach(test ${MODULE_RENDERING_TESTS}) get_filename_component(TName ${test} NAME_WE) set_property(TEST ${TName} APPEND PROPERTY LABELS "Rendering Tests") set_property(TEST ${TName} PROPERTY RUN_SERIAL TRUE) endforeach() set(TEST_TYPES IMAGE SURFACE POINTSET) # add other file types here foreach(test_type ${TEST_TYPES}) foreach(test_data ${MODULE_TEST${test_type}} ${ADDITIONAL_TEST_${test_type}}) if(EXISTS ${test_data}) set(TEST_DATA_FULL_PATH ${test_data}) else() # todo: maybe search other paths as well # yes, please in mitk/Testing/Data, too set(TEST_DATA_FULL_PATH ${MITK_DATA_DIR}/${test_data}) endif() if(EXISTS ${TEST_DATA_FULL_PATH}) foreach( test ${MODULE_${test_type}_TESTS}) get_filename_component(TName ${test} NAME_WE) get_filename_component(DName ${TEST_DATA_FULL_PATH} NAME) add_test(NAME ${TName}_${DName} COMMAND ${xvfb_run} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} ${TName} ${TEST_DATA_FULL_PATH}) set_property(TEST ${TName}_${DName} PROPERTY ENVIRONMENT "PATH=${test_env_path}" APPEND) set_property(TEST ${TName}_${DName} PROPERTY SKIP_RETURN_CODE 77) endforeach() else() message("!!!!! No such file: ${TEST_DATA_FULL_PATH} !!!!!") endif() endforeach() endforeach() endif() endmacro() diff --git a/CMake/mitkSetupCPack.cmake b/CMake/mitkSetupCPack.cmake index 1663a79fb3..6a95fec76a 100644 --- a/CMake/mitkSetupCPack.cmake +++ b/CMake/mitkSetupCPack.cmake @@ -1,142 +1,97 @@ # # First, set the generator variable # if(NOT CPACK_GENERATOR) if(WIN32) find_program(NSIS_MAKENSIS NAMES makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS] DOC "Where is makensis.exe located" ) - if(NOT NSIS_MAKENSIS) - set(CPACK_GENERATOR ZIP) - else() - set(CPACK_GENERATOR "NSIS;ZIP") + set(CPACK_GENERATOR ZIP) - endif(NOT NSIS_MAKENSIS) + if(NSIS_MAKENSIS) + set(MITK_CREATE_NSIS_INSTALLER ON CACHE BOOL "Create NSIS installer in addition to ZIP archive") + mark_as_advanced(MITK_CREATE_NSIS_INSTALLER) + if(MITK_CREATE_NSIS_INSTALLER) + list(APPEND CPACK_GENERATOR NSIS) + endif() + endif() else() if(APPLE) set(CPACK_GENERATOR DragNDrop) else() set(CPACK_GENERATOR TGZ) endif() endif() -endif(NOT CPACK_GENERATOR) - -# Set Redistributable information for windows -if(${CMAKE_SYSTEM_NAME} MATCHES Windows) - include(mitkFunctionGetMSVCVersion) - mitkFunctionGetMSVCVersion() - set(CPACK_VISUAL_STUDIO_VERSION_MAJOR "${VISUAL_STUDIO_VERSION_MAJOR}") - set(CPACK_VISUAL_STUDIO_PRODUCT_NAME "${VISUAL_STUDIO_PRODUCT_NAME}") - set(CPACK_LIBRARY_ARCHITECTURE "${CMAKE_LIBRARY_ARCHITECTURE}") - - # Visual Studio 2017 already comes with redistributable installers. - # Try to find the right one. - - set(vswhere "$ENV{PROGRAMFILES\(X86\)}\\Microsoft Visual Studio\\Installer\\vswhere.exe") - - if(EXISTS ${vswhere}) - execute_process(COMMAND ${vswhere} -latest -property installationPath - OUTPUT_VARIABLE installationPath - OUTPUT_STRIP_TRAILING_WHITESPACE) - file(TO_CMAKE_PATH "${installationPath}" installationPath) - set(redistPath "${installationPath}/VC/Redist/MSVC") - file(GLOB redistPath "${installationPath}/VC/Redist/MSVC/*") - list(LENGTH redistPath length) - if(length EQUAL 1) - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(redistPath "${redistPath}/vc_redist.x64.exe") - else() - set(redistPath "${redistPath}/vc_redist.x86.exe") - endif() - if(EXISTS ${redistPath}) - set(CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE ${redistPath} CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable") - endif() - endif() - endif() - - if(NOT DEFINED CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE) - set(CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE "" CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable") - endif() -endif() - -if(EXISTS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} ) - install(PROGRAMS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} - DESTINATION thirdpartyinstallers) - - get_filename_component(CPACK_REDISTRIBUTABLE_FILE_NAME ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} NAME ) endif() # On windows set default install directory appropriately for 32 and 64 bit # installers if not already set if(WIN32 AND NOT CPACK_NSIS_INSTALL_ROOT) if(CMAKE_CL_64) set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") else() set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") endif() endif() # By default, do not warn when built on machines using only VS Express -if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) - set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) +if(MITK_USE_OpenMP) + set(CMAKE_INSTALL_OPENMP_LIBRARIES ON) endif() # include required mfc libraries include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_NAME "MITK") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Medical Imaging Interaction Toolkit") set(CPACK_PACKAGE_VENDOR "German Cancer Research Center (DKFZ)") set(CPACK_PACKAGE_DESCRIPTION_FILE "${MITK_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_LICENSE "${MITK_SOURCE_DIR}/LICENSE") string(REPLACE "/" "_" CPACK_PACKAGE_VERSION_MAJOR "${MITK_REVISION_DESC}") # tell cpack to strip all debug symbols from all files set(CPACK_STRIP_FILES ON) # set version if(NOT CPACK_PACKAGE_VERSION_MAJOR) set(CPACK_PACKAGE_VERSION_MAJOR ${MITK_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${MITK_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${MITK_VERSION_PATCH}) set(CPACK_PACKAGE_VERSION "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") else() set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}) endif() # determine possible system specific extension set(CPACK_PACKAGE_ARCH "unkown-architecture") if(${CMAKE_SYSTEM_NAME} MATCHES Windows) if(CMAKE_CL_64) set(CPACK_PACKAGE_ARCH "windows-x86_64") elseif(WIN32) set(CPACK_PACKAGE_ARCH "windows-x86") endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES Linux) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686) set(CPACK_PACKAGE_ARCH "linux-x86") elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64) if(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") set(CPACK_PACKAGE_ARCH "linux-x86") else() set(CPACK_PACKAGE_ARCH "linux-x86_64") endif() else() set(CPACK_PACKAGE_ARCH "linux") endif() endif() if(${CMAKE_SYSTEM_NAME} MATCHES Darwin) set(CPACK_PACKAGE_ARCH "macos-x86_64") endif() set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCH}") - - - diff --git a/CMakeExternals/Boost.cmake b/CMakeExternals/Boost.cmake index a2921b9714..392f597f9f 100644 --- a/CMakeExternals/Boost.cmake +++ b/CMakeExternals/Boost.cmake @@ -1,335 +1,333 @@ #----------------------------------------------------------------------------- # Boost #----------------------------------------------------------------------------- include(mitkFunctionGetMSVCVersion) #[[ Sanity checks ]] if(DEFINED BOOST_ROOT AND NOT EXISTS ${BOOST_ROOT}) message(FATAL_ERROR "BOOST_ROOT variable is defined but corresponds to non-existing directory") endif() string(REPLACE "^^" ";" MITK_USE_Boost_LIBRARIES "${MITK_USE_Boost_LIBRARIES}") set(proj Boost) set(proj_DEPENDENCIES ) set(Boost_DEPENDS ${proj}) if(NOT DEFINED BOOST_ROOT AND NOT MITK_USE_SYSTEM_Boost) #[[ Reset variables. ]] set(patch_cmd "") set(configure_cmd "") set(install_cmd "") set(BOOST_ROOT ${ep_prefix}) if(WIN32) set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib") endif() #[[ If you update Boost, make sure that the FindBoost module of the minimum required version of CMake supports the new version of Boost. In case you are using a higher version of CMake, download at least the source code of the minimum required version of CMake to look into the right version of the FindBoost module: /share/cmake-/Modules/FindBoost.cmake Search for a list called _Boost_KNOWN_VERSIONS. If the new version is not included in this list, you have three options: * Update the minimum required version of CMake. This may require adaptions of other parts of our CMake scripts and has the most impact on other MITK developers. Yet this is the safest and cleanest option. * Set Boost_ADDITIONAL_VERSIONS (see the documentation of the FindBoost module). As Boost libraries and dependencies between them are hard-coded in the FindBoost module only for known versions, this may cause trouble for other MITK developers relying on new components of Boost or components with changed dependencies. * Copy a newer version of the FindBoost module into our CMake directory. Our CMake directory has a higher precedence than the default CMake module directory. Doublecheck if the minimum required version of CMake is able to process the newer version of the FindBoost module. Also, DO NOT FORGET to mention this option right above the call of cmake_minimum_required() in the top-level CMakeLists.txt file AND in this file right above the set(url) command below so if we update the minimum required version of CMake or use another option in the future, we do not forget to remove our copy of the FindBoost module again. ]] - set(url "${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_70_0.tar.gz") - set(md5 fea771fe8176828fabf9c09242ee8c26) + set(url "${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_74_0.tar.gz") + set(md5 3c8fb92ce08b9ad5a5f0b35731ac2c8e) if(MITK_USE_Boost_LIBRARIES) #[[ Boost has a two-step build process. In the first step, a bootstrap script is called to build b2, an executable that is used to actually build Boost in the second step. The bootstrap script expects a toolset (compiler) argument that is used to build the b2 executable. The scripts and their expected argument format differ between Windows and Unix. ]] if(WIN32) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_VERSION_MINOR EQUAL 0) #[[ Use just the major version in the toolset name. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 20) #[[ Assume Visual Studio 2017. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}1) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 30) #[[ Assume Visual Studio 2019. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}2) else() #[[ Fallback to the generic case. Be prepared to add another elseif branch above for future versions of Visual Studio. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) endif() else() #[[ We support GCC and Clang on Unix. On macOS, the toolset must be set - to darwin. The actual compiler for all of these toolkits is set + to clang. The actual compiler for all of these toolkits is set further below, after the bootstrap script but before b2. ]] - if(APPLE) - set(toolset darwin) - elseif(CMAKE_CXX_COMPILER_ID STREQUAL GNU) + if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) set(toolset gcc) - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR APPLE) set(toolset clang) endif() if(toolset) set(bootstrap_args --with-toolset=${toolset}) endif() #[[ At least give it a shot if the toolset is something else and let the bootstrap script decide on the toolset by not passing any argument. ]] endif() #[[ The call of b2 is more complex. b2 arguments are grouped into options and properties. Options follow the standard format for arguments while properties are plain key-value pairs. ]] set(b2_options --build-dir= --stagedir= --ignore-site-config #[[ Build independent of any site.config file ]] -q #[[ Stop at first error ]] ) if(APPLE AND CMAKE_OSX_SYSROOT) #[[ Specify the macOS platform SDK to be used. ]] list(APPEND b2_options --sysroot=${CMAKE_OSX_SYSROOT}) endif() foreach(lib ${MITK_USE_Boost_LIBRARIES}) list(APPEND b2_options --with-${lib}) endforeach() set(b2_properties threading=multi runtime-link=shared "cxxflags=${MITK_CXX14_FLAG} ${CMAKE_CXX_FLAGS}" ) if(CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND b2_properties address-model=64) else() list(APPEND b2_properties address-model=32) endif() if(BUILD_SHARED_LIBS) list(APPEND b2_properties link=shared) else() list(APPEND b2_properties link=static) endif() list(APPEND b2_properties "\ $<$:variant=debug>\ $<$:variant=release>\ $<$:variant=release>\ $<$:variant=release>") if(WIN32) set(bootstrap_cmd if not exist b2.exe \( call bootstrap.bat ${bootstrap_args} \)) set(b2_cmd b2 ${b2_options} ${b2_properties} stage) else() set(bootstrap_cmd #[[ test -e ./b2 || ]] ./bootstrap.sh ${bootstrap_args}) set(b2_cmd ./b2 ${b2_options} ${b2_properties} stage) #[[ We already told Boost if we want to use GCC or Clang but so far we were not able to specify the exact same compiler we set in CMake when configuring the MITK superbuild for the first time. For example, this can be different from the system default when multiple versions of the same compiler are installed at the same time. The bootstrap script creates a configuration file for b2 that should be modified if necessary before b2 is called. We look for a line like using gcc ; and replace it with something more specific like using gcc : : /usr/bin/gcc-7.3 ; We use the stream editor sed for the replacement but as macOS is based on BSD Unix, we use the limited but portable BSD syntax instead of the more powerful GNU syntax. We also use | instead of the more commonly used / separator for sed because the replacement contains slashes. ]] if(toolset) set(configure_cmd sed -i.backup "\ s|\ using[[:space:]][[:space:]]*${toolset}[[:space:]]*$|\ using ${toolset} : : ${CMAKE_CXX_COMPILER} $|\ g" /project-config.jam ) endif() endif() endif() if(WIN32) set(dummy_cmd cd .) else() set(dummy_cmd true) #[[ "cd ." does not work reliably ]] endif() if(NOT patch_cmd) set(patch_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(NOT configure_cmd) set(configure_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(WIN32) set(install_cmd if not exist $ \( ${CMAKE_COMMAND} -E copy_directory /boost /include/boost \) ) else() set(install_cmd # test -e /include/boost/config.hpp || ${CMAKE_COMMAND} -E copy_directory /boost /include/boost ) endif() ExternalProject_Add(${proj} URL ${url} URL_MD5 ${md5} PATCH_COMMAND ${patch_cmd} CONFIGURE_COMMAND ${configure_cmd} BUILD_COMMAND "" INSTALL_COMMAND ${install_cmd} ) ExternalProject_Add_Step(${proj} bootstrap COMMAND ${bootstrap_cmd} DEPENDEES patch DEPENDERS configure WORKING_DIRECTORY ) ExternalProject_Add_Step(${proj} b2 COMMAND ${b2_cmd} DEPENDEES bootstrap DEPENDERS build WORKING_DIRECTORY ) if(WIN32) #[[ Reuse already extracted files. ]] set(stamp_dir ${ep_prefix}/src/Boost-stamp) configure_file( ${CMAKE_CURRENT_LIST_DIR}/extract-Boost.replacement.cmake ${stamp_dir}/extract-Boost.replacement.cmake COPYONLY) ExternalProject_Add_Step(${proj} pre_download COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-pre_download.cmake DEPENDEES mkdir DEPENDERS download WORKING_DIRECTORY ${stamp_dir} ) endif() set(install_manifest_dependees install) if(MITK_USE_Boost_LIBRARIES) if(WIN32) #[[ Move DLLs from lib to bin directory. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-WIN32.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) elseif(APPLE) #[[ Boost does not follow the common practice of either using rpath or absolute paths for referencing dependencies. We have to use the install_name_tool to fix this. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-APPLE.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) endif() endif() ExternalProject_Add_Step(${proj} install_manifest COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-install_manifest.cmake DEPENDEES ${install_manifest_dependees} WORKING_DIRECTORY ${ep_prefix} ) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index 095ab60876..ed64006736 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,100 +1,100 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES DCMTK) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) - set(revision_tag "78341aba") + set(revision_tag "7210c5bc") set(ctk_optional_cache_args ) if(MITK_USE_Python3) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF "-DPYTHON_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIRS}" "-DPYTHON_LIBRARY:FILEPATH=${Python3_LIBRARY_RELEASE}" ) else() list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=OFF -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=d ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND ctk_optional_cache_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() FOREACH(type RUNTIME ARCHIVE LIBRARY) IF(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) LIST(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) ENDIF() ENDFOREACH() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} GIT_REPOSITORY https://github.com/commontk/CTK GIT_TAG ${revision_tag} UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} # The CTK PluginFramework cannot cope with # a non-empty CMAKE_DEBUG_POSTFIX for the plugin # libraries yet. -DCMAKE_DEBUG_POSTFIX:STRING= -DCTK_QT_VERSION:STRING=5 -DQt5_DIR=${Qt5_DIR} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_BUILD_QTDESIGNER_PLUGINS:BOOL=ON -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_LIB_XNAT/Core:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DPythonQt_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/PythonQt_fae23012.tar.gz ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(CTK_DIR ${binary_dir}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/CppUnit-1.12.1.patch b/CMakeExternals/CppUnit-1.12.1.patch deleted file mode 100644 index 03830eeea5..0000000000 --- a/CMakeExternals/CppUnit-1.12.1.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff -ru cppunit-1.12.1/include/cppunit/extensions/HelperMacros.h CppUnit/include/cppunit/extensions/HelperMacros.h ---- cppunit-1.12.1/include/cppunit/extensions/HelperMacros.h 2004-03-13 13:52:56.000000000 +0100 -+++ CppUnit/include/cppunit/extensions/HelperMacros.h 2018-03-02 13:18:25.487754669 +0100 -@@ -169,7 +169,7 @@ - static CPPUNIT_NS::TestSuite *suite() \ - { \ - const CPPUNIT_NS::TestNamer &namer = getTestNamer__(); \ -- std::auto_ptr suite( \ -+ std::unique_ptr suite( \ - new CPPUNIT_NS::TestSuite( namer.getFixtureName() )); \ - CPPUNIT_NS::ConcretTestFixtureFactory factory; \ - CPPUNIT_NS::TestSuiteBuilderContextBase context( *suite.get(), \ -diff -ru cppunit-1.12.1/src/cppunit/TypeInfoHelper.cpp CppUnit/src/cppunit/TypeInfoHelper.cpp ---- cppunit-1.12.1/src/cppunit/TypeInfoHelper.cpp 2004-02-18 21:45:44.000000000 +0100 -+++ CppUnit/src/cppunit/TypeInfoHelper.cpp 2018-03-02 13:16:03.100753385 +0100 -@@ -7,6 +7,7 @@ - - #if CPPUNIT_HAVE_GCC_ABI_DEMANGLE - #include -+#include - #endif diff --git a/CMakeExternals/CppUnit.cmake b/CMakeExternals/CppUnit.cmake index 085e5f3597..7ebf18c970 100644 --- a/CMakeExternals/CppUnit.cmake +++ b/CMakeExternals/CppUnit.cmake @@ -1,50 +1,49 @@ #----------------------------------------------------------------------------- # CppUnit #----------------------------------------------------------------------------- # Sanity checks if(DEFINED CppUnit_DIR AND NOT EXISTS ${CppUnit_DIR}) message(FATAL_ERROR "CppUnit_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CppUnit) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED CppUnit_DIR) set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/cppunit-1.12.1.tar.gz - URL_MD5 bd30e9cf5523cdfc019b94f5e1d7fd19 + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/cppunit-1.15.1.tar.gz + URL_MD5 9dc669e6145cadd9674873e24943e6dd PATCH_COMMAND - ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/CppUnit-1.12.1.patch COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/${proj}config.h.cmake /config/config.h.cmake COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=cppunit -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}/lib/cmake/CppUnit) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/CppUnitCMakeLists.txt b/CMakeExternals/CppUnitCMakeLists.txt index 993cc852cd..14c7590705 100644 --- a/CMakeExternals/CppUnitCMakeLists.txt +++ b/CMakeExternals/CppUnitCMakeLists.txt @@ -1,229 +1,228 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.18) project(CppUnit) set(${PROJECT_NAME}_MAJOR_VERSION 1) -set(${PROJECT_NAME}_MINOR_VERSION 12) +set(${PROJECT_NAME}_MINOR_VERSION 15) set(${PROJECT_NAME}_PATCH_VERSION 1) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) # UNICODE support # See Visual C Unicode Programming Summary # http://msdn.microsoft.com/en-us/library/dybsewaf%28VS.100%29.aspx #add_definitions(-DUNICODE -D_UNICODE) # Generates include/cppunit/config-auto.h # This is originally done by autoconf include(CheckIncludeFile) include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) include(CheckCSourceCompiles) include(CheckLibraryExists) include(CheckFunctionExists) #Not used == not seen in any *.h *.cpp files #Not used FUNC_STRING_COMPARE_STRING_FIRST check_include_file_cxx(sstream CPPUNIT_HAVE_SSTREAM) check_include_file_cxx(strstream CPPUNIT_HAVE_STRSTREAM) set (CMAKE_REQUIRED_DEFINITIONS -DHAVE_STRSTREAM=CPPUNIT_HAVE_STRSTREAM) check_cxx_source_compiles( "#ifdef HAVE_STRSTREAM #include #else #include #endif int main() { std::ostrstream message; message << \"Hello\"; return 0; }" CPPUNIT_HAVE_CLASS_STRSTREAM) check_include_file_cxx(cmath CPPUNIT_HAVE_CMATH) #Not used, dld library is obsolete anyway HAVE_DLD #Not used HAVE_DLERROR check_include_file(dlfcn.h CPPUNIT_HAVE_DLFCN_H) check_c_source_compiles( "#include int main() { return finite(3); }" CPPUNIT_HAVE_FINITE) check_c_source_compiles( "#include int main() { return _finite(3); }" CPPUNIT_HAVE__FINITE) check_include_file_cxx(cxxabi.h CPPUNIT_HAVE_GCC_ABI_DEMANGLE) #Not used HAVE_INTTYPES_H check_c_source_compiles( "#include int main() { return isfinite(3); }" CPPUNIT_HAVE_ISFINITE) check_library_exists(dl dlopen "" CPPUNIT_HAVE_LIBDL) #Not used HAVE_MEMORY_H check_cxx_source_compiles( "namespace Outer { namespace Inner { int i = 0; } } using namespace Outer::Inner; int main() { return i; }" CPPUNIT_HAVE_NAMESPACES) check_cxx_source_compiles( "#include class Base { public: Base() {} virtual int f() { return 0; } }; class Derived : public Base { public: Derived() {} virtual int f() { return 1; } }; int main() { Derived d; Base * ptr = &d; return typeid(*ptr) == typeid(Derived); }" CPPUNIT_HAVE_RTTI) check_library_exists(dl shl_load "" CPPUNIT_HAVE_SHL_LOAD) #Not used HAVE_STDINT_H #Not used HAVE_STDLIB_H #Not used HAVE_STRINGS_H #Not used HAVE_STRING_H #Not used HAVE_SYS_STAT_H #Not used HAVE_SYS_TYPES_H #Not used HAVE_UNISTD_H #Not used PACKAGE #Not used PACKAGE_BUGREPORT #Not used PACKAGE_NAME #Not used PACKAGE_STRING #Not used PACKAGE_TARNAME #Not used PACKAGE_VERSION #Not used STDC_HEADERS check_include_file_cxx(typeinfo CPPUNIT_USE_TYPEINFO_NAME) #CPPUNIT_VERSION ok configure_file(config/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/include/cppunit/config-auto.h) ## set(cppunit_SRCS src/cppunit/AdditionalMessage.cpp src/cppunit/Asserter.cpp - src/cppunit/BeOsDynamicLibraryManager.cpp src/cppunit/BriefTestProgressListener.cpp src/cppunit/CompilerOutputter.cpp src/cppunit/DefaultProtector.h src/cppunit/DefaultProtector.cpp src/cppunit/DynamicLibraryManager.cpp src/cppunit/DynamicLibraryManagerException.cpp src/cppunit/Exception.cpp src/cppunit/Message.cpp src/cppunit/PlugInManager.cpp src/cppunit/PlugInParameters.cpp src/cppunit/Protector.cpp src/cppunit/ProtectorChain.h src/cppunit/ProtectorContext.h src/cppunit/ProtectorChain.cpp src/cppunit/RepeatedTest.cpp src/cppunit/ShlDynamicLibraryManager.cpp src/cppunit/SourceLine.cpp src/cppunit/StringTools.cpp src/cppunit/SynchronizedObject.cpp src/cppunit/Test.cpp src/cppunit/TestAssert.cpp src/cppunit/TestCase.cpp src/cppunit/TestCaseDecorator.cpp src/cppunit/TestComposite.cpp src/cppunit/TestDecorator.cpp src/cppunit/TestFactoryRegistry.cpp src/cppunit/TestFailure.cpp src/cppunit/TestLeaf.cpp src/cppunit/TestNamer.cpp src/cppunit/TestPath.cpp src/cppunit/TestPlugInDefaultImpl.cpp src/cppunit/TestResult.cpp src/cppunit/TestResultCollector.cpp src/cppunit/TestRunner.cpp src/cppunit/TestSetUp.cpp src/cppunit/TestSuccessListener.cpp src/cppunit/TestSuite.cpp src/cppunit/TestSuiteBuilderContext.cpp src/cppunit/TextOutputter.cpp src/cppunit/TextTestProgressListener.cpp src/cppunit/TextTestResult.cpp src/cppunit/TextTestRunner.cpp src/cppunit/TypeInfoHelper.cpp src/cppunit/UnixDynamicLibraryManager.cpp src/cppunit/Win32DynamicLibraryManager.cpp src/cppunit/XmlDocument.cpp src/cppunit/XmlElement.cpp src/cppunit/XmlOutputter.cpp src/cppunit/XmlOutputterHook.cpp ) add_library(cppunit SHARED ${cppunit_SRCS}) target_include_directories(cppunit PUBLIC "$" "$" ) target_compile_definitions(cppunit PRIVATE CPPUNIT_BUILD_DLL) set_target_properties(cppunit PROPERTIES VERSION ${${PROJECT_NAME}_VERSION} SOVERSION ${${PROJECT_NAME}_VERSION} ) set(${PROJECT_NAME}_LIBRARIES cppunit) # Install support install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin ) install(DIRECTORY include/cppunit DESTINATION include ) # Config files configure_file( ${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(EXPORT ${PROJECT_NAME}_TARGETS FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake ) set(config_package_location lib/cmake/${PROJECT_NAME}) install(EXPORT ${PROJECT_NAME}_TARGETS FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${config_package_location} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${config_package_location} ) diff --git a/CMakeExternals/DCMQI.cmake b/CMakeExternals/DCMQI.cmake index 6ed5173b5e..f0cbb3ee51 100644 --- a/CMakeExternals/DCMQI.cmake +++ b/CMakeExternals/DCMQI.cmake @@ -1,65 +1,65 @@ #----------------------------------------------------------------------------- # DCMQI #----------------------------------------------------------------------------- if(MITK_USE_DCMQI) # Sanity checks if(DEFINED DCMQI_DIR AND NOT EXISTS ${DCMQI_DIR}) message(FATAL_ERROR "DCMQI_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMQI) set(proj_DEPENDENCIES DCMTK ITK) set(DCMQI_DEPENDS ${proj}) if(NOT DEFINED DCMQI_DIR) set(additional_cmake_args) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} GIT_REPOSITORY https://github.com/qiicr/dcmqi.git - GIT_TAG ea4f0809c8ba771e262a69b5f81d547a3945b264 + GIT_TAG 99192b76 UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} #-DCMAKE_INSTALL_PREFIX:PATH= -DBUILD_SHARED_LIBS:BOOL=ON -DDCMQI_BUILD_APPS:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DITK_DIR:PATH=${ITK_DIR} -DITK_NO_IO_FACTORY_REGISTER_MANAGER:BOOL=ON -DDCMQI_SUPERBUILD:BOOL=OFF -DDCMQI_CMAKE_CXX_STANDARD:STRING=14 ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(DCMQI_DIR ${binary_dir}) #set(${proj}_DIR ${ep_prefix}) #message(${proj}_DIR: ${${proj}_DIR}) #mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 92b6faa32a..4429abba21 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,69 +1,70 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) if(NOT DEFINED DCMTK_DIR) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.5.tar.gz URL_MD5 e19707f64ee5695c496b9c1e48e39d07 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${DCMTK_C_FLAGS}" + -DDCMTK_ENABLE_BUILTIN_DICTIONARY:BOOL=ON -DDCMTK_ENABLE_CXX11:BOOL=ON -DDCMTK_ENABLE_STL:BOOL=ON -DDCMTK_WITH_DOXYGEN:BOOL=OFF -DDCMTK_WITH_ZLIB:BOOL=OFF # see bug #9894 -DDCMTK_WITH_OPENSSL:BOOL=OFF # see bug #9894 -DDCMTK_WITH_PNG:BOOL=OFF # see bug #9894 -DDCMTK_WITH_TIFF:BOOL=OFF # see bug #9894 -DDCMTK_WITH_XML:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICONV:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICU:BOOL=OFF # see T26438 ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(DCMTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ExternalProjectList.cmake b/CMakeExternals/ExternalProjectList.cmake index ab452fc867..7eeb49a07a 100644 --- a/CMakeExternals/ExternalProjectList.cmake +++ b/CMakeExternals/ExternalProjectList.cmake @@ -1,26 +1,31 @@ mitkFunctionAddExternalProject(NAME Poco ON COMPONENTS Foundation Net Util XML Zip) mitkFunctionAddExternalProject(NAME DCMTK ON DOC "EXPERIMENTAL, superbuild only: Use DCMTK in MITK") mitkFunctionAddExternalProject(NAME OpenIGTLink OFF) -mitkFunctionAddExternalProject(NAME tinyxml ON ADVANCED) +mitkFunctionAddExternalProject(NAME tinyxml2 ON ADVANCED) mitkFunctionAddExternalProject(NAME GDCM ON ADVANCED) mitkFunctionAddExternalProject(NAME Eigen ON ADVANCED DOC "Use the Eigen library") mitkFunctionAddExternalProject(NAME ANN ON ADVANCED DOC "Use Approximate Nearest Neighbor Library") mitkFunctionAddExternalProject(NAME CppUnit ON ADVANCED DOC "Use CppUnit for unit tests") -mitkFunctionAddExternalProject(NAME PCRE OFF ADVANCED NO_PACKAGE) mitkFunctionAddExternalProject(NAME HDF5 ON ADVANCED) -mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE DEPENDS PCRE) mitkFunctionAddExternalProject(NAME OpenCV OFF) mitkFunctionAddExternalProject(NAME Vigra OFF DEPENDS HDF5) mitkFunctionAddExternalProject(NAME ITK ON NO_CACHE DEPENDS HDF5) mitkFunctionAddExternalProject(NAME VTK ON NO_CACHE) mitkFunctionAddExternalProject(NAME Boost ON NO_CACHE) mitkFunctionAddExternalProject(NAME ZLIB OFF ADVANCED) mitkFunctionAddExternalProject(NAME cpprestsdk OFF DEPENDS Boost ZLIB ADVANCED) mitkFunctionAddExternalProject(NAME OpenMesh OFF) mitkFunctionAddExternalProject(NAME CTK ON DEPENDS Qt5 DCMTK DOC "Use CTK in MITK") mitkFunctionAddExternalProject(NAME DCMQI ON DEPENDS DCMTK ITK DOC "Use dcmqi in MITK") mitkFunctionAddExternalProject(NAME MatchPoint OFF ADVANCED DEPENDS ITK DOC "Use the MatchPoint translation image registration library") if(MITK_USE_Qt5) mitkFunctionAddExternalProject(NAME Qwt ON ADVANCED DEPENDS Qt5) endif() + +if(UNIX) + mitkFunctionAddExternalProject(NAME PCRE OFF ADVANCED NO_PACKAGE) + mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE DEPENDS PCRE) +else() + mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE) +endif() diff --git a/CMakeExternals/GDCM.cmake b/CMakeExternals/GDCM.cmake index a8d1577792..0d384ba1e8 100644 --- a/CMakeExternals/GDCM.cmake +++ b/CMakeExternals/GDCM.cmake @@ -1,71 +1,71 @@ #----------------------------------------------------------------------------- # GDCM #----------------------------------------------------------------------------- # Sanity checks if(DEFINED GDCM_DIR AND NOT EXISTS ${GDCM_DIR}) message(FATAL_ERROR "GDCM_DIR variable is defined but corresponds to non-existing directory") endif() # Check if an external ITK build tree was specified. # If yes, use the GDCM from ITK, otherwise ITK will complain if(ITK_DIR) find_package(ITK) if(ITK_GDCM_DIR) set(GDCM_DIR ${ITK_GDCM_DIR}) endif() endif() set(proj GDCM) set(proj_DEPENDENCIES ) set(GDCM_DEPENDS ${proj}) if(NOT DEFINED GDCM_DIR) set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() # On Mac some assertions fail that prevent reading certain DICOM files. Bug #19995 if(APPLE) list(APPEND additional_args "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} -DNDEBUG" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/gdcm-3.0.4.tar.gz - URL_MD5 f12dbded708356d5fa0b5ed37ccdb66e + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/gdcm-3.0.8.tar.gz + URL_MD5 29e0e60b04183e3eb9c18ad093156b2c CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} -DGDCM_BUILD_SHARED_LIBS:BOOL=ON -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(GDCM_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") find_package(GDCM) endif() diff --git a/CMakeExternals/ITK-4.13.3.patch b/CMakeExternals/ITK-4.13.3.patch new file mode 100644 index 0000000000..d1d3ece7f7 --- /dev/null +++ b/CMakeExternals/ITK-4.13.3.patch @@ -0,0 +1,40 @@ +diff --git a/Modules/Core/Common/include/itkBoundingBox.h b/Modules/Core/Common/include/itkBoundingBox.h +index 36b03aaa7f..64205acfab 100644 +--- a/Modules/Core/Common/include/itkBoundingBox.h ++++ b/Modules/Core/Common/include/itkBoundingBox.h +@@ -87,7 +87,7 @@ public: + itkTypeMacro(BoundingBox, Object); + + /** Method for creation through the object factory. */ +- itkNewMacro(Self); ++ itkFactorylessNewMacro(Self); + + /** Hold on to the type information specified by the template parameters. */ + typedef TPointIdentifier PointIdentifier; +diff --git a/Modules/Core/Common/include/itkVectorContainer.h b/Modules/Core/Common/include/itkVectorContainer.h +index 72293c4ce8..e6366c66b5 100644 +--- a/Modules/Core/Common/include/itkVectorContainer.h ++++ b/Modules/Core/Common/include/itkVectorContainer.h +@@ -92,7 +92,7 @@ public: + typedef VectorType STLContainerType; + + /** Method for creation through the object factory. */ +- itkNewMacro(Self); ++ itkFactorylessNewMacro(Self); + + /** Standard part of every itk Object. */ + itkTypeMacro(VectorContainer, Object); +diff --git a/Modules/Core/Transform/include/itkScalableAffineTransform.h b/Modules/Core/Transform/include/itkScalableAffineTransform.h +index 4e830476a2..b5efeb95a4 100644 +--- a/Modules/Core/Transform/include/itkScalableAffineTransform.h ++++ b/Modules/Core/Transform/include/itkScalableAffineTransform.h +@@ -47,7 +47,8 @@ public: + itkTypeMacro(ScalableAffineTransform, AffineTransform); + + /** New macro for creation of through a Smart Pointer */ +- itkNewMacro(Self); ++ itkFactorylessNewMacro(Self); ++ itkCloneMacro(Self); + + /** Dimension of the domain space. */ + itkStaticConstMacro(InputSpaceDimension, unsigned int, NDimensions); diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake index 6217b38384..973e57229d 100644 --- a/CMakeExternals/ITK.cmake +++ b/CMakeExternals/ITK.cmake @@ -1,85 +1,84 @@ #----------------------------------------------------------------------------- # ITK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED ITK_DIR AND NOT EXISTS ${ITK_DIR}) message(FATAL_ERROR "ITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ITK) set(proj_DEPENDENCIES GDCM) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() set(ITK_DEPENDS ${proj}) if(NOT DEFINED ITK_DIR) set(additional_cmake_args -DUSE_WRAP_ITK:BOOL=OFF) if(MITK_USE_OpenCV) list(APPEND additional_cmake_args -DModule_ITKVideoBridgeOpenCV:BOOL=ON -DOpenCV_DIR:PATH=${OpenCV_DIR} ) endif() # Keep the behaviour of ITK 4.3 which by default turned on ITK Review # see MITK bug #17338 list(APPEND additional_cmake_args -DModule_ITKReview:BOOL=ON - # for 4.7, the OpenJPEG is needed by review but the variable must be set - -DModule_ITKOpenJPEG:BOOL=ON - # Added Module for Wavelets + -DModule_ITKOpenJPEG:BOOL=ON # for 4.7, the OpenJPEG is needed by review but the variable must be set -DModule_IsotropicWavelets:BOOL=ON ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} UPDATE_COMMAND "" - # ITK 4.13 release branch snapshot - URL https://github.com/InsightSoftwareConsortium/ITK/archive/e53d1d94.tar.gz - URL_MD5 977f77cb299cf3d722d13dd5408bcde5 + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/InsightToolkit-4.13.3.tar.gz + URL_MD5 d1c10c8288b47577d718a71190444815 + PATCH_COMMAND + ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ITK-4.13.3.patch CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DITK_USE_SYSTEM_GDCM:BOOL=ON -DGDCM_DIR:PATH=${GDCM_DIR} -DITK_USE_SYSTEM_HDF5:BOOL=ON -DHDF5_DIR:PATH=${HDF5_DIR} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(ITK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/Qwt-6.1.0.patch b/CMakeExternals/Qwt-6.1.0.patch deleted file mode 100644 index 51124e995c..0000000000 --- a/CMakeExternals/Qwt-6.1.0.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff -urNb qwt-6.1.0/src/qwt_transform.cpp Qwt-src/src/qwt_transform.cpp ---- qwt-6.1.0/src/qwt_transform.cpp 2013-05-30 17:18:27.000000000 +0200 -+++ Qwt-src/src/qwt_transform.cpp 2015-01-13 20:39:27.533871912 +0100 -@@ -15,10 +15,10 @@ - #endif - - //! Smallest allowed value for logarithmic scales: 1.0e-150 --QT_STATIC_CONST_IMPL double QwtLogTransform::LogMin = 1.0e-150; -+const double QwtLogTransform::LogMin = 1.0e-150; - - //! Largest allowed value for logarithmic scales: 1.0e150 --QT_STATIC_CONST_IMPL double QwtLogTransform::LogMax = 1.0e150; -+const double QwtLogTransform::LogMax = 1.0e150; - - //! Constructor - QwtTransform::QwtTransform() -diff -urNb qwt-6.1.0/src/qwt_transform.h Qwt-src/src/qwt_transform.h ---- qwt-6.1.0/src/qwt_transform.h 2013-05-30 17:18:25.000000000 +0200 -+++ Qwt-src/src/qwt_transform.h 2015-01-13 20:39:27.533871912 +0100 -@@ -107,8 +107,8 @@ - - virtual QwtTransform *copy() const; - -- QT_STATIC_CONST double LogMin; -- QT_STATIC_CONST double LogMax; -+ static const double LogMin; -+ static const double LogMax; - }; - - /*! diff --git a/CMakeExternals/Qwt.cmake b/CMakeExternals/Qwt.cmake index b397f9e042..e14f51089a 100644 --- a/CMakeExternals/Qwt.cmake +++ b/CMakeExternals/Qwt.cmake @@ -1,62 +1,61 @@ #----------------------------------------------------------------------------- # Qwt #----------------------------------------------------------------------------- if(MITK_USE_Qwt) # Sanity checks if(DEFINED Qwt_DIR AND NOT EXISTS ${Qwt_DIR}) message(FATAL_ERROR "Qwt_DIR variable is defined but corresponds to non-existing directory") endif() set(proj Qwt) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED ${proj}_DIR) set(patch_cmd ${CMAKE_COMMAND} -Dproj:STRING=${proj} -Dproj_target:STRING=qwt -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake) set(qt54patch_cmd ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchQwt-6.1.0.cmake) set(additional_cmake_args "-DQt5Svg_DIR:PATH=${Qt5Svg_DIR}" "-DQt5OpenGL_DIR:PATH=${Qt5OpenGL_DIR}" "-DQt5PrintSupport_DIR:PATH=${Qt5PrintSupport_DIR}" "-DQt5Concurrent_DIR:PATH=${Qt5Concurrent_DIR}" "-DQt5Designer_DIR:PATH=${Qt5_DIR}Designer" ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/qwt-6.1.0.tar.bz2 - URL_MD5 aef0437b37f191067a6a9dc01c30ba64 - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/Qwt-6.1.0.patch - COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=qwt -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/qwt-6.1.5.tar.bz2 + URL_MD5 d65582f99312796ed42c3be3208ed3db + PATCH_COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=qwt -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} ${qt_project_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/QwtCMakeLists.txt b/CMakeExternals/QwtCMakeLists.txt index 50bd9c2805..5c91a4acac 100644 --- a/CMakeExternals/QwtCMakeLists.txt +++ b/CMakeExternals/QwtCMakeLists.txt @@ -1,264 +1,264 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.18) project(Qwt) set(${PROJECT_NAME}_MAJOR_VERSION 6) set(${PROJECT_NAME}_MINOR_VERSION 1) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) set(QWT_MOC_HEADERS # General qwt_dyngrid_layout.h qwt_magnifier.h qwt_panner.h qwt_picker.h qwt_text_label.h # QwtPlot qwt_abstract_legend.h qwt_legend.h qwt_legend_label.h qwt_plot.h qwt_plot_renderer.h qwt_plot_canvas.h qwt_plot_panner.h qwt_plot_picker.h qwt_plot_zoomer.h qwt_plot_magnifier.h qwt_sampling_thread.h qwt_scale_widget.h # QwtOpenGL qwt_plot_glcanvas.h # QwtWidgets qwt_abstract_slider.h qwt_abstract_scale.h qwt_analog_clock.h qwt_compass.h qwt_counter.h qwt_dial.h qwt_knob.h qwt_slider.h qwt_thermo.h qwt_wheel.h ) set(QWT_SOURCES # General qwt_abstract_scale_draw.cpp qwt_clipper.cpp qwt_color_map.cpp qwt_column_symbol.cpp qwt_date.cpp qwt_date_scale_draw.cpp qwt_date_scale_engine.cpp qwt_dyngrid_layout.cpp qwt_event_pattern.cpp qwt_graphic.cpp qwt_interval.cpp qwt_interval_symbol.cpp qwt_math.cpp qwt_magnifier.cpp qwt_null_paintdevice.cpp qwt_painter.cpp qwt_painter_command.cpp qwt_panner.cpp qwt_picker.cpp qwt_picker_machine.cpp qwt_pixel_matrix.cpp qwt_point_3d.cpp qwt_point_polar.cpp qwt_round_scale_draw.cpp qwt_scale_div.cpp qwt_scale_draw.cpp qwt_scale_map.cpp qwt_spline.cpp qwt_scale_engine.cpp qwt_symbol.cpp qwt_system_clock.cpp qwt_text_engine.cpp qwt_text_label.cpp qwt_text.cpp qwt_transform.cpp qwt_widget_overlay.cpp # QwtPlot qwt_curve_fitter.cpp qwt_abstract_legend.cpp qwt_legend.cpp qwt_legend_data.cpp qwt_legend_label.cpp qwt_plot.cpp qwt_plot_renderer.cpp qwt_plot_xml.cpp qwt_plot_axis.cpp qwt_plot_curve.cpp qwt_plot_dict.cpp qwt_plot_directpainter.cpp qwt_plot_grid.cpp qwt_plot_histogram.cpp qwt_plot_item.cpp qwt_plot_abstract_barchart.cpp qwt_plot_barchart.cpp qwt_plot_multi_barchart.cpp qwt_plot_intervalcurve.cpp qwt_plot_zoneitem.cpp qwt_plot_tradingcurve.cpp qwt_plot_spectrogram.cpp qwt_plot_spectrocurve.cpp qwt_plot_scaleitem.cpp qwt_plot_legenditem.cpp qwt_plot_seriesitem.cpp qwt_plot_shapeitem.cpp qwt_plot_marker.cpp qwt_plot_textlabel.cpp qwt_plot_layout.cpp qwt_plot_canvas.cpp qwt_plot_panner.cpp qwt_plot_rasteritem.cpp qwt_plot_picker.cpp qwt_plot_zoomer.cpp qwt_plot_magnifier.cpp qwt_plot_rescaler.cpp qwt_point_mapper.cpp qwt_raster_data.cpp qwt_matrix_raster_data.cpp qwt_sampling_thread.cpp qwt_series_data.cpp qwt_point_data.cpp qwt_scale_widget.cpp # QwtSvg qwt_plot_svgitem.cpp # QwtOpenGL qwt_plot_glcanvas.cpp # QwtWidgets qwt_abstract_slider.cpp qwt_abstract_scale.cpp qwt_arrow_button.cpp qwt_analog_clock.cpp qwt_compass.cpp qwt_compass_rose.cpp qwt_counter.cpp qwt_dial.cpp qwt_dial_needle.cpp qwt_knob.cpp qwt_slider.cpp qwt_thermo.cpp qwt_wheel.cpp ) set(_qwt_moc_headers ) foreach(_header ${QWT_MOC_HEADERS}) list(APPEND _qwt_moc_headers src/${_header}) endforeach() set(_qwt_sources ) foreach(_source ${QWT_SOURCES}) list(APPEND _qwt_sources src/${_source}) endforeach() find_package(Qt5Svg REQUIRED) find_package(Qt5OpenGL REQUIRED) find_package(Qt5PrintSupport REQUIRED) find_package(Qt5Concurrent REQUIRED) qt5_wrap_cpp(_qwt_sources ${_qwt_moc_headers}) add_library(qwt SHARED ${_qwt_sources}) target_link_libraries(qwt PUBLIC Qt5::Svg Qt5::OpenGL Qt5::PrintSupport Qt5::Concurrent) target_compile_definitions(qwt PUBLIC QWT_DLL PRIVATE QWT_MAKEDLL) set_target_properties(qwt PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} ) # Build the designer plug-in option(QWT_BUILD_DESIGNER_PLUGIN "Build the Qt Designer plugin" ON) if (QWT_BUILD_DESIGNER_PLUGIN) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) set(_qwt_designer_sources designer/qwt_designer_plotdialog.cpp designer/qwt_designer_plugin.cpp ) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) find_package(Qt5Designer REQUIRED) include_directories(${Qt5Designer_INCLUDE_DIRS}) qt5_wrap_cpp(_qwt_designer_sources designer/qwt_designer_plugin.h designer/qwt_designer_plotdialog.h ) qt5_add_resources(_qwt_designer_sources designer/qwt_designer_plugin.qrc) add_library(qwt_designer_plugin SHARED ${_qwt_designer_sources}) target_link_libraries(qwt_designer_plugin qwt Qt5::Designer) set_target_properties(qwt_designer_plugin PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} COMPILE_DEFINITIONS QWT_DLL) endif() set(${PROJECT_NAME}_LIBRARIES qwt) # Install support if (QWT_BUILD_DESIGNER_PLUGIN) install(TARGETS qwt_designer_plugin RUNTIME DESTINATION plugins/designer LIBRARY DESTINATION plugins/designer ) endif() install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS LIBRARY DESTINATION lib ARCHIVE DESTINATION lib RUNTIME DESTINATION bin INCLUDES DESTINATION include/${PROJECT_NAME} ) install(DIRECTORY src/ DESTINATION include/${PROJECT_NAME} FILES_MATCHING PATTERN "*.h" ) # Config files configure_file( ${PROJECT_NAME}Config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(EXPORT ${PROJECT_NAME}_TARGETS FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake ) set(config_package_location lib/cmake/${PROJECT_NAME}) install(EXPORT ${PROJECT_NAME}_TARGETS FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${config_package_location} ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION ${config_package_location} ) diff --git a/CMakeExternals/SWIG.cmake b/CMakeExternals/SWIG.cmake index 0c008b722e..eccbfd6aae 100644 --- a/CMakeExternals/SWIG.cmake +++ b/CMakeExternals/SWIG.cmake @@ -1,71 +1,72 @@ #------------------------------------------------------------ # SWIG (Simple Wrapper Interface Generator) #----------------------------------------------------------- if(MITK_USE_SWIG) if(DEFINED SWIG_DIR AND NOT EXISTS ${SWIG_DIR}) message(FATAL_ERROR "SWIG_DIR variable is defined but corresponds to non-existing directory") endif() set(SWIG_TARGET_VERSION 3.0.2) set(proj SWIG) - set(proj_DEPENDENCIES PCRE) + if(WIN32) + set(proj_DEPENDENCIES) + else() + set(proj_DEPENDENCIES PCRE) + endif() set(SWIG_DEPENDS ${proj}) if(NOT SWIG_DIR) # We don't "install" SWIG in the common install prefix, # since it is only used as a tool during the MITK super-build # to generate the Python wrappings for some projects. # binary SWIG for windows if(WIN32) set(swig_source_dir ${CMAKE_CURRENT_BINARY_DIR}/swigwin-${SWIG_TARGET_VERSION}) # swig.exe available as pre-built binary on Windows: ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/swigwin-${SWIG_TARGET_VERSION}.zip URL_MD5 "3f18de4fc09ab9abb0d3be37c11fbc8f" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" ) ExternalProject_Get_Property(${proj} source_dir) set(SWIG_DIR ${source_dir}) set(SWIG_EXECUTABLE ${source_dir}/swig.exe) else() - - list(APPEND SWIG_DEPENDENCIES PCRE) - # swig uses bison find it by cmake and pass it down find_package(BISON) set(BISON_FLAGS "" CACHE STRING "Flags used by bison") mark_as_advanced( BISON_FLAGS) ExternalProject_add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/swig-${SWIG_TARGET_VERSION}.tar.gz # Custom install dir for SWIG INSTALL_DIR ${ep_prefix}/src/${proj}-install URL_MD5 "62f9b0d010cef36a13a010dc530d0d41" CONFIGURE_COMMAND /./configure CC=${CMAKE_C_COMPILER}${CMAKE_C_COMPILER_ARG1} LDFLAGS=${CMAKE_LINKER_FLAGS} ${CMAKE_LINKER_FLAGS_RELEASE} CXX=${CMAKE_CXX_COMPILER}${CMAKE_CXX_COMPILER_ARG1} "--prefix=" "--with-pcre-prefix=${PCRE_DIR}" --without-octave "--with-python=${Python3_EXECUTABLE}" DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} install_dir) set(SWIG_DIR ${install_dir}/share/swig/${SWIG_TARGET_VERSION}) set(SWIG_EXECUTABLE ${install_dir}/bin/swig) endif() else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/VTK-9.0.0.patch b/CMakeExternals/VTK-9.0.0.patch new file mode 100644 index 0000000000..a468c8fff2 --- /dev/null +++ b/CMakeExternals/VTK-9.0.0.patch @@ -0,0 +1,15 @@ +diff --git a/Rendering/FreeType/vtkFreeTypeTools.cxx b/Rendering/FreeType/vtkFreeTypeTools.cxx +index c54289dc60..03b899c4da 100644 +--- a/Rendering/FreeType/vtkFreeTypeTools.cxx ++++ b/Rendering/FreeType/vtkFreeTypeTools.cxx +@@ -378,8 +378,7 @@ FTC_CMapCache* vtkFreeTypeTools::GetCMapCache() + } + + //---------------------------------------------------------------------------- +-FT_CALLBACK_DEF(FT_Error) +-vtkFreeTypeToolsFaceRequester( ++static FT_Error vtkFreeTypeToolsFaceRequester( + FTC_FaceID face_id, FT_Library lib, FT_Pointer request_data, FT_Face* face) + { + #if VTK_FTFC_DEBUG_CD + diff --git a/CMakeExternals/VTK.cmake b/CMakeExternals/VTK.cmake index 36c53a21b2..96341d9d64 100644 --- a/CMakeExternals/VTK.cmake +++ b/CMakeExternals/VTK.cmake @@ -1,86 +1,88 @@ #----------------------------------------------------------------------------- # VTK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED VTK_DIR AND NOT EXISTS ${VTK_DIR}) message(FATAL_ERROR "VTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj VTK) set(proj_DEPENDENCIES ) set(VTK_DEPENDS ${proj}) if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() if(NOT DEFINED VTK_DIR) set(additional_cmake_args ) if(WIN32) list(APPEND additional_cmake_args -DCMAKE_CXX_MP_FLAG:BOOL=ON ) else() list(APPEND additional_cmake_args -DVTK_MODULE_USE_EXTERNAL_VTK_freetype:BOOL=ON ) endif() # Optionally enable memory leak checks for any objects derived from vtkObject. This # will force unit tests to fail if they have any of these memory leaks. option(MITK_VTK_DEBUG_LEAKS OFF) mark_as_advanced(MITK_VTK_DEBUG_LEAKS) list(APPEND additional_cmake_args -DVTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} ) if(MITK_USE_Qt5) list(APPEND additional_cmake_args -DVTK_GROUP_ENABLE_Qt:STRING=YES -DQt5_DIR:PATH=${Qt5_DIR} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/VTK-9.0.0.tar.gz URL_MD5 fa61cd36491d89a17edab18522bdda49 + PATCH_COMMAND + ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/VTK-9.0.0.patch CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} -DVTK_ENABLE_WRAPPING:BOOL=OFF -DVTK_LEGACY_REMOVE:BOOL=ON -DVTK_MODULE_ENABLE_VTK_TestingRendering:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES ${additional_cmake_args} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(VTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/cpprestsdk.cmake b/CMakeExternals/cpprestsdk.cmake index c48dccc0cf..93644937b8 100644 --- a/CMakeExternals/cpprestsdk.cmake +++ b/CMakeExternals/cpprestsdk.cmake @@ -1,40 +1,39 @@ set(proj cpprestsdk) set(proj_DEPENDENCIES Boost ZLIB) if(MITK_USE_${proj}) set(${proj}_DEPENDS ${proj}) if(DEFINED ${proj}_DIR AND NOT EXISTS ${${proj}_DIR}) message(FATAL_ERROR "${proj}_DIR variable is defined but corresponds to non-existing directory!") endif() if(NOT DEFINED ${proj}_DIR) set(cmake_cache_args ${ep_common_cache_args} -DBUILD_SAMPLES:BOOL=OFF -DBUILD_TESTS:BOOL=OFF -DWERROR:BOOL=OFF ) if(OPENSSL_ROOT_DIR) list(APPEND cmake_cache_args -DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR} ) endif() ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/cpprestsdk-2.10.10.tar.gz - URL_MD5 705c4bd79158433309b21251a4936b18 - PATCH_COMMAND ${PATCH_COMMAND} -d "Release/libs/websocketpp" -N -p1 -i "${CMAKE_CURRENT_LIST_DIR}/${proj}.patch" + GIT_REPOSITORY https://github.com/microsoft/cpprestsdk.git + GIT_TAG v2.10.16 SOURCE_SUBDIR Release CMAKE_ARGS ${ep_common_args} CMAKE_CACHE_ARGS ${cmake_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/cpprestsdk.patch b/CMakeExternals/cpprestsdk.patch deleted file mode 100644 index c6e9591407..0000000000 --- a/CMakeExternals/cpprestsdk.patch +++ /dev/null @@ -1,139 +0,0 @@ -From c769c9238ad62178f506038178714a1c35aa2769 Mon Sep 17 00:00:00 2001 -From: Stefan Floeren <42731906+stefan-floeren@users.noreply.github.com> -Date: Tue, 16 Apr 2019 08:38:01 +0200 -Subject: [PATCH 1/2] Replace make_shared with new in some cases - -Replace make_shared for asio types that take a lib::ref as a parameter. -This should fix the ASIO change (boostorg/asio@59066d8) for 1.70, -while keeping it backwards compatible to older boost versions. ---- - websocketpp/transport/asio/connection.hpp | 7 ++++--- - websocketpp/transport/asio/endpoint.hpp | 3 +-- - websocketpp/transport/asio/security/none.hpp | 3 +-- - websocketpp/transport/asio/security/tls.hpp | 3 +-- - 4 files changed, 7 insertions(+), 9 deletions(-) - -diff --git a/websocketpp/transport/asio/connection.hpp b/websocketpp/transport/asio/connection.hpp -index 60f88a79..1ccda8f3 100644 ---- a/websocketpp/transport/asio/connection.hpp -+++ b/websocketpp/transport/asio/connection.hpp -@@ -311,9 +311,10 @@ class connection : public config::socket_type::socket_con_type { - * needed. - */ - timer_ptr set_timer(long duration, timer_handler callback) { -- timer_ptr new_timer = lib::make_shared( -- lib::ref(*m_io_service), -- lib::asio::milliseconds(duration) -+ timer_ptr new_timer( -+ new lib::asio::steady_timer( -+ *m_io_service, -+ lib::asio::milliseconds(duration)) - ); - - if (config::enable_multithreading) { -diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp -index ddab2c74..4b719a97 100644 ---- a/websocketpp/transport/asio/endpoint.hpp -+++ b/websocketpp/transport/asio/endpoint.hpp -@@ -195,8 +195,7 @@ class endpoint : public config::socket_type { - - m_io_service = ptr; - m_external_io_service = true; -- m_acceptor = lib::make_shared( -- lib::ref(*m_io_service)); -+ m_acceptor.reset(new lib::asio::ip::tcp::acceptor(*m_io_service)); - - m_state = READY; - ec = lib::error_code(); -diff --git a/websocketpp/transport/asio/security/none.hpp b/websocketpp/transport/asio/security/none.hpp -index 5c8293db..6c7d3524 100644 ---- a/websocketpp/transport/asio/security/none.hpp -+++ b/websocketpp/transport/asio/security/none.hpp -@@ -168,8 +168,7 @@ class connection : public lib::enable_shared_from_this { - return socket::make_error_code(socket::error::invalid_state); - } - -- m_socket = lib::make_shared( -- lib::ref(*service)); -+ m_socket.reset(new lib::asio::ip::tcp::socket(*service)); - - if (m_socket_init_handler) { - m_socket_init_handler(m_hdl, *m_socket); -diff --git a/websocketpp/transport/asio/security/tls.hpp b/websocketpp/transport/asio/security/tls.hpp -index c76fd9aa..04ac3790 100644 ---- a/websocketpp/transport/asio/security/tls.hpp -+++ b/websocketpp/transport/asio/security/tls.hpp -@@ -193,8 +193,7 @@ class connection : public lib::enable_shared_from_this { - if (!m_context) { - return socket::make_error_code(socket::error::invalid_tls_context); - } -- m_socket = lib::make_shared( -- _WEBSOCKETPP_REF(*service),lib::ref(*m_context)); -+ m_socket.reset(new socket_type(*service, *m_context)); - - if (m_socket_init_handler) { - m_socket_init_handler(m_hdl, get_socket()); - -From f810ca2e800e9b55be41c5911cf1d1185fcd516b Mon Sep 17 00:00:00 2001 -From: Stefan Floeren <42731906+stefan-floeren@users.noreply.github.com> -Date: Wed, 17 Apr 2019 10:06:18 +0000 -Subject: [PATCH 2/2] Fix missed entries; fix testing - ---- - CMakeLists.txt | 2 +- - websocketpp/transport/asio/connection.hpp | 3 +-- - websocketpp/transport/asio/endpoint.hpp | 7 ++----- - 3 files changed, 4 insertions(+), 8 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index 2786aba9..951de975 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -202,7 +202,7 @@ if (BUILD_TESTS OR BUILD_EXAMPLES) - endif () - - if (NOT Boost_USE_STATIC_LIBS) -- add_definitions (/DBOOST_TEST_DYN_LINK) -+ add_definitions (-DBOOST_TEST_DYN_LINK) - endif () - - set (Boost_FIND_REQUIRED TRUE) -diff --git a/websocketpp/transport/asio/connection.hpp b/websocketpp/transport/asio/connection.hpp -index 1ccda8f3..57dda74a 100644 ---- a/websocketpp/transport/asio/connection.hpp -+++ b/websocketpp/transport/asio/connection.hpp -@@ -462,8 +462,7 @@ class connection : public config::socket_type::socket_con_type { - m_io_service = io_service; - - if (config::enable_multithreading) { -- m_strand = lib::make_shared( -- lib::ref(*io_service)); -+ m_strand.reset(new lib::asio::io_service::strand(*io_service)); - } - - lib::error_code ec = socket_con_type::init_asio(io_service, m_strand, -diff --git a/websocketpp/transport/asio/endpoint.hpp b/websocketpp/transport/asio/endpoint.hpp -index 4b719a97..94509adb 100644 ---- a/websocketpp/transport/asio/endpoint.hpp -+++ b/websocketpp/transport/asio/endpoint.hpp -@@ -687,9 +687,7 @@ class endpoint : public config::socket_type { - * @since 0.3.0 - */ - void start_perpetual() { -- m_work = lib::make_shared( -- lib::ref(*m_io_service) -- ); -+ m_work.reset(new lib::asio::io_service::work(*m_io_service)); - } - - /// Clears the endpoint's perpetual flag, allowing it to exit when empty -@@ -853,8 +851,7 @@ class endpoint : public config::socket_type { - - // Create a resolver - if (!m_resolver) { -- m_resolver = lib::make_shared( -- lib::ref(*m_io_service)); -+ m_resolver.reset(new lib::asio::ip::tcp::resolver(*m_io_service)); - } - - tcon->set_uri(u); diff --git a/CMakeExternals/tinyxml-2.6.2.patch b/CMakeExternals/tinyxml-2.6.2.patch deleted file mode 100644 index 4a601bb1e5..0000000000 --- a/CMakeExternals/tinyxml-2.6.2.patch +++ /dev/null @@ -1,266 +0,0 @@ -diff -burN tinyxml/tinyxml.cpp tinyxml-src/tinyxml.cpp ---- tinyxml/tinyxml.cpp 2011-05-15 04:24:57.000000000 +0200 -+++ tinyxml-src/tinyxml.cpp 2015-01-14 15:19:38.685333149 +0100 -@@ -34,6 +34,9 @@ - FILE* TiXmlFOpen( const char* filename, const char* mode ); - - bool TiXmlBase::condenseWhiteSpace = true; -+static unsigned int required_decimal_places = 14+1; // Need 14 for mitk default accuracy plus 1 to make sure we're within tolerance. -+ -+ - - // Microsoft compiler security - FILE* TiXmlFOpen( const char* filename, const char* mode ) -@@ -757,21 +760,21 @@ - #endif - - --void TiXmlElement::SetDoubleAttribute( const char * name, double val ) -+void TiXmlElement::SetDoubleAttribute( const char * name, double val, const unsigned int requiredDecimalPlaces ) - { - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { -- attrib->SetDoubleValue( val ); -+ attrib->SetDoubleValue( val, requiredDecimalPlaces ); - } - } - - - #ifdef TIXML_USE_STL --void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) -+void TiXmlElement::SetDoubleAttribute( const std::string& name, double val, const unsigned int requiredDecimalPlaces ) - { - TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); - if ( attrib ) { -- attrib->SetDoubleValue( val ); -+ attrib->SetDoubleValue( val, requiredDecimalPlaces ); - } - } - #endif -@@ -1242,33 +1245,73 @@ - - int TiXmlAttribute::QueryDoubleValue( double* dval ) const - { -+ //save old locale -+ char * oldLocale; -+ oldLocale = setlocale( LC_ALL, 0 ); -+ -+ //set new locale -+ setlocale( LC_ALL, "C" ); - if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) -+ { -+ //restore locale -+ setlocale( LC_ALL, oldLocale ); - return TIXML_SUCCESS; -+ } -+ //restore locale -+ setlocale( LC_ALL, oldLocale ); - return TIXML_WRONG_TYPE; - } - - void TiXmlAttribute::SetIntValue( int _value ) - { - char buf [64]; -- #if defined(TIXML_SNPRINTF) -+#if defined(TIXML_SNPRINTF) - TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); -- #else -+#else - sprintf (buf, "%d", _value); -- #endif -+#endif - SetValue (buf); - } - --void TiXmlAttribute::SetDoubleValue( double _value ) -+ -+ -+ -+void TiXmlAttribute::SetDoubleValue( double _value, const unsigned int requiredDecimalPlaces ) - { -+#if defined(TIXML_USE_STL) -+ std::ostringstream ss; -+ //save old locale -+ char * oldLocale; -+ oldLocale = setlocale( LC_ALL, 0 ); -+ -+ //set new locale -+ setlocale( LC_ALL, "C" ); -+ ss.precision(TiXmlBase::Precision(_value, requiredDecimalPlaces)); -+ ss << _value; -+ SetValue( ss.str() ); -+ //restore locale -+ setlocale( LC_ALL, oldLocale ); -+#else - char buf [256]; -- #if defined(TIXML_SNPRINTF) -- TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); -- #else -- sprintf (buf, "%g", _value); -- #endif -+ -+ //save old locale -+ char * oldLocale; -+ oldLocale = setlocale( LC_ALL, 0 ); -+ -+ //set new locale -+ setlocale( LC_ALL, "C" ); -+#if defined(TIXML_SNPRINTF) -+ TIXML_SNPRINTF( buf, sizeof(buf), TiXmlBase::Format(_value, requiredDecimalPlaces).c_str(), _value); -+#else -+ sprintf (buf, TiXmlBase::Format(_value, requiredDecimalPlaces).c_str(), _value); -+#endif - SetValue (buf); -+ //restore locale -+ setlocale( LC_ALL, oldLocale ); -+#endif - } - -+ - int TiXmlAttribute::IntValue() const - { - return atoi (value.c_str ()); -@@ -1276,7 +1319,15 @@ - - double TiXmlAttribute::DoubleValue() const - { -+#if defined(TIXML_USE_STL) -+ std::istringstream ss(value); -+ ss.imbue(std::locale("C")); -+ double dval; -+ ss >> dval; -+ return dval; -+#else - return atof (value.c_str ()); -+#endif - } - - -@@ -1884,3 +1935,36 @@ - return true; - } - -+unsigned int TiXmlBase::Precision( const double value, const unsigned int requiredDecimalPlaces ) const -+{ -+ unsigned int lhs = 0; -+ unsigned int one_for_plus_minus_sign = 1; -+ -+ lhs = 0; -+ double temp(value); -+ while (temp >= 1.0) -+ { -+ lhs++; -+ temp /= 10.0; -+ } -+ -+ return( lhs + requiredDecimalPlaces + one_for_plus_minus_sign ); -+} -+ -+/** -+ Return the printf format string that will ensure that the double value -+ passed in will be stored with 'required_decimal_places' worth of decimal -+ points as well as enough digits for the left hand side of the decimal point. -+ */ -+TIXML_STRING TiXmlBase::Format( const double value, const unsigned int requiredDecimalPlaces ) const -+{ -+ char buf[ 32 ]; -+ -+#if defined(TIXML_SNPRINTF) -+ TIXML_SNPRINTF( buf, sizeof(buf), "%%%d.%dlf", Precision(value, requiredDecimalPlaces), requiredDecimalPlaces); -+#else -+ sprintf( buf, "%%%d.%dlf", Precision(value, requiredDecimalPlaces), requiredDecimalPlaces); -+#endif -+ -+ return(TIXML_STRING(buf)); -+} -diff -burN tinyxml/tinyxml.h tinyxml-src/tinyxml.h ---- tinyxml/tinyxml.h 2011-05-15 04:24:57.000000000 +0200 -+++ tinyxml-src/tinyxml.h 2015-01-14 15:19:38.686333149 +0100 -@@ -20,12 +20,24 @@ - - 3. This notice may not be removed or altered from any source - distribution. --*/ -+ */ - - - #ifndef TINYXML_INCLUDED - #define TINYXML_INCLUDED - -+#ifndef TIXML_USE_STL -+ #define TIXML_USE_STL -+#endif -+ -+#ifndef TIXML_USE_STL -+#define TIXML_USE_STL -+#endif -+ -+#ifndef TIXML_USE_STL -+#define TIXML_USE_STL -+#endif -+ - #ifdef _MSC_VER - #pragma warning( push ) - #pragma warning( disable : 4530 ) -@@ -93,9 +105,11 @@ - const int TIXML_MINOR_VERSION = 6; - const int TIXML_PATCH_VERSION = 2; - -+#define DEFAULT_REQUIRED_DECIMAL_PLACES 14 -+ - /* Internal structure for tracking location of items - in the XML file. --*/ -+ */ - struct TiXmlCursor - { - TiXmlCursor() { Clear(); } -@@ -283,6 +297,10 @@ - TIXML_ERROR_STRING_COUNT - }; - -+ unsigned int Precision( const double value, const unsigned int requiredDecimalPlaces ) const ; -+ -+ TIXML_STRING Format( const double value, const unsigned int requiredDecimalPlaces ) const; -+ - protected: - - static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); -@@ -836,14 +854,14 @@ - void SetValue( const char* _value ) { value = _value; } ///< Set the value. - - void SetIntValue( int _value ); ///< Set the value from an integer. -- void SetDoubleValue( double _value ); ///< Set the value from a double. -+ void SetDoubleValue( double _value, const unsigned int requiredDecimalPlaces = DEFAULT_REQUIRED_DECIMAL_PLACES ); ///< Set the value from a double. - -- #ifdef TIXML_USE_STL -+#ifdef TIXML_USE_STL - /// STL std::string form. - void SetName( const std::string& _name ) { name = _name; } - /// STL std::string form. - void SetValue( const std::string& _value ) { value = _value; } -- #endif -+#endif - - /// Get the next sibling attribute in the DOM. Returns null at end. - const TiXmlAttribute* Next() const; -@@ -1061,8 +1079,8 @@ - ///< STL std::string form. - void SetAttribute( const std::string& name, int _value ); - ///< STL std::string form. -- void SetDoubleAttribute( const std::string& name, double value ); -- #endif -+ void SetDoubleAttribute( const std::string& name, double value, const unsigned int requiredDecimalPlaces = DEFAULT_REQUIRED_DECIMAL_PLACES ); -+#endif - - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. -@@ -1072,7 +1090,7 @@ - /** Sets an attribute of name to a given value. The attribute - will be created if it does not exist, or changed if it does. - */ -- void SetDoubleAttribute( const char * name, double value ); -+ void SetDoubleAttribute( const char * name, double value, const unsigned int requiredDecimalPlaces = DEFAULT_REQUIRED_DECIMAL_PLACES ); - - /** Deletes an attribute with the given name. - */ diff --git a/CMakeExternals/tinyxml.cmake b/CMakeExternals/tinyxml2.cmake similarity index 65% rename from CMakeExternals/tinyxml.cmake rename to CMakeExternals/tinyxml2.cmake index 74391bee27..8b24f8c184 100644 --- a/CMakeExternals/tinyxml.cmake +++ b/CMakeExternals/tinyxml2.cmake @@ -1,52 +1,52 @@ #----------------------------------------------------------------------------- -# tinyxml +# tinyxml2 #----------------------------------------------------------------------------- # Sanity checks -if(DEFINED tinyxml_DIR AND NOT EXISTS ${tinyxml_DIR}) - message(FATAL_ERROR "tinyxml_DIR variable is defined but corresponds to non-existing directory") +if(DEFINED tinyxml2_DIR AND NOT EXISTS ${tinyxml2_DIR}) + message(FATAL_ERROR "tinyxml2_DIR variable is defined but corresponds to non-existing directory") endif() -set(proj tinyxml) +set(proj tinyxml2) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) -if(NOT DEFINED tinyxml_DIR) +if(NOT DEFINED tinyxml2_DIR) set(additional_cmake_args ) if(WIN32) set(additional_cmake_args -DBUILD_SHARED_LIBS:BOOL=OFF) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/tinyxml_2_6_2.tar.gz - URL_MD5 c1b864c96804a10526540c664ade67f0 - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/tinyxml-2.6.2.patch - COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=tinyxml -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake + URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/tinyxml2-8.0.0.tar.gz + URL_MD5 5dc535c8b34ee621fe2128f072d275b5 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} + -DBUILD_TESTING:BOOL=OFF + -DBUILD_TESTS:BOOL=OFF CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/tinyxmlCMakeLists.txt b/CMakeExternals/tinyxmlCMakeLists.txt deleted file mode 100644 index d19c0dfb25..0000000000 --- a/CMakeExternals/tinyxmlCMakeLists.txt +++ /dev/null @@ -1,66 +0,0 @@ -cmake_minimum_required(VERSION 2.8.4) - -project(tinyxml) - -set(${PROJECT_NAME}_MAJOR_VERSION 2) -set(${PROJECT_NAME}_MINOR_VERSION 6) -set(${PROJECT_NAME}_PATCH_VERSION 2) -set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) - - -set(tinyxml_HEADERS - tinystr.h - tinyxml.h -) - -set(tinyxml_SOURCES - tinyxml.cpp - tinyxmlparser.cpp - tinyxmlerror.cpp - tinystr.cpp -) - -add_library(tinyxml ${tinyxml_HEADERS} ${tinyxml_SOURCES}) -set_target_properties(tinyxml PROPERTIES - SOVERSION ${${PROJECT_NAME}_VERSION}) - -set(${PROJECT_NAME}_LIBRARIES tinyxml) - -# Install support - -install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include/${PROJECT_NAME} -) -install(FILES ${tinyxml_HEADERS} - DESTINATION include/${PROJECT_NAME} -) - -# Config files -configure_file( - ${PROJECT_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - @ONLY -) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - @ONLY -) - -export(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake -) - -set(config_package_location lib/cmake/${PROJECT_NAME}) -install(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${PROJECT_NAME}Targets.cmake - DESTINATION ${config_package_location} -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION ${config_package_location} -) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cd4bc6dd5..9dbf9c2326 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1418 +1,1422 @@ -set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.14.5) +set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.18) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) +if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19 AND CMAKE_VERSION VERSION_LESS 3.19.2) + message(FATAL_ERROR "\ +CMake v${CMAKE_VERSION} is defective [1]. \ +Please either downgrade to v3.18 or upgrade to at least v3.19.2.\n\ +[1] https://gitlab.kitware.com/cmake/cmake/-/issues/21529") +endif() + #----------------------------------------------------------------------------- -# See https://cmake.org/cmake/help/v3.14/manual/cmake-policies.7.html for details +# Policies #----------------------------------------------------------------------------- -set(project_policies ) -foreach(policy ${project_policies}) - if(POLICY ${policy}) - cmake_policy(SET ${policy} NEW) - endif() -endforeach() +#[[ T28060 + + https://cmake.org/cmake/help/v3.18/policy/CMP0091.html + https://cmake.org/cmake/help/v3.18/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html + + We pass CMP0091 to all external projects as command-line argument: + -DCMAKE_POLICY_DEFAULT_CMP0091:STRING=OLD + ]] +cmake_policy(SET CMP0091 OLD) #----------------------------------------------------------------------------- # 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 "") unset(MITK_ABSOLUTE_EXTENSION_DIRS) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_ABSOLUTE_EXTENSION_DIR "${MITK_EXTENSION_DIR}" ABSOLUTE) list(APPEND MITK_ABSOLUTE_EXTENSION_DIRS "${MITK_ABSOLUTE_EXTENSION_DIR}") endforeach() set(MITK_DIR_PLUS_EXTENSION_DIRS "${MITK_SOURCE_DIR}" ${MITK_ABSOLUTE_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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake") 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(CTest) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) 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_FAST_TESTING "Disable long-running tests like packaging" OFF) option(MITK_XVFB_TESTING "Execute test drivers through xvfb-run" OFF) 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_XVFB_TESTING MITK_FAST_TESTING MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) #----------------------------------------------------------------------------- # Set UI testing flags #----------------------------------------------------------------------------- if(MITK_XVFB_TESTING) set(MITK_XVFB_TESTING_COMMAND "xvfb-run" "--auto-servernum" CACHE STRING "Command and options to test through Xvfb") mark_as_advanced(MITK_XVFB_TESTING_COMMAND) endif(MITK_XVFB_TESTING) # ----------------------------------------- # Other options set(MITK_CUSTOM_REVISION_DESC "" CACHE STRING "Override MITK revision description") mark_as_advanced(MITK_CUSTOM_REVISION_DESC) set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMakeExternals") 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_ABSOLUTE_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) # ----------------------------------------- # Qt version related variables option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) if(WIN32) set(MITK_QT5_MINIMUM_VERSION 5.12.9) else() set(MITK_QT5_MINIMUM_VERSION 5.12) endif() 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() # ----------------------------------------- # 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) if(WIN32 AND Qt5_DIR) set(_dir_candidate "${Qt5_DIR}/../../../../../Tools/OpenSSL/Win_x64") get_filename_component(_dir_candidate ${_dir_candidate} ABSOLUTE) if(EXISTS "${_dir_candidate}") set(OPENSSL_ROOT_DIR "${_dir_candidate}") endif() endif() 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 either install Win32 OpenSSL:\n" " https://slproweb.com/products/Win32OpenSSL.html\n" "Or use the Qt Maintenance tool to install:\n" " Developer and Designer Tools > OpenSSL Toolkit > OpenSSL 64-bit binaries\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() find_package(Git REQUIRED) #----------------------------------------------------------------------------- # 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 **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Organize MITK targets in folders #----------------------------------------------------------------------------- set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(MITK_ROOT_FOLDER "MITK" CACHE STRING "") mark_as_advanced(MITK_ROOT_FOLDER) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) 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(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 applications 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(MITK_CTEST_SCRIPT_MODE STREQUAL "Continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "Experimental") set(MITK_FAST_TESTING ON) 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") 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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake/PackageDepends") 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) +set(Boost_ADDITIONAL_VERSIONS 1.74 1.74.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) #[[ See T27701 # 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 (const std::exception& e) { fprintf(stderr, \"%s\\n\", e.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 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 subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) set(MITK_ROOT_FOLDER_BACKUP "${MITK_ROOT_FOLDER}") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) get_filename_component(MITK_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set(MITK_MODULES_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Modules") 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() set(MITK_ROOT_FOLDER "${MITK_ROOT_FOLDER_BACKUP}") add_subdirectory(Wrapping) set(MITK_DOXYGEN_OUTPUT_DIR "${PROJECT_BINARY_DIR}/Documentation/Doxygen" CACHE PATH "Output directory for doxygen generated documentation.") if(MITK_USE_BLUEBERRY) 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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Plugins") 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") 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") 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_ABSOLUTE_EXTENSION_DIRS}) set(MITK_APPLICATIONS_EXTENSION_DIR "${MITK_EXTENSION_DIR}/Applications") 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/Documentation/CMakeLists.txt b/Documentation/CMakeLists.txt index 9a25867947..a25b37f09e 100644 --- a/Documentation/CMakeLists.txt +++ b/Documentation/CMakeLists.txt @@ -1,166 +1,166 @@ # Different doxygen versions produce significantly different behaviour in the MITK documentation # especially in regards to the MITK Qt assistant help files and markdown files. # The HTML documentation is supposed to be build with Doxygen 1.8.7 or newer, the # Qt assistant QCH files are supposed to be generated with Doxygen 1.8.7 or newer. # So we check for 1.8.7 here and QCH generation support is checked in # BlueBerry/CMakeLists.txt set(supported_doxygen_version "1.8.7") if(DOXYGEN_VERSION VERSION_LESS ${supported_doxygen_version}) MESSAGE(WARNING "Unsupported doxygen version ${DOXYGEN_VERSION}. The MITK HTML documentation has been tested to work with doxygen ${supported_doxygen_version} or newer.") endif() option(USE_DOT "Use dot program for generating graphical class diagrams with doxygen, if available" ON) option(MITK_DOXYGEN_BUILD_ALWAYS "Always build the MITK documentation when building the default target" OFF) option(MITK_DOXYGEN_GENERATE_QCH_FILES "Use doxygen to generate Qt compressed help files for MITK docs" OFF) mark_as_advanced(USE_DOT MITK_DOXYGEN_BUILD_ALWAYS MITK_DOXYGEN_GENERATE_QCH_FILES) if (MITK_DOXYGEN_GENERATE_QCH_FILES AND DOXYGEN_VERSION VERSION_LESS "1.8.7") message(WARNING "> Forcing MITK_DOXYGEN_GENERATE_QCH_FILES to OFF because Doxygen version 1.8.7 or newer not found.") set(MITK_DOXYGEN_GENERATE_QCH_FILES OFF CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) endif() set(HAVE_DOT "NO") if(DOXYGEN_DOT_EXECUTABLE AND USE_DOT) set(HAVE_DOT "YES") endif() set(MITK_DOXYGEN_TAGFILE_NAME ${MITK_DOXYGEN_OUTPUT_DIR}/MITK.tag CACHE INTERNAL "MITK Doxygen tag file") # This is relative to the working directory of the doxygen command set(MITK_DOXYGEN_STYLESHEET mitk_doxygen_extra.css) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${MITK_DOXYGEN_STYLESHEET} ${CMAKE_CURRENT_BINARY_DIR}/${MITK_DOXYGEN_STYLESHEET} COPYONLY) # Create QCH files for MITK and external projects set(MITK_DOXYGEN_GENERATE_QHP "NO") if(MITK_DOXYGEN_GENERATE_QCH_FILES) find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} DOC "The location of the the Qt help generator executable" NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE) if(NOT QT_HELPGENERATOR_EXECUTABLE) message(SEND_ERROR "The Qt help generator could not be found. Disabling qch generation") else() set(MITK_DOXYGEN_GENERATE_QHP "YES") endif() # The name of the generated MITK qch file, relative to the # Doxygen HTML output folder set(MITK_DOXYGEN_QCH_FILE "${MITK_BINARY_DIR}/MITK-${MITK_REVISION_ID}.qch") # Generating ITK and VTK docs it not done yet #option(MITK_DOXYGEN_GENERATE_VTK_QCH_FILE "Use doxygen to generate a Qt compressed help file for VTK docs" OFF) #option(MITK_DOXYGEN_GENERATE_ITK_QCH_FILE "Use doxygen to generate a Qt compressed help file for ITK docs" OFF) #mark_as_advanced(MITK_DOXYGEN_GENERATE_VTK_QCH_FILE MITK_DOXYGEN_GENERATE_ITK_QCH_FILE) endif() # Compile a doxygen input filter for processing CMake scripts include(mitkFunctionCMakeDoxygenFilterCompile) mitkFunctionCMakeDoxygenFilterCompile(NAMESPACE "CMake") # Configure some doxygen options if(NOT MITK_DOXYGEN_INTERNAL_DOCS) set(MITK_DOXYGEN_INTERNAL_DOCS "NO") set(MITK_DOXYGEN_HIDE_FRIEND_COMPOUNDS "YES") set(MITK_DOXYGEN_EXCLUDE_PATTERNS "*_p.* *Private.h */internal/*") else() set(MITK_DOXYGEN_HIDE_FRIEND_COMPOUNDS "NO") set(MITK_DOXYGEN_EXCLUDE_PATTERNS "") endif() if(NOT MITK_DOXYGEN_GENERATE_TODOLIST) set(MITK_DOXYGEN_GENERATE_TODOLIST "NO") endif() if(NOT MITK_DOXYGEN_GENERATE_BUGLIST) set(MITK_DOXYGEN_GENERATE_BUGLIST "NO") endif() if(NOT MITK_DOXYGEN_HTML_DYNAMIC_SECTIONS) set(MITK_DOXYGEN_HTML_DYNAMIC_SECTIONS "NO") endif() if(NOT MITK_DOXYGEN_UML_LOOK) set(MITK_DOXYGEN_UML_LOOK "NO") endif() if(NOT MITK_DOXYGEN_GENERATE_DEPRECATEDLIST) set(MITK_DOXYGEN_GENERATE_DEPRECATEDLIST "YES") endif() if(NOT DEFINED MITK_DOXYGEN_DOT_NUM_THREADS) set(MITK_DOXYGEN_DOT_NUM_THREADS 0) endif() if(NOT DEFINED US_PLATFORM) if(UNIX) if(APPLE) set(US_PLATFORM "US_PLATFORM_APPLE=1") else() set(US_PLATFORM "US_PLATFORM_LINUX=1") endif() set(US_PLATFORM "${US_PLATFORM} \\\nUS_PLATFORM_POSIX=1") else() set(US_PLATFORM "US_PLATFORM_WINDOWS=1") endif() endif() -# parse which plug-in documentation to activate +#[[ parse which plug-in documentation to activate set(USERS_GUIDE_INPUT "${MITK_SOURCE_DIR}/Documentation/Doxygen/UserManual/") if(MITK_USE_BLUEBERRY) if(MITK_BUILD_ALL_PLUGINS) set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ ${MITK_SOURCE_DIR}/Plugins/") else() foreach(mitk_plugin ${${CMAKE_PROJECT_NAME}_PLUGIN_LIBRARIES}) # we want each line to end in " \" and each directory be on a separate line set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ ${${mitk_plugin}_SOURCE_DIR}/") endforeach() endif() if(MITK_BUILD_EXAMPLES) set(USERS_GUIDE_INPUT "${USERS_GUIDE_INPUT} \\ ${MITK_SOURCE_DIR}/Examples/Plugins/") endif() -endif() +endif()]] -# create output directories for the guides +#[[ create output directories for the guides file(MAKE_DIRECTORY ${MITK_DOXYGEN_OUTPUT_DIR}/Guides/Users_Guide/) -file(MAKE_DIRECTORY ${MITK_DOXYGEN_OUTPUT_DIR}/Guides/Developers_Guide/) +file(MAKE_DIRECTORY ${MITK_DOXYGEN_OUTPUT_DIR}/Guides/Developers_Guide/)]] configure_file(doxygen.conf.in ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf) -configure_file(doxygen_users_guide.conf.in +#[[configure_file(doxygen_users_guide.conf.in ${CMAKE_CURRENT_BINARY_DIR}/doxygen_users_guide.conf) configure_file(doxygen_developers_guide.conf.in - ${CMAKE_CURRENT_BINARY_DIR}/doxygen_developers_guide.conf) + ${CMAKE_CURRENT_BINARY_DIR}/doxygen_developers_guide.conf)]] if(MITK_DOXYGEN_BUILD_ALWAYS) set(_doc_in_all "ALL") else() set(_doc_in_all "") endif() add_custom_target(doc ${_doc_in_all} ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.conf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -add_custom_target(doc_usersguide +#[[add_custom_target(doc_usersguide ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen_users_guide.conf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_target(doc_developersguide ${DOXYGEN} ${CMAKE_CURRENT_BINARY_DIR}/doxygen_developers_guide.conf WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - ) + )]] -set_property(TARGET doc doc_usersguide doc_developersguide PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Documentation") +set_property(TARGET doc #[[doc_usersguide doc_developersguide]] PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Documentation") diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox index 28d65a2336..a85370db75 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginManualsList.dox @@ -1,73 +1,71 @@ /** \page PluginListPage MITK Plugin Manuals The plugins and bundles provide much of the extended functionality of MITK. Each encapsulates a solution to a problem and associated features. This way one can easily assemble the necessary capabilites for a workflow without adding a lot of bloat, by combining plugins as needed. \subpage PluginListGeneralPage
  • \ref org_mitk_views_basicimageprocessing
  • \ref org_mitk_views_datamanager
  • \ref org_mitk_editors_dicombrowser
  • \ref org_mitk_views_dicominspector
  • \ref org_mitk_views_imagecropper
  • \ref org_mitk_views_imagenavigator
  • \ref org_blueberry_views_logview
  • \ref org_mitk_views_matchpoint_algorithm_browser
  • \ref org_mitk_views_matchpoint_algorithm_control
  • \ref org_mitk_views_matchpoint_evaluator
  • \ref org_mitk_views_matchpoint_framereg
  • \ref org_mitk_views_matchpoint_manipulator
  • \ref org_mitk_views_matchpoint_mapper
  • \ref org_mitk_views_matchpoint_visualizer
  • \ref org_mitk_views_measurement
  • \ref org_mitk_views_imagestatistics
  • \ref org_mitk_views_moviemaker
  • \ref org_mitk_views_multilabelsegmentation
  • \ref org_mitk_views_pointsetinteraction
  • \ref org_mitk_views_python
  • \ref org_mitk_views_remeshing
  • \ref org_mitk_views_screenshotmaker
  • \ref org_mitk_views_segmentation
  • \ref org_mitk_views_deformableclippingplane
  • \ref org_mitk_views_viewnavigatorview
  • \ref org_mitk_views_volumevisualization
  • \ref org_mitk_views_properties
\subpage PluginListSpecificPage
  • \ref org_mitk_gui_qt_flowapplication
  • \ref org_mitk_gui_qt_aicpregistration
  • \ref org_mitk_gui_qt_cest
  • \ref org_mitk_gui_qt_classificationsegmentation
  • \ref org_mitk_views_cmdlinemodules
  • \ref org_mitk_views_pharmacokinetics_concentration_mri
  • \ref org_mitk_views_pharmacokinetics_mri
  • \ref org_mitk_views_pharmacokinetics_pet
  • \ref org_mitk_gui_qt_examples
  • \ref org_mitk_gui_qt_geometrytools
  • \ref org_mitk_gui_qt_igtexample
  • \ref org_mitk_gui_qt_igttracking
  • \ref org_mitk_views_igttrackingsemiautomaticmeasurement
  • \ref org_mitk_views_fit_demo
  • \ref org_mitk_views_fit_genericfitting
  • \ref org_mitk_views_fit_inspector
  • \ref org_mitkexamplesopencv
  • \ref org_mitk_gui_qt_overlaymanager
  • \ref org_mitk_gui_qt_mitkphenotyping
  • \ref org_mitk_gui_qt_preprocessing_resampling
  • \ref org_mitk_views_pharmacokinetics_curvedescriptor
  • -
  • \ref org_mitk_views_photoacoustics_imageprocessing
  • \ref org_mitk_gui_qt_pharmacokinetics_simulation
  • -
  • \ref org_mitk_gui_qt_photoacoustics_spectralunmixing
  • \ref org_surfacematerialeditor
  • \ref org_toftutorial
  • \ref org_blueberry_ui_qt_objectinspector
  • \ref org_mitk_gui_qt_ultrasound
  • \ref org_mitk_gui_qt_xnat
*/ diff --git a/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox b/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox index 9f1a98ced2..a6e4f4d28f 100644 --- a/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox +++ b/Documentation/Doxygen/2-UserManual/MITKPluginSpecificManualsList.dox @@ -1,36 +1,34 @@ /** \page PluginListSpecificPage List of Application-specific Plugins \li \subpage org_mitk_gui_qt_aicpregistration \li \subpage org_mitk_gui_qt_cest \li \subpage org_mitk_gui_qt_classificationsegmentation \li \subpage org_mitk_gui_qt_flowapplication \li \subpage org_mitk_views_cmdlinemodules \li \subpage org_mitk_views_pharmacokinetics_concentration_mri \li \subpage org_mitk_views_pharmacokinetics_mri \li \subpage org_mitk_views_pharmacokinetics_pet \li \subpage org_mitk_views_pharmacokinetics_simulation \li \subpage org_mitk_gui_qt_examples \li \subpage org_mitk_gui_qt_geometrytools \li \subpage org_mitk_gui_qt_igtexample \li \subpage org_mitk_gui_qt_igttracking \li \subpage org_mitk_views_igttrackingsemiautomaticmeasurement \li \subpage org_mitk_views_imagestatistics \li \subpage org_mitk_views_fit_demo \li \subpage org_mitk_views_fit_genericfitting \li \subpage org_mitk_views_fit_inspector \li \subpage org_mitkexamplesopencv \li \subpage org_mitk_gui_qt_overlaymanager \li \subpage org_mitk_gui_qt_mitkphenotyping \li \subpage org_mitk_gui_qt_preprocessing_resampling \li \subpage org_mitk_views_pharmacokinetics_curvedescriptor - \li \subpage org_mitk_views_photoacoustics_imageprocessing \li \subpage org_mitk_gui_qt_pharmacokinetics_simulation - \li \subpage org_mitk_gui_qt_photoacoustics_spectralunmixing \li \subpage org_surfacematerialeditor \li \subpage org_blueberry_ui_qt_objectinspector \li \subpage org_toftutorial \li \subpage org_mitk_gui_qt_ultrasound \li \subpage org_mitk_gui_qt_xnat */ diff --git a/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox index b88bc16275..ca06401761 100644 --- a/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox @@ -1,18 +1,17 @@ /** \page MITKModuleManualsList List of Module Manuals \li \subpage AnnotationModulePage \li \subpage ChartModule \li \subpage IGTConcepts \li \subpage NavigationGeneralModulePage \li \subpage IGTTutorialOverview \li \subpage MitkOpenCL_Overview \li \subpage LegacyGLModule - \li \subpage PAModulePage \li \subpage mitkPython_Overview \li \subpage RESTModule \li \subpage GeneratingDeviceModulesPage \li \subpage USModulePage */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox index 9d0ec93913..26f23d216f 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/BuildInstructions.dox @@ -1,214 +1,214 @@ /** \page BuildInstructionsPage Build Instructions \tableofcontents \section BuildInstructions_Introduction Introduction The CMake-based build system of MITK supports a "superbuild" process, meaning that it will download, configure, and build all required third-party libraries (except Qt) automatically. These instructions will show you how to use the MITK superbuild. \note This page explains explicitly how to build MITK itself. If you want to create your own project based on MITK, the process described below is completely automated. Please see \ref HowToNewProject. For more advanced users, the last sections explains how to inject custom build libraries into the superbuild process. \section BuildInstructions_Prerequisites Prerequisites You need: -# Git (there are also numerous third-party graphical clients available). We recommend using Git, but see below for a way how to get the current source code without using it. -# CMake (version \minimumCMakeVersion or higher) - -# Qt 5.12 if you plan to develop Qt-based + -# Qt \minimumQt5Version if you plan to develop Qt-based applications -# If you are using macOS you need an XCode installation and the Command Line Tools as it provides the neccessary compilers and SDKs \section BuildInstructions_Qt A note about Qt As we do not provide Qt in the MITK superbuild you need to install Qt manually. The Qt Company provides online installers for all supported platforms. \section BuildInstructions_Get_Source Get a source tree Since MITK is under active development we recommend to use Git to check out the latest stable release from the homepage. If you decide to use the most current nightly release, make sure to get a stable tree: Check the MITK dashboard before checking out. If the build tree is not clean, you can specify an older revision for the checkout or get a stable tar ball from www.mitk.org. To clone MITK's current Git repository do: \code git clone https://phabricator.mitk.org/source/mitk.git MITK \endcode \section BuildInstructions_Build_With_CMake Build MITK with CMake Create a new directory for the superbuild binary tree, change to it and call CMake: In the shell (assuming your current directory is the same as the one where you issued the git clone command): \code mkdir MITK-superbuild cd MITK-superbuild ccmake ../MITK \endcode If you use Windows or prefer to use the CMake GUI, start the CMake GUI and enter the location of the source tree and binary tree, choose a suitable generator and configure the project. CMake will present you a couple of options, these are the most important ones: - CMAKE_PREFIX_PATH The path to your Qt installation, e.g., C:/Qt/5.12.9/msvc2017_64 or /home/user/Qt/5.12.9/gcc_64 - MITK_USE_BLUEBERRY Build the BlueBerry application framework - MITK_USE_Boost_LIBRARIES If you need binary Boost libraries, specify them here. - MITK_USE_OpenCV Build MITK code which depends on OpenCV (this will download and build OpenCV 2.4) - MITK_USE_Python3 Enables Python wrapping in MITK. This will also configure ITK, VTK, and OpenCV (if enabled) to build Python wrappers. - MITK_USE_Qt5 Build MITK code which depends on Qt 5 If you are satisfied with the configuration of your MITK superbuild, generate the project files with CMake by pressing "Generate". Linux and macOS users usually just enter "make" (optionally supplying the number threads to be used for a parallel build): \code make -j6 \endcode Windows users using Visual Studio can open the generated MITK-superbuild.sln solution file in the MITK-superbuild directory and start the build by building the BUILD_ALL project. \section BuildInstructions_Customize Customize your MITK superbuild The MITK superbuild configures MITK as well as all external libraries. The build directories of these libraries, and of MITK itself are located inside the MITK-superbuild directory. For example, the directory layout may look like: \code MITK-superbuild |- ep "external projects" |-bin |-lib |-include |-src |- MITK-build \endcode To change the configuration of the MITK build itself, choose the MITK-build directory as the binary directory in the CMake GUI (not the MITK-superbuild directory). After generating the project files, build the MITK project by either issuing "make" in the MITK-build directory (Linux, macOS), or by opening MITK-build/MITK.sln (Windows). You may also change the configuration of any project configured via the superbuild process. Make sure to also build the changed project and also the projects which depend on it. \section BuildInstructions_Running Running Applications On Linux, just execute the application you want to run. MITK executables are located in MITK-superbuild/MITK-build/bin On Windows, the PATH environment variable must contain the directories containing the third-party libraries. This is automatically done from Visual Studio. For running the applications directly use the generated batch files in the MITK-superbuild/MITK-build/bin. \section BuildInstructions_Documentation Documentation If you have the Doxygen documentation tool installed, you get a new project (Visual Studio) or "make" target named "doc". You can build this to generate the HTML documentation of MITK in the Documentation/Doxygen directory of your MITK-build binary tree or in the MITK_DOXYGEN_OUTPUT_DIR CMake variable (if specified). \section BuildInstructions_Extending Extend MITK on your own (using the application framework BlueBerry) Please see \ref NewPluginPage \section BuildInstructions_As_Toolkit Use MITK in your own project (as a toolkit) To use MITK in your external project, add the CMake command find_package(MITK REQUIRED) to your CMakeLists.txt and make use of the CMake macros mitk_create_module() and mitk_create_executable() provided by MITK. Here is a very basic example CMakeLists.txt including MITK as a project: \code cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(MyProject) find_package(MITK 2018.04.02 REQUIRED) add_executable(MyApp main.cpp) target_link_libraries(MyApp MitkCore) \endcode with the main.ccp being \code #include #include int main() { MITK_INFO << "Hello world!"; return 0; } \endcode \section BuildInstructions_Advanced_Customization Superbuild customization You can inject pre-build third-party libraries into the MITK superbuild by setting certain CMake variables before the first configure step. MITK will then use these third-party libraries instead of downloading and building them by itself. Note that you must take care of configuring those libraries with all options MITK requires. The variables listed below are provided for injecting third-party libraries. Their occurrence in the CMake GUI or in ccmake may depend on specific MITK_USE_* options set to ON. You may also use the variable names below without the EXTERNAL_ prefix, for example when providing their values on a command line call to CMake. - EXTERNAL_BOOST_ROOT Set this variable to your custom Boost installation - EXTERNAL_CTK_DIR Set this variable to your CTK binary tree (the directory containing the CTKConfig.cmake file) - EXTERNAL_CableSwig_DIR Set this variable to your CableSwig binary tree for Python wrapping (the directory containing the CableSwigConfig.cmake file) - EXTERNAL_DCMTK_DIR Set this variable to your DCMTK binary tree (the directory containing the DCMTKConfig.cmake file) - EXTERNAL_GDCM_DIR Set this variable to your GDCM binary tree (the directory containing the GDCMConfig.cmake file) - EXTERNAL_ITK_DIR Set this variable to your ITK binary tree (the directory containing the ITKConfig.cmake file) - EXTERNAL_OpenCV_DIR Set this variable to your OpenCV binary tree (the directory containing the OpenCVConfig.cmake file) - EXTERNAL_VTK_DIR Set this variable to your VTK binary tree (the directory containing the VTKConfig.cmake file) To set CMake options before the first configure step is invoked, supply them on the command line, i.e. \code ccmake -DITK_DIR:PATH=/opt/ITK-release ../MITK \endcode */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox index 5babea66ab..2b93804d69 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Starting/SettingUpMITK/ThirdPartyLibs.dox @@ -1,107 +1,107 @@ /** \page thirdpartylibs Third-party libraries The following third-party libraries can be used with MITK by default and can, in part, be automatically downloaded during superbuild. \par ANN https://www.cs.umd.edu/~mount/ANN/ \par Boost https://www.boost.org/ \par C++ REST SDK https://github.com/Microsoft/cpprestsdk/ \par CppUnit https://sourceforge.net/projects/cppunit/ \par CTK https://commontk.org/ \par DCMTK https://dicom.offis.de/dcmtk \par Eigen http://eigen.tuxfamily.org/index.php?title=Main_Page \par GDCM https://gdcm.sourceforge.net/ \par HDF5 https://support.hdfgroup.org/HDF5/ \par ITK https://itk.org/ \par MatchPoint https://www.dkfz.de/en/sidt/projects/MatchPoint/info.html \par OpenCL https://www.khronos.org/opencl/ \par OpenCV https://opencv.org/ \par OpenIGTLink http://openigtlink.org/ \par OpenMesh https://www.openmesh.org/ \par PCRE https://www.pcre.org/ \par POCO https://pocoproject.org/ \par Python https://www.python.org/ \par Qt https://www.qt.io/ \par Qwt http://qwt.sourceforge.net/ \par SWIG http://www.swig.org/ -\par tinyxml +\par TinyXML-2 -http://www.grinninglizard.com/tinyxml/ +http://www.grinninglizard.com/tinyxml2/ \par VIGRA https://ukoethe.github.io/vigra/ \par VTK https://vtk.org/ \par zlib https://zlib.net/ For copyright information on any of the above toolkits see the corresponding home page or the corresponding source folder. */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index ee981d8a3a..1891d949b6 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,36 +1,35 @@ /** \page MITKModuleManualsListPage MITK Module Manuals Overview The modules are shared libraries that provide functionality that can be used by developers. \subpage MITKModuleManualsList List of Module Manuals
  • \ref AnnotationModulePage
  • \ref ChartModule
  • \ref IGTConcepts
  • \ref NavigationGeneralModulePage
  • \ref IGTTutorialOverview
  • \ref MitkOpenCL_Overview
  • \ref LegacyGLModule -
  • \ref PAModulePage
  • \ref mitkPython_Overview
  • \ref RESTModule
  • \ref GeneratingDeviceModulesPage
  • \ref USModulePage
\subpage MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules
  • \ref PlanarPropertiesPage
\subpage MITKMigrationGuides Migration Guides
  • \ref GeometryMigration
  • \ref InteractionMigration
  • \ref OverlayMigration
*/ diff --git a/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt b/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt index 24b2612a99..0f1dc85585 100644 --- a/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt +++ b/Examples/FirstSteps/NewModule/autoload/IO/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( NewModuleIO INCLUDE_DIRS PRIVATE src/IO DEPENDS PUBLIC MitkNewModule MitkSceneSerialization PACKAGE_DEPENDS - PRIVATE tinyxml + PRIVATE tinyxml2 AUTOLOAD_WITH MitkCore ) diff --git a/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt b/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt index 4b257e3d5c..1508687d56 100644 --- a/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt +++ b/Examples/FirstSteps/NewModule/cmdapps/CMakeLists.txt @@ -1,11 +1,10 @@ option(BUILD_NewModuleMiniApps "Build commandline tools for the example module" OFF) if(BUILD_NewModuleMiniApps) mitkFunctionCreateCommandLineApp( NAME ExampleToUpperCaseMiniApp DEPENDS MitkNewModule - PACKAGE_DEPENDS ITK - ) + ) endif() diff --git a/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt index 5b90620ad8..ee279d1db8 100644 --- a/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt +++ b/Examples/Plugins/org.mitk.example.gui.regiongrowing/CMakeLists.txt @@ -1,9 +1,8 @@ project(org_mitk_example_gui_regiongrowing) mitk_create_plugin( EXPORT_DIRECTIVE REGIONGROWING_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkQtWidgetsExt - PACKAGE_DEPENDS ITK|ITKRegionGrowing NO_INSTALL ) diff --git a/Examples/Tutorial/Step6/CMakeLists.txt b/Examples/Tutorial/Step6/CMakeLists.txt index 14f5b14c0f..8fb1bbb466 100644 --- a/Examples/Tutorial/Step6/CMakeLists.txt +++ b/Examples/Tutorial/Step6/CMakeLists.txt @@ -1,5 +1,3 @@ mitk_create_executable( DEPENDS MitkQtWidgetsExt - PACKAGE_DEPENDS ITK|ITKCurvatureFlow+ITKRegionGrowing ) - diff --git a/Examples/Tutorial/Step7/CMakeLists.txt b/Examples/Tutorial/Step7/CMakeLists.txt index 0bb009bb25..13c7b070a6 100644 --- a/Examples/Tutorial/Step7/CMakeLists.txt +++ b/Examples/Tutorial/Step7/CMakeLists.txt @@ -1,6 +1,5 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../Step6) mitk_create_executable( DEPENDS MitkQtWidgetsExt - PACKAGE_DEPENDS ITK|ITKCurvatureFlow+ITKRegionGrowing - ) +) diff --git a/Examples/Tutorial/Step8/CMakeLists.txt b/Examples/Tutorial/Step8/CMakeLists.txt index c52a311f4b..a090d34d9e 100644 --- a/Examples/Tutorial/Step8/CMakeLists.txt +++ b/Examples/Tutorial/Step8/CMakeLists.txt @@ -1,9 +1,8 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../Step6 ${CMAKE_CURRENT_SOURCE_DIR}/../Step7 - ) +) mitk_create_executable( DEPENDS MitkQtWidgetsExt - PACKAGE_DEPENDS ITK|ITKCurvatureFlow+ITKRegionGrowing - ) +) diff --git a/MITKConfig.cmake.in b/MITKConfig.cmake.in index e638db3c1d..bedd4e6385 100644 --- a/MITKConfig.cmake.in +++ b/MITKConfig.cmake.in @@ -1,313 +1,313 @@ if(CMAKE_VERSION VERSION_LESS @MITK_CMAKE_MINIMUM_REQUIRED_VERSION@) message(FATAL_ERROR "MITK requires at least CMake Version @MITK_CMAKE_MINIMUM_REQUIRED_VERSION@") endif() # The MITK version number set(MITK_VERSION_MAJOR "@MITK_VERSION_MAJOR@") set(MITK_VERSION_MINOR "@MITK_VERSION_MINOR@") set(MITK_VERSION_PATCH "@MITK_VERSION_PATCH@") set(MITK_VERSION_STRING "@MITK_VERSION_STRING@") #----------------------------------------------------------------------------- # C++ language standard #----------------------------------------------------------------------------- set(MITK_CXX_STANDARD @MITK_CXX_STANDARD@) #----------------------------------------------------------------------------- # Include required CMake scripts #----------------------------------------------------------------------------- # Update the CMake module path set(MITK_CMAKE_MODULE_PATH "@MITK_SOURCE_DIR@/CMake") list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_MODULE_PATH}) # Standard CMake macros include(CMakeParseArguments) include(FeatureSummary) include(FindPackageHandleStandardArgs) include(GenerateExportHeader) # Include MITK macros include(MacroParseArguments) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckMitkCompatibility) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionUseModules) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroFindDependency) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) #----------------------------------------------------------------------------- # MITK flags and directories #----------------------------------------------------------------------------- # MITK compiler flags set(MITK_C_FLAGS "@MITK_C_FLAGS@") set(MTTK_C_FLAGS_DEBUG "@MITK_C_FLAGS_DEBUG@") set(MITK_C_FLAGS_RELEASE "@MITK_C_FLAGS_RELEASE@") set(MITK_CXX_FLAGS "@MITK_CXX_FLAGS@") set(MTTK_CXX_FLAGS_DEBUG "@MITK_CXX_FLAGS_DEBUG@") set(MITK_CXX_FLAGS_RELEASE "@MITK_CXX_FLAGS_RELEASE@") # MITK linker flags set(MITK_EXE_LINKER_FLAGS "@MITK_EXE_LINKER_FLAGS@") set(MITK_SHARED_LINKER_FLAGS "@MITK_SHARED_LINKER_FLAGS@") set(MITK_MODULE_LINKER_FLAGS "@MITK_MODULE_LINKER_FLAGS@") # MITK specific directories set(MITK_SOURCE_DIR "@MITK_SOURCE_DIR@") set(MITK_BINARY_DIR "@MITK_BINARY_DIR@") set(MITK_CMAKE_DIR "@MITK_CMAKE_DIR@") # MITK output directories set(MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY "@MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY@") set(MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY "@MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY@") set(MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY "@MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY@") #----------------------------------------------------------------------------- # Miscellaneous variables #----------------------------------------------------------------------------- # Internal version numbers, used for approximate compatibility checks # of a MITK development version (non-release). set(MITK_VERSION_PLUGIN_SYSTEM 2) # dropped legacy BlueBerry plug-in CMake support set(MITK_DATA_DIR "@MITK_DATA_DIR@") set(UTILITIES_DIR "@UTILITIES_DIR@") set(REGISTER_QFUNCTIONALITY_CPP_IN "@REGISTER_QFUNCTIONALITY_CPP_IN@") set(MITK_DOXYGEN_TAGFILE_NAME "@MITK_DOXYGEN_TAGFILE_NAME@") set(MITK_LEGACY_EXPORT_MACRO_NAME 1) set(DCMTK_CMAKE_DEBUG_POSTFIX @DCMTK_CMAKE_DEBUG_POSTFIX@) # Get the canonical name of the directory to avoid potential case mismatch, # e.g. in the drive letter on Windows. get_filename_component(CMAKE_CURRENT_LIST_DIR_REALPATH ${CMAKE_CURRENT_LIST_DIR} REALPATH) if(CMAKE_CURRENT_LIST_DIR_REALPATH STREQUAL MITK_BINARY_DIR) set(MITK_EXTERNAL_PROJECT_PREFIX @MITK_EXTERNAL_PROJECT_PREFIX@) endif() set(MITK_MODULES_PACKAGE_DEPENDS_DIR "@MITK_MODULES_PACKAGE_DEPENDS_DIR@") if(MODULES_PACKAGE_DEPENDS_DIRS) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) list(REMOVE_DUPLICATES MODULES_PACKAGE_DEPENDS_DIRS) else() set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) endif() #----------------------------------------------------------------------------- # External dependencies #----------------------------------------------------------------------------- list(APPEND CMAKE_PREFIX_PATH "@MITK_EXTERNAL_PROJECT_PREFIX@") # ----------------------------------------- # Qt variables and dependencies set(MITK_USE_Qt5 @MITK_USE_Qt5@) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION @MITK_QT5_MINIMUM_VERSION@) set(MITK_QT5_COMPONENTS @MITK_QT5_COMPONENTS@) mitkMacroFindDependency(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS}) endif() # ----------------------------------------- # Special Python variables set(MITK_USE_Python3 @MITK_USE_Python3@) if(MITK_USE_Python3) set(PYTHON_EXECUTABLE "@PYTHON_EXECUTABLE@" CACHE FILEPATH "") set(PYTHON_INCLUDE_DIR "@PYTHON_INCLUDE_DIR@" CACHE PATH "") set(PYTHON_LIBRARY "@PYTHON_LIBRARY@" CACHE FILEPATH "") set(PYTHON_INCLUDE_DIR2 "@PYTHON_INCLUDE_DIR2@" CACHE PATH "") mitkMacroFindDependency(Python3 COMPONENTS Interpreter Development NumPy) endif() # ----------------------------------------- # Special Boost variables set(MITK_USE_Boost_LIBRARIES @MITK_USE_Boost_LIBRARIES@) set(MITK_USE_SYSTEM_Boost @MITK_USE_SYSTEM_Boost@) set(BOOST_ROOT "@BOOST_ROOT@" CACHE PATH "") set(BOOST_LIBRARYDIR "@BOOST_LIBRARYDIR@" CACHE PATH "") -set(Boost_ADDITIONAL_VERSIONS 1.68 1.68.0) +set(Boost_ADDITIONAL_VERSIONS 1.74 1.74.0) # We need this later for a DCMTK workaround set(_dcmtk_dir_orig "@DCMTK_DIR@") # ----------------------------------------- # External dependencies from the superbuild # or injected from somewhere else via # _DIR variables. @MITK_CONFIG_EXTERNAL_PROJECTS@ # Ensure the MITK module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}) # ----------------------------------------- # Special handling for DCMTK 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() # ----------------------------------------- # Special handling for DCMQI 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() # ----------------------------------------- # Special handling for Boost if(MITK_USE_Boost) link_directories(${Boost_LIBRARY_DIRS}) endif() # ----------------------------------------- # Special handling for OpenIGTLink if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() # ----------------------------------------- # Internal project dependencies set(CppMicroServices_DIR "@CppMicroServices_DIR@") mitkMacroFindDependency(CppMicroServices) set(MITK_USE_BLUEBERRY @MITK_USE_BLUEBERRY@) if(MITK_USE_BLUEBERRY) set(MITK_PLUGIN_USE_FILE "@MITK_PLUGIN_USE_FILE@") if(MITK_PLUGIN_USE_FILE) if(EXISTS "${MITK_PLUGIN_USE_FILE}") include("${MITK_PLUGIN_USE_FILE}") endif() endif() set(MITK_PLUGIN_PROVISIONING_FILE "@MITK_EXTAPP_PROVISIONING_FILE@") set(MITK_PROVISIONING_FILES "${BLUEBERRY_PLUGIN_PROVISIONING_FILE}" "${MITK_PLUGIN_PROVISIONING_FILE}") endif() set(BLUEBERRY_USE_QT_HELP @BLUEBERRY_USE_QT_HELP@) if(BLUEBERRY_USE_QT_HELP AND DOXYGEN_VERSION VERSION_LESS "1.8.7") message("Setting BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(BLUEBERRY_USE_QT_HELP OFF) endif() set(BLUEBERRY_QTPLUGIN_PATH "@BLUEBERRY_QTPLUGIN_PATH@") set(QT_HELPGENERATOR_EXECUTABLE "@QT_HELPGENERATOR_EXECUTABLE@") set(QT_COLLECTIONGENERATOR_EXECUTABLE "@QT_COLLECTIONGENERATOR_EXECUTABLE@") set(QT_ASSISTANT_EXECUTABLE "@QT_ASSISTANT_EXECUTABLE@") set(QT_XMLPATTERNS_EXECUTABLE "@QT_XMLPATTERNS_EXECUTABLE@") #----------------------------------------------------------------------------- # MITK sub-project variables #----------------------------------------------------------------------------- # External SDK directories set(MITK_PMD_SDK_DIR @MITK_PMD_SDK_DIR@) # MITK ToF use variables set(MITK_TOF_PMDCAMCUBE_AVAILABLE @MITK_USE_TOF_PMDCAMCUBE@) if(MITK_TOF_PMDCAMCUBE_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDCAMCUBE "Enable support for PMD Cam Cube" @MITK_USE_TOF_PMDCAMCUBE@) mark_as_advanced(MITK_USE_TOF_PMDCAMCUBE) endif() set(MITK_TOF_PMDCAMBOARD_AVAILABLE @MITK_USE_TOF_PMDCAMBOARD@) if(MITK_TOF_PMDCAMBOARD_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDCAMBOARD "Enable support for PMD Cam Board" @MITK_USE_TOF_PMDCAMBOARD@) mark_as_advanced(MITK_USE_TOF_PMDCAMBOARD) endif() set(MITK_TOF_PMDO3_AVAILABLE @MITK_USE_TOF_PMDO3@) if(MITK_TOF_PMDO3_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_PMDO3 "Enable support for PMD =3" @MITK_USE_TOF_PMDO3@) mark_as_advanced(MITK_USE_TOF_PMDO3) endif() set(MITK_TOF_KINECT_AVAILABLE @MITK_USE_TOF_KINECT@) if(MITK_TOF_KINECT_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_KINECT "Enable support for Kinect" @MITK_USE_TOF_KINECT@) mark_as_advanced(MITK_USE_TOF_KINECT) endif() set(MITK_TOF_MESASR4000_AVAILABLE @MITK_USE_TOF_MESASR4000@) if(MITK_TOF_MESASR4000_AVAILABLE AND NOT ${PROJECT_NAME} STREQUAL "MITK") option(MITK_USE_TOF_MESASR4000 "Enable support for MESA SR4000" @MITK_USE_TOF_MESASR4000@) mark_as_advanced(MITK_USE_TOF_MESASR4000) endif() if(MITK_USE_IGT) #include("${MITK_DIR}/mitkIGTConfig.cmake") endif() #----------------------------------------------------------------------------- # Import MITK targets and set custom properties #----------------------------------------------------------------------------- if(NOT MITK_EXPORTS_FILE_INCLUDED) if(EXISTS "@MITK_EXPORTS_FILE@") set(MITK_EXPORTS_FILE_INCLUDED 1) include("@MITK_EXPORTS_FILE@") endif() endif() # Set properties on exported targets @MITK_EXPORTED_TARGET_PROPERTIES@ #----------------------------------------------------------------------------- # Install rules #----------------------------------------------------------------------------- # Install rules for ToF libraries loaded at runtime if(EXISTS "@MITK_BINARY_DIR@/mitkToFHardwareInstallRules.cmake") include("@MITK_BINARY_DIR@/mitkToFHardwareInstallRules.cmake") endif() diff --git a/Modules/AlgorithmsExt/CMakeLists.txt b/Modules/AlgorithmsExt/CMakeLists.txt index 4e593dfe19..9afd8aad97 100644 --- a/Modules/AlgorithmsExt/CMakeLists.txt +++ b/Modules/AlgorithmsExt/CMakeLists.txt @@ -1,16 +1,12 @@ mitk_create_module( DEPENDS MitkDataTypesExt MitkLegacyGL PACKAGE_DEPENDS - PUBLIC ITK|ITKThresholding - PRIVATE ANN ITK|ITKIOImageBase VTK|ImagingGeneral + PUBLIC OpenMP + PRIVATE ANN VTK|ImagingGeneral ) if(TARGET ${MODULE_TARGET}) - if(MITK_USE_OpenMP) - target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) - endif() - if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/BasicImageProcessing/CMakeLists.txt b/Modules/BasicImageProcessing/CMakeLists.txt index b4e12f4b38..f529ea8639 100644 --- a/Modules/BasicImageProcessing/CMakeLists.txt +++ b/Modules/BasicImageProcessing/CMakeLists.txt @@ -1,8 +1,6 @@ -MITK_CREATE_MODULE( +mitk_create_module( DEPENDS MitkCore MitkMatchPointRegistration - PACKAGE_DEPENDS - PUBLIC - PRIVATE ITK|ITKIOImageBase+ITKIOGDCM + TARGET_DEPENDS PRIVATE IsotropicWavelets ) add_subdirectory(MiniApps) diff --git a/Modules/Biophotonics/CMakeLists.txt b/Modules/Biophotonics/CMakeLists.txt deleted file mode 100644 index f45b05b564..0000000000 --- a/Modules/Biophotonics/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -MITK_CREATE_MODULE(mitkBiophotonics -) -if( MITK_USE_Python3 ) - ADD_SUBDIRECTORY(python) -endif() diff --git a/Modules/Biophotonics/python/iMC/mc/__init__.py b/Modules/Biophotonics/python/iMC/mc/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/mc/batches.py b/Modules/Biophotonics/python/iMC/mc/batches.py deleted file mode 100644 index 2706262dc6..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/batches.py +++ /dev/null @@ -1,375 +0,0 @@ -''' -Created on Oct 15, 2015 - -@author: wirkert -''' - -import numpy as np -from pandas import DataFrame -import pandas as pd - - -class AbstractBatch(object): - """summarizes a batch of simulated mc spectra""" - - def __init__(self): - self._nr_layers = 0 # internally keeps track of number of layers - my_index = pd.MultiIndex(levels=[[], []], - labels=[[], []]) - self.df = DataFrame(columns=my_index) - - def create_parameters(self, nr_samples): - """create the parameters for the batch, the simulation has - to create the resulting reflectances""" - pass - - def nr_elements(self): - return self.df.shape[0] - - -class GenericBatch(AbstractBatch): - """generic n-layer batch with each layer having the same oxygenation """ - - def __init__(self): - super(GenericBatch, self).__init__() - - def append_one_layer(self, saO2, nr_samples): - """helper function to create parameters for one layer""" - - # scales data to lie between maxi and mini instead of 0 and 1 - scale = lambda x, mini, maxi: x * (maxi - mini) + mini - # shortcut to random generator - gen = np.random.random_sample - gen_n = np.random.normal - - # create layer elements - self.df["layer" + str(self._nr_layers), "vhb"] = \ - scale(gen(nr_samples), 0, 1.) - self.df["layer" + str(self._nr_layers), "sao2"] = \ - saO2 - self.df["layer" + str(self._nr_layers), "a_mie"] = \ - np.clip(gen_n(loc=18.9, scale=10.2, size=nr_samples), - 0.1, np.inf) * 100 # to 1/m - self.df["layer" + str(self._nr_layers), "b_mie"] = \ - np.clip(gen_n(loc=1.286, scale=0.521, size=nr_samples), 0, np.inf) - self.df["layer" + str(self._nr_layers), "d"] = \ - scale(gen(nr_samples), 0, 1.) - self.df["layer" + str(self._nr_layers), "n"] = \ - scale(gen(nr_samples), 1.33, 1.54) - self.df["layer" + str(self._nr_layers), "g"] = \ - scale(gen(nr_samples), 0.8, 0.95) - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - """Create generic three layer batch with a total diameter of 2mm. - saO2 is the same in all layers, but all other parameters vary randomly - within each layer""" - saO2 = np.random.random_sample(size=nr_samples) - - # create three layers with random samples - self.append_one_layer(saO2, nr_samples) - self.append_one_layer(saO2, nr_samples) - self.append_one_layer(saO2, nr_samples) - - # "normalize" d to 2mm - # first extract all layers from df - self.df - - layers = [l for l in self.df.columns.levels[0] if "layer" in l] - # summarize all ds - sum_d = 0 - for l in layers: - sum_d += self.df[l, "d"] - for l in layers: - self.df[l, "d"] = self.df[l, "d"] / sum_d * 2000. * 10 ** -6 - self.df[l, "d"] = np.clip(self.df[l, "d"], 25 * 10 ** -6, np.inf) - - return self.df - - -class GenericBatch(AbstractBatch): - """generic n-layer batch with each layer having the same oxygenation """ - - def __init__(self): - super(GenericBatch, self).__init__() - - def append_one_layer(self, saO2, nr_samples): - """helper function to create parameters for one layer""" - - # scales data to lie between maxi and mini instead of 0 and 1 - scale = lambda x, mini, maxi: x * (maxi - mini) + mini - # shortcut to random generator - gen = np.random.random_sample - gen_n = np.random.normal - - # create layer elements - self.df["layer" + str(self._nr_layers), "vhb"] = \ - scale(gen(nr_samples), 0, 1.) - self.df["layer" + str(self._nr_layers), "sao2"] = \ - saO2 - self.df["layer" + str(self._nr_layers), "a_mie"] = \ - np.clip(gen_n(loc=18.9, scale=10.2, size=nr_samples), - 0.1, np.inf) * 100 # to 1/m - self.df["layer" + str(self._nr_layers), "b_mie"] = \ - np.clip(gen_n(loc=1.286, scale=0.521, size=nr_samples), 0, np.inf) - self.df["layer" + str(self._nr_layers), "d"] = \ - scale(gen(nr_samples), 0, 1.) - self.df["layer" + str(self._nr_layers), "n"] = \ - scale(gen(nr_samples), 1.33, 1.54) - self.df["layer" + str(self._nr_layers), "g"] = \ - scale(gen(nr_samples), 0.8, 0.95) - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - """Create generic three layer batch with a total diameter of 2mm. - saO2 is the same in all layers, but all other parameters vary randomly - within each layer""" - saO2 = np.random.random_sample(size=nr_samples) - - # create three layers with random samples - self.append_one_layer(saO2, nr_samples) - self.append_one_layer(saO2, nr_samples) - self.append_one_layer(saO2, nr_samples) - - # "normalize" d to 2mm - # first extract all layers from df - self.df - - layers = [l for l in self.df.columns.levels[0] if "layer" in l] - # summarize all ds - sum_d = 0 - for l in layers: - sum_d += self.df[l, "d"] - for l in layers: - self.df[l, "d"] = self.df[l, "d"] / sum_d * 2000. * 10 ** -6 - self.df[l, "d"] = np.clip(self.df[l, "d"], 25 * 10 ** -6, np.inf) - - return self.df - - -class LessGenericBatch(AbstractBatch): - """less generic three layer batch. This only varies blood volume fraction - w.r.t. the ColonMuscleBatch. Let's see if DA works in this case.""" - - def __init__(self): - super(LessGenericBatch, self).__init__() - - def append_one_layer(self, saO2, n, d_ranges, nr_samples): - """helper function to create parameters for one layer""" - - # scales data to lie between maxi and mini instead of 0 and 1 - scale = lambda x, mini, maxi: x * (maxi - mini) + mini - # shortcut to random generator - gen = np.random.random_sample - - # create as generic batch - super(LessGenericBatch, self).append_one_layer(saO2, nr_samples) - self._nr_layers -= 1 # we're not finished - - # but some changes in specific layer elements - # more specific layer thicknesses - self.df["layer" + str(self._nr_layers), "d"] = \ - scale(gen(nr_samples), d_ranges[0], d_ranges[1]) - # more specific n - self.df["layer" + str(self._nr_layers), "n"] = \ - n - - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - """Create generic three layer batch with a total diameter of 2mm. - saO2 is the same in all layers, but all other parameters vary randomly - within each layer""" - saO2 = np.random.random_sample(size=nr_samples) - n = np.ones_like(saO2) - # create three layers with random samples - # muscle - self.append_one_layer(saO2, n * 1.36, (600.*10 ** -6, 1010.*10 ** -6), - nr_samples) - # submucosa - self.append_one_layer(saO2, n * 1.36, (415.*10 ** -6, 847.*10 ** -6), - nr_samples) - # mucosa - self.append_one_layer(saO2, n * 1.38, (395.*10 ** -6, 603.*10 ** -6), - nr_samples) - - return self.df - - -class ColonMuscleBatch(GenericBatch): - """three layer batch simulating colonic tissue""" - - def __init__(self): - super(ColonMuscleBatch, self).__init__() - - def append_one_layer(self, saO2, n, d_ranges, nr_samples): - """helper function to create parameters for one layer""" - - # scales data to lie between maxi and mini instead of 0 and 1 - scale = lambda x, mini, maxi: x * (maxi - mini) + mini - # shortcut to random generator - gen = np.random.random_sample - - # create as generic batch - super(ColonMuscleBatch, self).append_one_layer(saO2, nr_samples) - self._nr_layers -= 1 # we're not finished - - # but some changes in specific layer elements - # less blood - self.df["layer" + str(self._nr_layers), "vhb"] = \ - scale(gen(nr_samples), 0, 0.1) - # more specific layer thicknesses - self.df["layer" + str(self._nr_layers), "d"] = \ - scale(gen(nr_samples), d_ranges[0], d_ranges[1]) - # more specific n - self.df["layer" + str(self._nr_layers), "n"] = \ - n - - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - """Create generic three layer batch with a total diameter of 2mm. - saO2 is the same in all layers, but all other parameters vary randomly - within each layer""" - saO2 = np.random.random_sample(size=nr_samples) - n = np.ones_like(saO2) - # create three layers with random samples - # muscle - self.append_one_layer(saO2, n * 1.36, (600.*10 ** -6, 1010.*10 ** -6), - nr_samples) - # submucosa - self.append_one_layer(saO2, n * 1.36, (415.*10 ** -6, 847.*10 ** -6), - nr_samples) - # mucosa - self.append_one_layer(saO2, n * 1.38, (395.*10 ** -6, 603.*10 ** -6), - nr_samples) - - return self.df - - -class GenericMeanScatteringBatch(GenericBatch): - """three layer batch simulating colonic tissue""" - - def __init__(self): - super(GenericMeanScatteringBatch, self).__init__() - - def append_one_layer(self, saO2, nr_samples): - """helper function to create parameters for one layer""" - - # create as generic batch - super(GenericMeanScatteringBatch, self).append_one_layer(saO2, - nr_samples) - self._nr_layers -= 1 # we're not finished - - # restrict exponential scattering to mean value for soft tissue. - self.df["layer" + str(self._nr_layers), "b_mie"] = 1.286 - - self._nr_layers += 1 - - -class ColonMuscleMeanScatteringBatch(ColonMuscleBatch): - """three layer batch simulating colonic tissue""" - - def __init__(self): - super(ColonMuscleMeanScatteringBatch, self).__init__() - - def append_one_layer(self, saO2, n, d_ranges, nr_samples): - """helper function to create parameters for one layer""" - - # create as generic batch - super(ColonMuscleMeanScatteringBatch, self).append_one_layer(saO2, - n, - d_ranges, - nr_samples) - self._nr_layers -= 1 # we're not finished - - # restrict exponential scattering to mean value for soft tissue. - self.df["layer" + str(self._nr_layers), "b_mie"] = 1.286 - - self._nr_layers += 1 - - -class VisualizationBatch(AbstractBatch): - """batch used for visualization of different spectra. Feel free to adapt - for your visualization purposes.""" - - def __init__(self): - super(VisualizationBatch, self).__init__() - - def append_one_layer(self, vhb, sao2, a_mie, b_mie, d, n, g, nr_samples): - """helper function to create parameters for one layer""" - - # create layer elements - self.df["layer" + str(self._nr_layers), "vhb"] = vhb - self.df["layer" + str(self._nr_layers), "sao2"] = sao2 - self.df["layer" + str(self._nr_layers), "a_mie"] = a_mie - self.df["layer" + str(self._nr_layers), "b_mie"] = b_mie - self.df["layer" + str(self._nr_layers), "d"] = d - self.df["layer" + str(self._nr_layers), "n"] = n - self.df["layer" + str(self._nr_layers), "g"] = g - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - # bvf = np.linspace(0.0, .1, nr_samples) - # saO2 = np.linspace(0., 1., nr_samples) - # d = np.linspace(175, 735, nr_samples) * 10 ** -6 - # a_mie = np.linspace(5., 30., nr_samples) * 100 - # a_ray = np.linspace(0., 60., nr_samples) * 100 - # n = np.linspace(1.33, 1.54, nr_samples) - # g = np.linspace(0, 0.95, nr_samples) - # create three layers with random samples - self.append_one_layer([0.1, 0.02], [0.7, 0.1], 18.9*100., 1.286, - 500 * 10 ** -6, 1.38, 0.9, - nr_samples) - self.append_one_layer(0.04, 0.7, 18.9*100., 1.286, 500 * 10 ** -6, - 1.36, 0.9, - nr_samples) - self.append_one_layer(0.04, 0.7, 18.9*100., 1.286, 500 * 10 ** -6, - 1.36, 0.9, - nr_samples) - - return self.df - - -class IntralipidPhantomBatch(AbstractBatch): - """batch used for visualization of different spectra. Feel free to adapt - for your visualization purposes.""" - - def __init__(self): - super(IntralipidPhantomBatch, self).__init__() - - def append_one_layer(self, nr_samples): - """helper function to create parameters for one layer""" - - # scales data to lie between maxi and mini instead of 0 and 1 - scale = lambda x, mini, maxi: x * (maxi - mini) + mini - # shortcut to random generator - gen = np.random.random_sample - - # create layer elements - self.df["layer" + str(self._nr_layers), "vhb"] = \ - scale(gen(nr_samples), 0.001, 0.1) - self.df["layer" + str(self._nr_layers), "sao2"] = \ - scale(gen(nr_samples), 0., 1.) - self.df["layer" + str(self._nr_layers), "a_mie"] = \ - scale(gen(nr_samples), 5., 40.) * 100 # to 1/m - self.df["layer" + str(self._nr_layers), "b_mie"] = \ - scale(gen(nr_samples), 2.3, 2.4) - self.df["layer" + str(self._nr_layers), "d"] = \ - 2000.*10**-6 - self.df["layer" + str(self._nr_layers), "n"] = \ - scale(gen(nr_samples), 1.33, 1.54) - self.df["layer" + str(self._nr_layers), "g"] = \ - scale(gen(nr_samples), 0.8, 0.95) - self._nr_layers += 1 - - def create_parameters(self, nr_samples): - """Create intralipid batch with a total diameter of 2mm. - all other parameters vary randomly - within each layer to simulate the interlipid scattering/absorption - properties.""" - - # create three layers with random samples - self.append_one_layer(nr_samples) - - return self.df diff --git a/Modules/Biophotonics/python/iMC/mc/create_spectrum.py b/Modules/Biophotonics/python/iMC/mc/create_spectrum.py deleted file mode 100644 index 8d42ea197c..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/create_spectrum.py +++ /dev/null @@ -1,41 +0,0 @@ - -import logging -import time -import os - -from mc.sim import get_diffuse_reflectance - - -def create_spectrum(tissue_model, sim_wrapper, wavelengths): - """ - Create a whole spectrum from one instance (dataframe_row) using our - tissue model at wavelength wavelength. - - Args: - tissue_model: the model which should be used to generate the - spectrum - sim_wrapper: the simulation which should be used to generate the - reflectances - wavelengths: the wavelengths which shall be simulated - - Returns: the simulated reflectances - """ - start = time.time() - # map the _wavelengths array to reflectance list - - def wavelength_to_reflectance(wavelength): - # helper function to determine the reflectance for a given - # wavelength using the current model and simulation - tissue_model.set_wavelength(wavelength) - tissue_model.create_mci_file() - sim_wrapper.run_simulation() - simulation_path = os.path.split(sim_wrapper.mcml_executable)[0] - return get_diffuse_reflectance(os.path.join(simulation_path, - tissue_model. - get_mco_filename())) - reflectances = map(wavelength_to_reflectance, wavelengths) - end = time.time() - # success! - logging.info("successfully ran simulation in " + - "{:.2f}".format(end - start) + " seconds") - return reflectances diff --git a/Modules/Biophotonics/python/iMC/mc/data/beta_carotin.txt b/Modules/Biophotonics/python/iMC/mc/data/beta_carotin.txt deleted file mode 100644 index 902019d56c..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/data/beta_carotin.txt +++ /dev/null @@ -1,1924 +0,0 @@ -lambda beta carotin -##Wavelength (nm) Molar Extinction (cm-1/M) -219.74 860669 -219.99 866939 -220.24 873996 -220.49 887103 -220.74 901200 -220.99 914068 -221.24 931102 -221.49 952261 -221.74 984397 -221.99 1006831 -222.24 1032652 -222.49 1061135 -222.74 1081015 -222.99 1093144 -223.24 1101278 -223.49 1095590 -223.74 1087870 -223.99 1078610 -224.24 1055667 -224.49 1019649 -224.74 984279 -224.99 942523 -225.24 897948 -225.49 847468 -225.74 802920 -225.99 750521 -226.24 704257 -226.49 657528 -226.74 612102 -226.99 568332 -227.24 522203 -227.49 483550 -227.74 445839 -227.99 410272 -228.24 376479 -228.49 346892 -228.74 317864 -228.99 291931 -229.24 267330 -229.49 244432 -229.74 224462 -229.99 206460 -230.24 189372 -230.49 174797 -230.74 162312 -230.99 149431 -231.24 139576 -231.49 129411 -231.74 119268 -231.99 111778 -232.24 104297 -232.49 97028 -232.74 91749 -232.99 85840 -233.24 82466 -233.49 78359 -233.74 74179 -233.99 71819 -234.24 68531 -234.49 65721 -234.74 62361 -234.99 60073 -235.24 57992 -235.49 56889 -235.74 54353 -235.99 52961 -236.24 51795 -236.49 51443 -236.74 49052 -236.99 49363 -237.24 49200 -237.49 48552 -237.74 47755 -237.99 47755 -238.24 47872 -238.49 46494 -238.74 45877 -238.99 45503 -239.24 46845 -239.49 45570 -239.74 46489 -239.99 45822 -240.24 45151 -240.49 45629 -240.74 45232 -240.99 45426 -241.24 44949 -241.49 45723 -241.74 45863 -241.99 44908 -242.24 45165 -242.49 45219 -242.74 44710 -242.99 45597 -243.24 44814 -243.49 45192 -243.74 45250 -243.99 44863 -244.24 44926 -244.49 44841 -244.74 44660 -244.99 44359 -245.24 44796 -245.49 44260 -245.74 45746 -245.99 45404 -246.24 45917 -246.49 45759 -246.74 46012 -246.99 45386 -247.24 45372 -247.49 46291 -247.74 45656 -247.99 46417 -248.24 46989 -248.49 46750 -248.74 47615 -248.99 48034 -249.24 48313 -249.49 48295 -249.74 48777 -249.99 49601 -250.24 49817 -250.49 50290 -250.74 50169 -250.99 49971 -251.24 51047 -251.49 51475 -251.74 52313 -251.99 52551 -252.24 52416 -252.49 54020 -252.74 54168 -252.99 53988 -253.24 53583 -253.49 55038 -253.74 55213 -253.99 55308 -254.24 55155 -254.49 56299 -254.74 56546 -254.99 56470 -255.24 56546 -255.49 56929 -255.74 56641 -255.99 57726 -256.24 58510 -256.49 58433 -256.74 58609 -256.99 58830 -257.24 59411 -257.49 60199 -257.74 59785 -257.99 61920 -258.24 62595 -258.49 63109 -258.74 64541 -258.99 63901 -259.24 64662 -259.49 65284 -259.74 66779 -259.99 66365 -260.24 67946 -260.49 67734 -260.74 69689 -260.99 70594 -261.24 71004 -261.49 72387 -261.74 74004 -261.99 75368 -262.24 75283 -262.49 75864 -262.74 75738 -262.99 77503 -263.24 76265 -263.49 77116 -263.74 77976 -263.99 78476 -264.24 78827 -264.49 79215 -264.74 79841 -264.99 79246 -265.24 79341 -265.49 78886 -265.74 79652 -265.99 80958 -266.24 80696 -266.49 82030 -266.74 82214 -266.99 82201 -267.24 83273 -267.49 84101 -267.74 84790 -267.99 86502 -268.24 87196 -268.49 87479 -268.74 88029 -268.99 89853 -269.24 89641 -269.49 90925 -269.74 93334 -269.99 93983 -270.24 94415 -270.49 95136 -270.74 95951 -270.99 97046 -271.24 98482 -271.49 99924 -271.74 101248 -271.99 101460 -272.24 102617 -272.49 104198 -272.74 104572 -272.99 103621 -273.24 104112 -273.49 103928 -273.74 103185 -273.99 102324 -274.24 103414 -274.49 102270 -274.74 100802 -274.99 100099 -275.24 98856 -275.49 97528 -275.74 98050 -275.99 96253 -276.24 96469 -276.49 97104 -276.74 97212 -276.99 97663 -277.24 98329 -277.49 98235 -277.74 98523 -277.99 98942 -278.24 100099 -278.49 99757 -278.74 101550 -278.99 101649 -279.24 100933 -279.49 102689 -279.74 102865 -279.99 102743 -280.24 103266 -280.49 104220 -280.74 104018 -280.99 103748 -281.24 104797 -281.49 105247 -281.74 105878 -281.99 105954 -282.24 107324 -282.49 108333 -282.74 109679 -282.99 110400 -283.24 111179 -283.49 111332 -283.74 111499 -283.99 110323 -284.24 108968 -284.49 108432 -284.74 106148 -284.99 104653 -285.24 102905 -285.49 99717 -285.74 97735 -285.99 95681 -286.24 92771 -286.49 90096 -286.74 88344 -286.99 85795 -287.24 83975 -287.49 83147 -287.74 80728 -287.99 79206 -288.24 79071 -288.49 78386 -288.74 77503 -288.99 78206 -289.24 77125 -289.49 78053 -289.74 76715 -289.99 77215 -290.24 77035 -290.49 77913 -290.74 77071 -290.99 77715 -291.24 76454 -291.49 76783 -291.74 74440 -291.99 75175 -292.24 73260 -292.49 72198 -292.74 71828 -292.99 71576 -293.24 71725 -293.49 71535 -293.74 70918 -293.99 70319 -294.24 70306 -294.49 71035 -294.74 70603 -294.99 70896 -295.24 70797 -295.49 70783 -295.74 69067 -295.99 67986 -296.24 66658 -296.49 64874 -296.74 62600 -296.99 61176 -297.24 59316 -297.49 56191 -297.74 53763 -297.99 50912 -298.24 48412 -298.49 44381 -298.74 41994 -298.99 39296 -299.24 36734 -299.49 34342 -299.74 32923 -299.99 31887 -300.24 30667 -300.49 29343 -300.74 27352 -300.99 28383 -301.24 26834 -301.49 25902 -301.74 24852 -301.99 23951 -302.24 23591 -302.49 22627 -302.74 22717 -302.99 22136 -303.24 21889 -303.49 22100 -303.74 22961 -303.99 21911 -304.24 20664 -304.49 20551 -304.74 20934 -304.99 19150 -305.24 20736 -305.49 19983 -305.74 21087 -305.99 20245 -306.24 18448 -306.49 18254 -306.74 17547 -306.99 16808 -307.24 16777 -307.49 16434 -307.74 16232 -307.99 17605 -308.24 16551 -308.49 17214 -308.74 16664 -308.99 16218 -309.24 16601 -309.49 16939 -309.74 16205 -309.99 19488 -310.24 16412 -310.49 17713 -310.74 18520 -310.99 12223 -311.24 14417 -311.49 16669 -311.74 18119 -311.99 15633 -312.24 15871 -312.49 14016 -312.74 15961 -312.99 15457 -313.24 13570 -313.49 16808 -313.74 15669 -313.99 14421 -314.24 16033 -314.49 14642 -314.74 16385 -314.99 13471 -315.24 14871 -315.49 17218 -315.74 15943 -315.99 17722 -316.24 13056 -316.49 16376 -316.74 14218 -316.99 13444 -317.24 15043 -317.49 14808 -317.74 12493 -317.99 14142 -318.24 13034 -318.49 11939 -318.74 13980 -318.99 15398 -319.24 12804 -319.49 14115 -319.74 14277 -319.99 15561 -320.24 16313 -320.49 14525 -320.74 13642 -320.99 11989 -321.24 13939 -321.49 14367 -321.74 14759 -321.99 12133 -322.24 13624 -322.49 14430 -322.74 8715 -322.99 14687 -323.24 13741 -323.49 11989 -323.74 10408 -323.99 12457 -324.24 13241 -324.49 12881 -324.74 12376 -324.99 13309 -325.24 14390 -325.49 12120 -325.74 13155 -325.99 12120 -326.24 13552 -326.49 12597 -326.74 13300 -326.99 11822 -327.24 16074 -327.49 14097 -327.74 13498 -327.99 12624 -328.24 14426 -328.49 12291 -328.74 11822 -328.99 13106 -329.24 13863 -329.49 13056 -329.74 11061 -329.99 14421 -330.24 14417 -330.49 13083 -330.74 15079 -330.99 13691 -331.24 12201 -331.49 15858 -331.74 14128 -331.99 14903 -332.24 14727 -332.49 12435 -332.74 13052 -332.99 14660 -333.24 15223 -333.49 13520 -333.74 12002 -333.99 13655 -334.24 14056 -334.49 13705 -334.74 12313 -334.99 14272 -335.24 14295 -335.49 16786 -335.74 14813 -335.99 13565 -336.24 15128 -336.49 14200 -336.74 14241 -336.99 13975 -337.24 12165 -337.49 12854 -337.74 16070 -337.99 12939 -338.24 14484 -338.49 14727 -338.74 16151 -338.99 16245 -339.24 14529 -339.49 15313 -339.74 15655 -339.99 13791 -340.24 13822 -340.49 16466 -340.74 14390 -340.99 15889 -341.24 13714 -341.49 12903 -341.74 11899 -341.99 13854 -342.24 11629 -342.49 13813 -342.74 14853 -342.99 15475 -343.24 13944 -343.49 13637 -343.74 14529 -343.99 14056 -344.24 14466 -344.49 14957 -344.74 14079 -344.99 13953 -345.24 16088 -345.49 14678 -345.74 12854 -345.99 14944 -346.24 13219 -346.49 16070 -346.74 14556 -346.99 15281 -347.24 13998 -347.49 15043 -347.74 15038 -347.99 15565 -348.24 14723 -348.49 15164 -348.74 13660 -348.99 14002 -349.24 14480 -349.49 15579 -349.74 14678 -349.99 15786 -350.24 15880 -350.49 16146 -350.74 14390 -350.99 15020 -351.24 15007 -351.49 15502 -351.74 14209 -351.99 16236 -352.24 16880 -352.49 14142 -352.74 14709 -352.99 15254 -353.24 14678 -353.49 16052 -353.74 15038 -353.99 13822 -354.24 15281 -354.49 14601 -354.74 14588 -354.99 16583 -355.24 15187 -355.49 16678 -355.74 15232 -355.99 15380 -356.24 15466 -356.49 17695 -356.74 15534 -356.99 17934 -357.24 17358 -357.49 16344 -357.74 15511 -357.99 15781 -358.24 17137 -358.49 16813 -358.74 16587 -358.99 15664 -359.24 16673 -359.49 14529 -359.74 15412 -359.99 15412 -360.24 15714 -360.49 16862 -360.74 15723 -360.99 17907 -361.24 16574 -361.49 17502 -361.74 17295 -361.99 16673 -362.24 17141 -362.49 17795 -362.74 16178 -362.99 17646 -363.24 18047 -363.49 17975 -363.74 17389 -363.99 16786 -364.24 16745 -364.49 18614 -364.74 17331 -364.99 17686 -365.24 19191 -365.49 18857 -365.74 17056 -365.99 19529 -366.24 20862 -366.49 18862 -366.74 19281 -366.99 19776 -367.24 20452 -367.49 19727 -367.74 19623 -367.99 18574 -368.24 21010 -368.49 19911 -368.74 20812 -368.99 20028 -369.24 22623 -369.49 22425 -369.74 21695 -369.99 21609 -370.24 21308 -370.49 22456 -370.74 21591 -370.99 21555 -371.24 22578 -371.49 22956 -371.74 23033 -371.99 23641 -372.24 24204 -372.49 24150 -372.74 24123 -372.99 25019 -373.24 23528 -373.49 23469 -373.74 25523 -373.99 25361 -374.24 24298 -374.49 25068 -374.74 25244 -374.99 26555 -375.24 26762 -375.49 25352 -375.74 26244 -375.99 26451 -376.24 26654 -376.49 27352 -376.74 26591 -376.99 27451 -377.24 27424 -377.49 28518 -377.74 27892 -377.99 28577 -378.24 28338 -378.49 29059 -378.74 29298 -378.99 29928 -379.24 29253 -379.49 30090 -379.74 29847 -379.99 29757 -380.24 32072 -380.49 30329 -380.74 29325 -380.99 32432 -381.24 30365 -381.49 30424 -381.74 32013 -381.99 31068 -382.24 32824 -382.49 32959 -382.74 34991 -382.99 31968 -383.24 33045 -383.49 33599 -383.74 34049 -383.99 34923 -384.24 33482 -384.49 34774 -384.74 36216 -384.99 35004 -385.24 36008 -385.49 35981 -385.74 36450 -385.99 35626 -386.24 36828 -386.49 36954 -386.74 38242 -386.99 37833 -387.24 37616 -387.49 38977 -387.74 38472 -387.99 38454 -388.24 39576 -388.49 38796 -388.74 40656 -388.99 40003 -389.24 40733 -389.49 40107 -389.74 42683 -389.99 41850 -390.24 42098 -390.49 40931 -390.74 42791 -390.99 43976 -391.24 44219 -391.49 44246 -391.74 45836 -391.99 45904 -392.24 44570 -392.49 46881 -392.74 47948 -392.99 46849 -393.24 47448 -393.49 48187 -393.74 48863 -393.99 50925 -394.24 50723 -394.49 50916 -394.74 49691 -394.99 50151 -395.24 51164 -395.49 52340 -395.74 52096 -395.99 51624 -396.24 54218 -396.49 53326 -396.74 53754 -396.99 55420 -397.24 55465 -397.49 54529 -397.74 55632 -397.99 56407 -398.24 57528 -398.49 57091 -398.74 56961 -398.99 59213 -399.24 58726 -399.49 59208 -399.74 59109 -399.99 58312 -400.24 60258 -400.49 60744 -400.74 60505 -400.99 61185 -401.24 62154 -401.49 61483 -401.74 61023 -401.99 62302 -402.24 61348 -402.49 61676 -402.74 62717 -402.99 62919 -403.24 62879 -403.49 64248 -403.74 63455 -403.99 63627 -404.24 65315 -404.49 64874 -404.74 65644 -404.99 66126 -405.24 65203 -405.49 66360 -405.74 65117 -405.99 66631 -406.24 66333 -406.49 67063 -406.74 68004 -406.99 68117 -407.24 68063 -407.49 68108 -407.74 68747 -407.99 68189 -408.24 71153 -408.49 69270 -408.74 70999 -408.99 70135 -409.24 71612 -409.49 72414 -409.74 73071 -409.99 73202 -410.24 73179 -410.49 73873 -410.74 74963 -410.99 75463 -411.24 75206 -411.49 75805 -411.74 76260 -411.99 76634 -412.24 78287 -412.49 77485 -412.74 78656 -412.99 78692 -413.24 80233 -413.49 79859 -413.74 81250 -413.99 80426 -414.24 82710 -414.49 83723 -414.74 83723 -414.99 82223 -415.24 83354 -415.49 83633 -415.74 85885 -415.99 86389 -416.24 86750 -416.49 88132 -416.74 88398 -416.99 88259 -417.24 90065 -417.49 89979 -417.74 90416 -417.99 91672 -418.24 92141 -418.49 93294 -418.74 92389 -418.99 94789 -419.24 94744 -419.49 95321 -419.74 96519 -419.99 97374 -420.24 97712 -420.49 97825 -420.74 98014 -420.99 99496 -421.24 99347 -421.49 99527 -421.74 99527 -421.99 100442 -422.24 100955 -422.49 101784 -422.74 102153 -422.99 103176 -423.24 103428 -423.49 103626 -423.74 103468 -423.99 103338 -424.24 103757 -424.49 104738 -424.74 105297 -424.99 105923 -425.24 105756 -425.49 105819 -425.74 106126 -425.99 106094 -426.24 106166 -426.49 105085 -426.74 105711 -426.99 105774 -427.24 106162 -427.49 107071 -427.74 107080 -427.99 106824 -428.24 107193 -428.49 106770 -428.74 108269 -428.99 107216 -429.24 107855 -429.49 107589 -429.74 107445 -429.99 106824 -430.24 107324 -430.49 107711 -430.74 109035 -430.99 107571 -431.24 108634 -431.49 108661 -431.74 107621 -431.99 109040 -432.24 108008 -432.49 108801 -432.74 109179 -432.99 109801 -433.24 109459 -433.49 109341 -433.74 110170 -433.99 110003 -434.24 110116 -434.49 109801 -434.74 111197 -434.99 111436 -435.24 110805 -435.49 112053 -435.74 111643 -435.99 113197 -436.24 112742 -436.49 113008 -436.74 115215 -436.99 114129 -437.24 113994 -437.49 115435 -437.74 116111 -437.99 116147 -438.24 116593 -438.49 117701 -438.74 118205 -438.99 117944 -439.24 118453 -439.49 119908 -439.74 119529 -439.99 120966 -440.24 120948 -440.49 121295 -440.74 122556 -440.99 123367 -441.24 124087 -441.49 124380 -441.74 125105 -441.99 126781 -442.24 124200 -442.49 126961 -442.74 127037 -442.99 127835 -443.24 128785 -443.49 127609 -443.74 129172 -443.99 130510 -444.24 130758 -444.49 130731 -444.74 131604 -444.99 132086 -445.24 132609 -445.49 132721 -445.74 132582 -445.99 135095 -446.24 135649 -446.49 133969 -446.74 134676 -446.99 135383 -447.24 136428 -447.49 135964 -447.74 136752 -447.99 136270 -448.24 137604 -448.49 138288 -448.74 137329 -448.99 136698 -449.24 137464 -449.49 139171 -449.74 139342 -449.99 138730 -450.24 138243 -450.49 139356 -450.74 138590 -450.99 139500 -451.24 137541 -451.49 138509 -451.74 138342 -451.99 137401 -452.24 137887 -452.49 137820 -452.74 136518 -452.99 137572 -453.24 136653 -453.49 136000 -453.74 135915 -453.99 135550 -454.24 135437 -454.49 133577 -454.74 134036 -454.99 133122 -455.24 134000 -455.49 132424 -455.74 133253 -455.99 130983 -456.24 131816 -456.49 131920 -456.74 129028 -456.99 129478 -457.24 129087 -457.49 129015 -457.74 126893 -457.99 126808 -458.24 125736 -458.49 125065 -458.74 125335 -458.99 124367 -459.24 123227 -459.49 122187 -459.74 121966 -459.99 121173 -460.24 119818 -460.49 119651 -460.74 119435 -460.99 118336 -461.24 118070 -461.49 116665 -461.74 116818 -461.99 116273 -462.24 114805 -462.49 114057 -462.74 113998 -462.99 113535 -463.24 113904 -463.49 112882 -463.74 111368 -463.99 112332 -464.24 111233 -464.49 111436 -464.74 109504 -464.99 110148 -465.24 110386 -465.49 109990 -465.74 109431 -465.99 110161 -466.24 110139 -466.49 108369 -466.74 108981 -466.99 107995 -467.24 107450 -467.49 107445 -467.74 107661 -467.99 108432 -468.24 107621 -468.49 108796 -468.74 107517 -468.99 107607 -469.24 108378 -469.49 107977 -469.74 108251 -469.99 108427 -470.24 108792 -470.49 108900 -470.74 108157 -470.99 109283 -471.24 109350 -471.49 109805 -471.74 109094 -471.99 109197 -472.24 109319 -472.49 109058 -472.74 109940 -472.99 110148 -473.24 110472 -473.49 110071 -473.74 111864 -473.99 111409 -474.24 110747 -474.49 111733 -474.74 111134 -474.99 112395 -475.24 112972 -475.49 112566 -475.74 112521 -475.99 111765 -476.24 111747 -476.49 111792 -476.74 112778 -476.99 110404 -477.24 112314 -477.49 112476 -477.74 113111 -477.99 112368 -478.24 111850 -478.49 110445 -478.74 111517 -478.99 110711 -479.24 110828 -479.49 110382 -479.74 109873 -479.99 110769 -480.24 110166 -480.49 108936 -480.74 108427 -480.99 108409 -481.24 108837 -481.49 107270 -481.74 105716 -481.99 106765 -482.24 105491 -482.49 104711 -482.74 103712 -482.99 104356 -483.24 103198 -483.49 102941 -483.74 101518 -483.99 100162 -484.24 99802 -484.49 98491 -484.74 98960 -484.99 96757 -485.24 96248 -485.49 95622 -485.74 94663 -485.99 95114 -486.24 93803 -486.49 91772 -486.74 91551 -486.99 89497 -487.24 89529 -487.49 85826 -487.74 86646 -487.99 85047 -488.24 85115 -488.49 83304 -488.74 81021 -488.99 80611 -489.24 80399 -489.49 79075 -489.74 77318 -489.99 76107 -490.24 74945 -490.49 74323 -490.74 72553 -490.99 70999 -491.24 71265 -491.49 70590 -491.74 68027 -491.99 66887 -492.24 65180 -492.49 64514 -492.74 63618 -492.99 62996 -493.24 59983 -493.49 59379 -493.74 57789 -493.99 58560 -494.24 55605 -494.49 55024 -494.74 54200 -494.99 52736 -495.24 52376 -495.49 50371 -495.74 50218 -495.99 49926 -496.24 48696 -496.49 47142 -496.74 46525 -496.99 45332 -497.24 44390 -497.49 42030 -497.74 41454 -497.99 40458 -498.24 41260 -498.49 37598 -498.74 37044 -498.99 36337 -499.24 35968 -499.49 34621 -499.74 33729 -499.99 32662 -500.24 32135 -500.49 32657 -500.74 30180 -500.99 29933 -501.24 28100 -501.49 27982 -501.74 27437 -501.99 26257 -502.24 24960 -502.49 25203 -502.74 24942 -502.99 24686 -503.24 23118 -503.49 22375 -503.74 21353 -503.99 20673 -504.24 19871 -504.49 20407 -504.74 18155 -504.99 19186 -505.24 19596 -505.49 17912 -505.74 16619 -505.99 16867 -506.24 16880 -506.49 15628 -506.74 15205 -506.99 15434 -507.24 14736 -507.49 13628 -507.74 13016 -507.99 13286 -508.24 13223 -508.49 13417 -508.74 12363 -508.99 11259 -509.24 11800 -509.49 10606 -509.74 9760 -509.99 10985 -510.24 10440 -510.49 9751 -510.74 10277 -510.99 9890 -511.24 9287 -511.49 9683 -511.74 8845 -511.99 8039 -512.24 7296 -512.49 7192 -512.74 7215 -512.99 7994 -513.24 7449 -513.49 6850 -513.74 7003 -513.99 7147 -514.24 6652 -514.49 7490 -514.74 6341 -514.99 6539 -515.24 5129 -515.49 5084 -515.74 4206 -515.99 4963 -516.24 4859 -516.49 5557 -516.74 5490 -516.99 4585 -517.24 4828 -517.49 4278 -517.74 4301 -517.99 4350 -518.24 5098 -518.49 4562 -518.74 4062 -518.99 4589 -519.24 3778 -519.49 3220 -519.74 3639 -519.99 3386 -520.24 3319 -520.49 2850 -520.74 3823 -520.99 4305 -521.24 3666 -521.49 3400 -521.74 1900 -521.99 4188 -522.24 2418 -522.49 3350 -522.74 2116 -522.99 2670 -523.24 3585 -523.49 2535 -523.74 3355 -523.99 1621 -524.24 2661 -524.49 2306 -524.74 2441 -524.99 2026 -525.24 1990 -525.49 2706 -525.74 2319 -525.99 1806 -526.24 2026 -526.49 3058 -526.74 2233 -526.99 319 -527.24 1873 -527.49 2814 -527.74 2837 -527.99 1999 -528.24 1612 -528.49 2143 -528.74 1977 -528.99 3026 -529.24 1549 -529.49 1180 -529.74 1508 -529.99 2229 -530.24 2040 -530.49 824 -530.74 1607 -530.99 1562 -531.24 2260 -531.49 1157 -531.74 1193 -531.99 1810 -532.24 675 -532.49 1837 -532.74 801 -532.99 1801 -533.24 2405 -533.49 963 -533.74 743 -533.99 540 -534.24 1688 -534.49 1288 -534.74 1806 -534.99 454 -535.24 2053 -535.49 1603 -535.74 1896 -535.99 1184 -536.24 -67 -536.49 1423 -536.74 1697 -536.99 986 -537.24 653 -537.49 247 -537.74 157 -537.99 -405 -538.24 1022 -538.49 797 -538.74 1495 -538.99 2062 -539.24 999 -539.49 1634 -539.74 -229 -539.99 2143 -540.24 571 -540.49 1797 -540.74 1274 -540.99 909 -541.24 1355 -541.49 1391 -541.74 1567 -541.99 1157 -542.24 855 -542.49 571 -542.74 810 -542.99 1229 -543.24 1130 -543.49 1035 -543.74 1198 -543.99 571 -544.24 1279 -544.49 319 -544.74 1283 -544.99 702 -545.24 774 -545.49 0 -545.74 1265 -545.99 963 -546.24 -297 -546.49 819 -546.74 427 -546.99 1923 -547.24 495 -547.49 1238 -547.74 405 -547.99 1292 -548.24 882 -548.49 657 -548.74 567 -548.99 900 -549.24 1851 -549.49 1202 -549.74 1373 -549.99 1369 -550.24 1756 -550.49 1153 -550.74 851 -550.99 1675 -551.24 729 -551.49 1279 -551.74 806 -551.99 -495 -552.24 508 -552.49 544 -552.74 1013 -552.99 621 -553.24 229 -553.49 972 -553.74 1697 -553.99 234 -554.24 27 -554.49 1490 -554.74 369 -554.99 747 -555.24 1963 -555.49 585 -555.74 1756 -555.99 13 -556.24 1107 -556.49 -58 -556.74 783 -556.99 1490 -557.24 -337 -557.49 1860 -557.74 666 -557.99 459 -558.24 117 -558.49 977 -558.74 310 -558.99 1026 -559.24 -3 -559.49 1576 -559.74 900 -559.99 -1184 -560.24 774 -560.49 936 -560.74 360 -560.99 801 -561.24 -819 -561.49 1580 -561.74 63 -561.99 1112 -562.24 571 -562.49 833 -562.74 283 -562.99 -211 -563.24 1035 -563.49 252 -563.74 792 -563.99 -481 -564.24 288 -564.49 540 -564.74 31 -564.99 1585 -565.24 -94 -565.49 1427 -565.74 675 -565.99 1252 -566.24 1499 -566.49 -977 -566.74 648 -566.99 -198 -567.24 1549 -567.49 1089 -567.74 680 -567.99 -423 -568.24 198 -568.49 878 -568.74 189 -568.99 193 -569.24 576 -569.49 1022 -569.74 630 -569.99 653 -570.24 481 -570.49 270 -570.74 216 -570.99 1216 -571.24 873 -571.49 -756 -571.74 1589 -571.99 175 -572.24 909 -572.49 -499 -572.74 1134 -572.99 472 -573.24 1162 -573.49 1702 -573.74 36 -573.99 1026 -574.24 1130 -574.49 896 -574.74 1058 -574.99 972 -575.24 1107 -575.49 702 -575.74 1454 -575.99 1116 -576.24 1562 -576.49 707 -576.74 1130 -576.99 1576 -577.24 364 -577.49 18 -577.74 666 -577.99 175 -578.24 905 -578.49 364 -578.74 2161 -578.99 684 -579.24 1342 -579.49 130 -579.74 923 -579.99 833 -580.24 1116 -580.49 666 -580.74 27 -580.99 1189 -581.24 454 -581.49 139 -581.74 -414 -581.99 481 -582.24 2022 -582.49 743 -582.74 594 -582.99 657 -583.24 1026 -583.49 1630 -583.74 207 -583.99 319 -584.24 553 -584.49 1166 -584.74 716 -584.99 1107 -585.24 -72 -585.49 815 -585.74 1382 -585.99 1445 -586.24 860 -586.49 535 -586.74 819 -586.99 355 -587.24 400 -587.49 626 -587.74 -121 -587.99 1175 -588.24 1116 -588.49 788 -588.74 -198 -588.99 1490 -589.24 1279 -589.49 -499 -589.74 1049 -589.99 103 -590.24 481 -590.49 1153 -590.74 1396 -590.99 -193 -591.24 999 -591.49 364 -591.74 972 -591.99 891 -592.24 -31 -592.49 810 -592.74 1171 -592.99 626 -593.24 959 -593.49 1143 -593.74 297 -593.99 558 -594.24 -94 -594.49 918 -594.74 504 -594.99 1022 -595.24 626 -595.49 211 -595.74 490 -595.99 1391 -596.24 220 -596.49 617 -596.74 261 -596.99 346 -597.24 828 -597.49 162 -597.74 121 -597.99 36 -598.24 184 -598.49 1360 -598.74 1022 -598.99 630 -599.24 1116 -599.49 1819 -599.74 -45 -599.99 734 -600.24 522 -600.49 558 -600.74 887 -600.99 81 -601.24 1373 -601.49 297 -601.74 1427 -601.99 -603 -602.24 81 -602.49 1351 -602.74 891 -602.99 635 -603.24 963 -603.49 -247 -603.74 1058 -603.99 936 -604.24 1688 -604.49 -162 -604.74 1342 -604.99 680 -605.24 963 -605.49 567 -605.74 1171 -605.99 1238 -606.24 693 -606.49 1517 -606.74 526 -606.99 792 -607.24 436 -607.49 1508 -607.74 -328 -607.99 -144 -608.24 1567 -608.49 914 -608.74 702 -608.99 891 -609.24 535 -609.49 1261 -609.74 495 -609.99 1630 -610.24 486 -610.49 1116 -610.74 1274 -610.99 1130 -611.24 914 -611.49 1022 -611.74 1504 -611.99 441 -612.24 1216 -612.49 279 -612.74 729 -612.99 1693 -613.24 968 -613.49 1234 -613.74 851 -613.99 698 -614.24 873 -614.49 1040 -614.74 617 -614.99 684 -615.24 1472 -615.49 608 -615.74 779 -615.99 -139 -616.24 1851 -616.49 1391 -616.74 1540 -616.99 463 -617.24 1080 -617.49 450 -617.74 1058 -617.99 1067 -618.24 819 -618.49 783 -618.74 747 -618.99 603 -619.24 1454 -619.49 896 -619.74 1243 -619.99 1743 -620.24 535 -620.49 1607 -620.74 -198 -620.99 1026 -621.24 535 -621.49 54 -621.74 1121 -621.99 432 -622.24 1243 -622.49 846 -622.74 918 -622.99 662 -623.24 2058 -623.49 207 -623.74 508 -623.99 869 -624.24 -13 -624.49 1387 -624.74 950 -624.99 1779 -625.24 1017 -625.49 1369 -625.74 720 -625.99 346 -626.24 2076 -626.49 319 -626.74 1495 -626.99 1202 -627.24 1274 -627.49 2175 -627.74 743 -627.99 1977 -628.24 680 -628.49 1292 -628.74 1234 -628.99 1914 -629.24 626 -629.49 27 -629.74 1882 -629.99 535 -630.24 1495 -630.49 1171 -630.74 720 -630.99 571 -631.24 1049 -631.49 680 -631.74 788 -631.99 1981 -632.24 738 -632.49 801 -632.74 986 -632.99 837 -633.24 1265 -633.49 1481 -633.74 1896 -633.99 738 -634.24 990 -634.49 729 -634.74 968 -634.99 1684 -635.24 963 -635.49 2310 -635.74 743 -635.99 1071 -636.24 1247 -636.49 617 -636.74 2139 -636.99 1688 -637.24 1432 -637.49 1004 -637.74 788 -637.99 1234 -638.24 761 -638.49 806 -638.74 743 -638.99 1589 -639.24 1490 -639.49 2116 -639.74 1774 -639.99 936 -640.24 1612 -640.49 1193 -640.74 977 -640.99 720 -641.24 1238 -641.49 1657 -641.74 900 -641.99 1603 -642.24 761 -642.49 878 -642.74 599 -642.99 585 -643.24 1891 -643.49 1684 -643.74 2022 -643.99 1634 -644.24 873 -644.49 342 -644.74 1373 -644.99 346 -645.24 1774 -645.49 1107 -645.74 977 -645.99 1909 -646.24 468 -646.49 1171 -646.74 662 -646.99 1837 -647.24 274 -647.49 562 -647.74 932 -647.99 621 -648.24 648 -648.49 815 -648.74 1220 -648.99 1022 -649.24 1067 -649.49 828 -649.74 373 -649.99 553 -650.24 828 -650.49 1116 -650.74 1752 -650.99 297 -651.24 2085 -651.49 45 -651.74 1103 -651.99 562 -652.24 1234 -652.49 540 -652.74 581 -652.99 400 -653.24 1288 -653.49 644 -653.74 423 -653.99 1472 -654.24 490 -654.49 684 -654.74 1571 -654.99 1094 -655.24 535 -655.49 198 -655.74 454 -655.99 666 -656.24 445 -656.49 234 -656.74 544 -656.99 1594 -657.24 806 -657.49 941 -657.74 797 -657.99 914 -658.25 234 -658.5 819 -658.75 873 -659 36 -659.25 1481 -659.5 1306 -659.75 662 -660 454 -660.25 1013 -660.5 945 -660.75 -108 -661 1504 -661.25 472 -661.5 1004 -661.75 391 -662 -67 -662.25 648 -662.5 -139 -662.75 869 -663 306 -663.25 1400 -663.5 1116 -663.75 887 -664 1040 -664.25 391 -664.5 378 -664.75 -337 -665 666 -665.25 562 -665.5 112 -665.75 806 -666 544 -666.25 1508 -666.5 90 -666.75 211 -667 378 -667.25 -441 -667.5 540 -667.75 486 -668 562 -668.25 -36 -668.5 247 -668.75 423 -669 -486 -669.25 225 -669.5 918 -669.75 1049 -670 1409 -670.25 549 -670.5 477 -670.75 369 -671 283 -671.25 891 -671.5 171 -671.75 49 -672 387 -672.25 1008 -672.5 405 -672.75 67 -673 -175 -673.25 905 -673.5 -139 -673.75 558 -674 945 -674.25 959 -674.5 450 -674.75 508 -675 234 -675.25 297 -675.5 -13 -675.75 -49 -676 414 -676.25 382 -676.5 -103 -676.75 1013 -677 639 -677.25 513 -677.5 -58 -677.75 1661 -678 -153 -678.25 40 -678.5 130 -678.75 639 -679 941 -679.25 -477 -679.5 -108 -679.75 180 -680 472 -680.25 765 -680.5 -297 -680.75 1220 -681 684 -681.25 450 -681.5 234 -681.75 310 -682 -54 -682.25 279 -682.5 261 -682.75 499 -683 -135 -683.25 517 -683.5 -2 -683.75 94 -684 72 -684.25 680 -684.5 -108 -684.75 279 -685 513 -685.25 -328 -685.5 594 -685.75 126 -686 675 -686.25 103 -686.5 387 -686.75 927 -687 -310 -687.25 364 -687.5 306 -687.75 756 -688 810 -688.25 725 -688.5 54 -688.75 40 -689 720 -689.25 409 -689.5 657 -689.75 315 -690 599 -690.25 373 -690.5 -247 -690.75 490 -691 54 -691.25 540 -691.5 -126 -691.75 -549 -692 486 -692.25 788 -692.5 -234 -692.75 -162 -693 171 -693.25 409 -693.5 477 -693.75 -981 -694 157 -694.25 99 -694.5 1071 -694.75 -648 -695 -58 -695.25 477 -695.5 220 -695.75 211 -696 -171 -696.25 126 -696.5 666 -696.75 166 -697 743 -697.25 387 -697.5 -130 -697.75 716 -698 409 -698.25 4 -698.5 774 -698.75 1639 -699 252 -699.25 396 -699.5 -454 -699.75 -148 -700 1436 diff --git a/Modules/Biophotonics/python/iMC/mc/data/bilirubin.txt b/Modules/Biophotonics/python/iMC/mc/data/bilirubin.txt deleted file mode 100644 index 3ca6e8e1c0..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/data/bilirubin.txt +++ /dev/null @@ -1,1844 +0,0 @@ -# taken from http://omlc.org/spectra/PhotochemCAD/data/119-abs.txt -##Wavelength (nm) Molar Extinction (cm-1/M) -239.75 17208 -240 16074 -240.25 18576 -240.5 16910 -240.75 17810 -241 17784 -241.25 17734 -241.5 18617 -241.75 17737 -242 17532 -242.25 17582 -242.5 17609 -242.75 17141 -243 17102 -243.25 16666 -243.5 16594 -243.75 16111 -244 16576 -244.25 15964 -244.5 15470 -244.75 15805 -245 15304 -245.25 15243 -245.5 15230 -245.75 14725 -246 14481 -246.25 14588 -246.5 14454 -246.75 14002 -247 14152 -247.25 13951 -247.5 13735 -247.75 13755 -248 13531 -248.25 13231 -248.5 13354 -248.75 13226 -249 12855 -249.25 13256 -249.5 12851 -249.75 12557 -250 12254 -250.25 12287 -250.5 12174 -250.75 12231 -251 11840 -251.25 11772 -251.5 11575 -251.75 11246 -252 11231 -252.25 11165 -252.5 11021 -252.75 11034 -253 11068 -253.25 10789 -253.5 10691 -253.75 10568 -254 10477 -254.25 10341 -254.5 10346 -254.75 10029 -255 10164 -255.25 10055 -255.5 9970 -255.75 9865 -256 9945 -256.25 9764 -256.5 9632 -256.75 9781 -257 9670 -257.25 9526 -257.5 9223 -257.75 9096 -258 9220 -258.25 9312 -258.5 9145 -258.75 9138 -259 8955 -259.25 8984 -259.5 8862 -259.75 8933 -260 8891 -260.25 8896 -260.5 8816 -260.75 8984 -261 8774 -261.25 8840 -261.5 8737 -261.75 8679 -262 8719 -262.25 8874 -262.5 8777 -262.75 8685 -263 8627 -263.25 8732 -263.5 8527 -263.75 8572 -264 8650 -264.25 8812 -264.5 8614 -264.75 8601 -265 8612 -265.25 8688 -265.5 8513 -265.75 8498 -266 8698 -266.25 8554 -266.5 8479 -266.75 8449 -267 8560 -267.25 8544 -267.5 8536 -267.75 8448 -268 8470 -268.25 8574 -268.5 8519 -268.75 8580 -269 8518 -269.25 8460 -269.5 8514 -269.75 8616 -270 8620 -270.25 8681 -270.5 8436 -270.75 8509 -271 8573 -271.25 8526 -271.5 8474 -271.75 8543 -272 8591 -272.25 8515 -272.5 8537 -272.75 8695 -273 8550 -273.25 8547 -273.5 8596 -273.75 8545 -274 8435 -274.25 8695 -274.5 8471 -274.75 8560 -275 8727 -275.25 8631 -275.5 8652 -275.75 8360 -276 8625 -276.25 8456 -276.5 8639 -276.75 8632 -277 8473 -277.25 8521 -277.5 8589 -277.75 8557 -278 8627 -278.25 8344 -278.5 8597 -278.75 8561 -279 8646 -279.25 8452 -279.5 8527 -279.75 8426 -280 8634 -280.25 8461 -280.5 8496 -280.75 8525 -281 8383 -281.25 8515 -281.5 8307 -281.75 8411 -282 8374 -282.25 8663 -282.5 8398 -282.75 8418 -283 8501 -283.25 8565 -283.5 8227 -283.75 8286 -284 8582 -284.25 8334 -284.5 8305 -284.75 8220 -285 8313 -285.25 8211 -285.5 8302 -285.75 8226 -286 8234 -286.25 8471 -286.5 8205 -286.75 8313 -287 8258 -287.25 8237 -287.5 8234 -287.75 8210 -288 8104 -288.25 8203 -288.5 8269 -288.75 8138 -289 8030 -289.25 8063 -289.5 8104 -289.75 8119 -290 7874 -290.25 7970 -290.5 8081 -290.75 8068 -291 8115 -291.25 7943 -291.5 7911 -291.75 7808 -292 7876 -292.25 7947 -292.5 7832 -292.75 8024 -293 7867 -293.25 7657 -293.5 7798 -293.75 7739 -294 7745 -294.25 7622 -294.5 7718 -294.75 7922 -295 7810 -295.25 7709 -295.5 7784 -295.75 7745 -296 7644 -296.25 7642 -296.5 7512 -296.75 7609 -297 7791 -297.25 7664 -297.5 7414 -297.75 7515 -298 7596 -298.25 7627 -298.5 7578 -298.75 7628 -299 7569 -299.25 7374 -299.5 7429 -299.75 7468 -300 7370 -300.25 7448 -300.5 7331 -300.75 7592 -301 7374 -301.25 7214 -301.5 7484 -301.75 7449 -302 7282 -302.25 7230 -302.5 7328 -302.75 7071 -303 7348 -303.25 7135 -303.5 7224 -303.75 7300 -304 7399 -304.25 7224 -304.5 7244 -304.75 7208 -305 7085 -305.25 7036 -305.5 7257 -305.75 7153 -306 6989 -306.25 6795 -306.5 7012 -306.75 6993 -307 7047 -307.25 7085 -307.5 6900 -307.75 6823 -308 6737 -308.25 6897 -308.5 6852 -308.75 7083 -309 6903 -309.25 6895 -309.5 6826 -309.75 6820 -310 6811 -310.25 6907 -310.5 6804 -310.75 6522 -311 6559 -311.25 6618 -311.5 6688 -311.75 6701 -312 6632 -312.25 6548 -312.5 6667 -312.75 6580 -313 6519 -313.25 6607 -313.5 6338 -313.75 6559 -314 6529 -314.25 6385 -314.5 6425 -314.75 6346 -315 6458 -315.25 6318 -315.5 6260 -315.75 6212 -316 6277 -316.25 6176 -316.5 6219 -316.75 6363 -317 6160 -317.25 6304 -317.5 6070 -317.75 6201 -318 6177 -318.25 6108 -318.5 6033 -318.75 5911 -319 5864 -319.25 5951 -319.5 5995 -319.75 5901 -320 6010 -320.25 5815 -320.5 5753 -320.75 5996 -321 5886 -321.25 5830 -321.5 5816 -321.75 5627 -322 5870 -322.25 5621 -322.5 5559 -322.75 5697 -323 5679 -323.25 5544 -323.5 5478 -323.75 5637 -324 5690 -324.25 5486 -324.5 5325 -324.75 5452 -325 5328 -325.25 5432 -325.5 5564 -325.75 5209 -326 5194 -326.25 5150 -326.5 5252 -326.75 5311 -327 5056 -327.25 5097 -327.5 5312 -327.75 5208 -328 5030 -328.25 4895 -328.5 5167 -328.75 5078 -329 4928 -329.25 5029 -329.5 4921 -329.75 4866 -330 4851 -330.25 4971 -330.5 4965 -330.75 4756 -331 4830 -331.25 4924 -331.5 4578 -331.75 4746 -332 4801 -332.25 4654 -332.5 4736 -332.75 4795 -333 4822 -333.25 4698 -333.5 4701 -333.75 4652 -334 4351 -334.25 4609 -334.5 4523 -334.75 4423 -335 4573 -335.25 4883 -335.5 4723 -335.75 4337 -336 4560 -336.25 4593 -336.5 4807 -336.75 4531 -337 4442 -337.25 4470 -337.5 4425 -337.75 4531 -338 4267 -338.25 4399 -338.5 4248 -338.75 4383 -339 4350 -339.25 4346 -339.5 4390 -339.75 4632 -340 4394 -340.25 4330 -340.5 4231 -340.75 4441 -341 4371 -341.25 4360 -341.5 4383 -341.75 4538 -342 4197 -342.25 4176 -342.5 4356 -342.75 4335 -343 4234 -343.25 4170 -343.5 4184 -343.75 4384 -344 4472 -344.25 4256 -344.5 4466 -344.75 4355 -345 4351 -345.25 4556 -345.5 4298 -345.75 4225 -346 4508 -346.25 4502 -346.5 4557 -346.75 4384 -347 4371 -347.25 4533 -347.5 4385 -347.75 4628 -348 4396 -348.25 4668 -348.5 4687 -348.75 4254 -349 4565 -349.25 4804 -349.5 4687 -349.75 4724 -350 4639 -350.25 4570 -350.5 4544 -350.75 4738 -351 4801 -351.25 4728 -351.5 4914 -351.75 4843 -352 4826 -352.25 4962 -352.5 5069 -352.75 4863 -353 4951 -353.25 5046 -353.5 5156 -353.75 5211 -354 5139 -354.25 4968 -354.5 5138 -354.75 5196 -355 5241 -355.25 5325 -355.5 5324 -355.75 5280 -356 5180 -356.25 5445 -356.5 5225 -356.75 5468 -357 5401 -357.25 5586 -357.5 5684 -357.75 5657 -358 5600 -358.25 5847 -358.5 5801 -358.75 5667 -359 5802 -359.25 5822 -359.5 5899 -359.75 6019 -360 5936 -360.25 5993 -360.5 6071 -360.75 6071 -361 6135 -361.25 6222 -361.5 6196 -361.75 6219 -362 6386 -362.25 6342 -362.5 6462 -362.75 6449 -363 6670 -363.25 6545 -363.5 6722 -363.75 6663 -364 6678 -364.25 6709 -364.5 6865 -364.75 6765 -365 6972 -365.25 6997 -365.5 6991 -365.75 7078 -366 7225 -366.25 7159 -366.5 7295 -366.75 7440 -367 7392 -367.25 7443 -367.5 7485 -367.75 7604 -368 7718 -368.25 7726 -368.5 7732 -368.75 7787 -369 8029 -369.25 7979 -369.5 8120 -369.75 8211 -370 8189 -370.25 8371 -370.5 8318 -370.75 8419 -371 8399 -371.25 8576 -371.5 8579 -371.75 8714 -372 8934 -372.25 8884 -372.5 8952 -372.75 8892 -373 9054 -373.25 9118 -373.5 9234 -373.75 9307 -374 9389 -374.25 9520 -374.5 9382 -374.75 9615 -375 9685 -375.25 9807 -375.5 9809 -375.75 10012 -376 9949 -376.25 10165 -376.5 10160 -376.75 10361 -377 10418 -377.25 10527 -377.5 10587 -377.75 10720 -378 10795 -378.25 10832 -378.5 10931 -378.75 11099 -379 11352 -379.25 11250 -379.5 11380 -379.75 11488 -380 11551 -380.25 11693 -380.5 11781 -380.75 12018 -381 12026 -381.25 12158 -381.5 12153 -381.75 12321 -382 12376 -382.25 12542 -382.5 12561 -382.75 12914 -383 12831 -383.25 13004 -383.5 13033 -383.75 13120 -384 13339 -384.25 13526 -384.5 13534 -384.75 13639 -385 13778 -385.25 13924 -385.5 14011 -385.75 14125 -386 14245 -386.25 14357 -386.5 14611 -386.75 14578 -387 14794 -387.25 14943 -387.5 15004 -387.75 15132 -388 15217 -388.25 15346 -388.5 15625 -388.75 15701 -389 15763 -389.25 15872 -389.5 16082 -389.75 16198 -390 16334 -390.25 16618 -390.5 16750 -390.75 16922 -391 16897 -391.25 17153 -391.5 17363 -391.75 17306 -392 17508 -392.25 17645 -392.5 17947 -392.75 18077 -393 18306 -393.25 18360 -393.5 18564 -393.75 18681 -394 18947 -394.25 19077 -394.5 19257 -394.75 19386 -395 19603 -395.25 19819 -395.5 19840 -395.75 20018 -396 20306 -396.25 20537 -396.5 20696 -396.75 20890 -397 21025 -397.25 21099 -397.5 21508 -397.75 21590 -398 21695 -398.25 22046 -398.5 22099 -398.75 22208 -399 22456 -399.25 22739 -399.5 22910 -399.75 23068 -400 23223 -400.25 23332 -400.5 23529 -400.75 23716 -401 23938 -401.25 24060 -401.5 24153 -401.75 24483 -402 24617 -402.25 24823 -402.5 24967 -402.75 25185 -403 25435 -403.25 25604 -403.5 25578 -403.75 25931 -404 26126 -404.25 26394 -404.5 26468 -404.75 26635 -405 26737 -405.25 27056 -405.5 27230 -405.75 27451 -406 27857 -406.25 27866 -406.5 28176 -406.75 28139 -407 28467 -407.25 28640 -407.5 28746 -407.75 29143 -408 29168 -408.25 29527 -408.5 29637 -408.75 29858 -409 30049 -409.25 30302 -409.5 30569 -409.75 30645 -410 30831 -410.25 30924 -410.5 31204 -410.75 31548 -411 31698 -411.25 31887 -411.5 32216 -411.75 32411 -412 32610 -412.25 32535 -412.5 32945 -412.75 32846 -413 33200 -413.25 33433 -413.5 33480 -413.75 33777 -414 34095 -414.25 34190 -414.5 34531 -414.75 34834 -415 34903 -415.25 35085 -415.5 35414 -415.75 35564 -416 35706 -416.25 35778 -416.5 36112 -416.75 36431 -417 36596 -417.25 36893 -417.5 37139 -417.75 37287 -418 37558 -418.25 37587 -418.5 37957 -418.75 38212 -419 38475 -419.25 38640 -419.5 38902 -419.75 39044 -420 39293 -420.25 39645 -420.5 39675 -420.75 39886 -421 40236 -421.25 40299 -421.5 40898 -421.75 40977 -422 41146 -422.25 41209 -422.5 41438 -422.75 41659 -423 42024 -423.25 41937 -423.5 42254 -423.75 42509 -424 42569 -424.25 42830 -424.5 43004 -424.75 43220 -425 43491 -425.25 43775 -425.5 43958 -425.75 44066 -426 44106 -426.25 44366 -426.5 44656 -426.75 44818 -427 44920 -427.25 45175 -427.5 45289 -427.75 45205 -428 45653 -428.25 45663 -428.5 46031 -428.75 45880 -429 46284 -429.25 46275 -429.5 46321 -429.75 46875 -430 46801 -430.25 47034 -430.5 47183 -430.75 47159 -431 47497 -431.25 47738 -431.5 47623 -431.75 47944 -432 48068 -432.25 48045 -432.5 48481 -432.75 48552 -433 48455 -433.25 48794 -433.5 48981 -433.75 48824 -434 49361 -434.25 49335 -434.5 49562 -434.75 49363 -435 49796 -435.25 49830 -435.5 50195 -435.75 50058 -436 50080 -436.25 50471 -436.5 50242 -436.75 50212 -437 50999 -437.25 50705 -437.5 50718 -437.75 51066 -438 51272 -438.25 51313 -438.5 51585 -438.75 51472 -439 51653 -439.25 51846 -439.5 51777 -439.75 51924 -440 52109 -440.25 52208 -440.5 52280 -440.75 52293 -441 52356 -441.25 52457 -441.5 52557 -441.75 52914 -442 53001 -442.25 52673 -442.5 52891 -442.75 52803 -443 53133 -443.25 52993 -443.5 53312 -443.75 53499 -444 53570 -444.25 53376 -444.5 53727 -444.75 53590 -445 53466 -445.25 53330 -445.5 53550 -445.75 53855 -446 53945 -446.25 54100 -446.5 53803 -446.75 54042 -447 53727 -447.25 54205 -447.5 54320 -447.75 54323 -448 54336 -448.25 54364 -448.5 54198 -448.75 54445 -449 54593 -449.25 54669 -449.5 54570 -449.75 54814 -450 54889 -450.25 55016 -450.5 54631 -450.75 55023 -451 54904 -451.25 55003 -451.5 54709 -451.75 54692 -452 54913 -452.25 54882 -452.5 54780 -452.75 54816 -453 54985 -453.25 54709 -453.5 54940 -453.75 54965 -454 54944 -454.25 54897 -454.5 54881 -454.75 54860 -455 54838 -455.25 54970 -455.5 54914 -455.75 54792 -456 54852 -456.25 54810 -456.5 54653 -456.75 54691 -457 54697 -457.25 54499 -457.5 54411 -457.75 54379 -458 54456 -458.25 54476 -458.5 54507 -458.75 54318 -459 54179 -459.25 54368 -459.5 53982 -459.75 53776 -460 53869 -460.25 53863 -460.5 53765 -460.75 53687 -461 53612 -461.25 53421 -461.5 53163 -461.75 53220 -462 53073 -462.25 52805 -462.5 52643 -462.75 52655 -463 52297 -463.25 52346 -463.5 52125 -463.75 52124 -464 51893 -464.25 51713 -464.5 51601 -464.75 51196 -465 51182 -465.25 50770 -465.5 50676 -465.75 50469 -466 50213 -466.25 50146 -466.5 49932 -466.75 49547 -467 49358 -467.25 49033 -467.5 48863 -467.75 48688 -468 48330 -468.25 48011 -468.5 47847 -468.75 47529 -469 47213 -469.25 47164 -469.5 46779 -469.75 46505 -470 46188 -470.25 45749 -470.5 45325 -470.75 45059 -471 44709 -471.25 44313 -471.5 44104 -471.75 43981 -472 43437 -472.25 43051 -472.5 42721 -472.75 42370 -473 41989 -473.25 41733 -473.5 41243 -473.75 40789 -474 40495 -474.25 39942 -474.5 39694 -474.75 39259 -475 38765 -475.25 38218 -475.5 37894 -475.75 37467 -476 36981 -476.25 36510 -476.5 36003 -476.75 35534 -477 35156 -477.25 34646 -477.5 34092 -477.75 33757 -478 33338 -478.25 32856 -478.5 32487 -478.75 31972 -479 31378 -479.25 30972 -479.5 30621 -479.75 30125 -480 29636 -480.25 29219 -480.5 28809 -480.75 28426 -481 27950 -481.25 27596 -481.5 27063 -481.75 26732 -482 26271 -482.25 25872 -482.5 25391 -482.75 24929 -483 24544 -483.25 24180 -483.5 23794 -483.75 23353 -484 22833 -484.25 22532 -484.5 22123 -484.75 21593 -485 21333 -485.25 20952 -485.5 20411 -485.75 20085 -486 19771 -486.25 19386 -486.5 18940 -486.75 18564 -487 18211 -487.25 17827 -487.5 17433 -487.75 17152 -488 16794 -488.25 16455 -488.5 16035 -488.75 15691 -489 15367 -489.25 14995 -489.5 14678 -489.75 14362 -490 14025 -490.25 13750 -490.5 13415 -490.75 13103 -491 12797 -491.25 12457 -491.5 12191 -491.75 11964 -492 11835 -492.25 11548 -492.5 11298 -492.75 11013 -493 10718 -493.25 10489 -493.5 10199 -493.75 9944 -494 9634 -494.25 9399 -494.5 9098 -494.75 8913 -495 8611 -495.25 8326 -495.5 8195 -495.75 7887 -496 7707 -496.25 7520 -496.5 7320 -496.75 7033 -497 6821 -497.25 6602 -497.5 6485 -497.75 6171 -498 6090 -498.25 5889 -498.5 5721 -498.75 5508 -499 5400 -499.25 5182 -499.5 5068 -499.75 4893 -500 4767 -500.25 4534 -500.5 4461 -500.75 4285 -501 4204 -501.25 4053 -501.5 3875 -501.75 3753 -502 3654 -502.25 3487 -502.5 3412 -502.75 3333 -503 3151 -503.25 3151 -503.5 3037 -503.75 2899 -504 2794 -504.25 2746 -504.5 2654 -504.75 2530 -505 2503 -505.25 2359 -505.5 2327 -505.75 2211 -506 2144 -506.25 2030 -506.5 2033 -506.75 2005 -507 1863 -507.25 1858 -507.5 1718 -507.75 1776 -508 1702 -508.25 1587 -508.5 1611 -508.75 1561 -509 1466 -509.25 1385 -509.5 1383 -509.75 1374 -510 1299 -510.25 1314 -510.5 1200 -510.75 1148 -511 1116 -511.25 1032 -511.5 1108 -511.75 995 -512 966 -512.25 941 -512.5 920 -512.75 908 -513 846 -513.25 848 -513.5 846 -513.75 737 -514 782 -514.25 724 -514.5 716 -514.75 704 -515 624 -515.25 616 -515.5 574 -515.75 602 -516 582 -516.25 547 -516.5 506 -516.75 525 -517 485 -517.25 488 -517.5 487 -517.75 431 -518 396 -518.25 411 -518.5 418 -518.75 365 -519 401 -519.25 361 -519.5 375 -519.75 346 -520 340 -520.25 326 -520.5 357 -520.75 292 -521 306 -521.25 270 -521.5 273 -521.75 251 -522 212 -522.25 253 -522.5 285 -522.75 233 -523 251 -523.25 247 -523.5 236 -523.75 235 -524 214 -524.25 188 -524.5 212 -524.75 201 -525 214 -525.25 169 -525.5 136 -525.75 182 -526 222 -526.25 147 -526.5 164 -526.75 133 -527 191 -527.25 176 -527.5 141 -527.75 156 -528 208 -528.25 179 -528.5 117 -528.75 116 -529 152 -529.25 121 -529.5 153 -529.75 178 -530 129 -530.25 102 -530.5 163 -530.75 118 -531 130 -531.25 82 -531.5 83 -531.75 99 -532 126 -532.25 153 -532.5 70 -532.75 109 -533 101 -533.25 72 -533.5 72 -533.75 114 -534 68 -534.25 71 -534.5 90 -534.75 177 -535 107 -535.25 107 -535.5 80 -535.75 92 -536 121 -536.25 37 -536.5 15 -536.75 54 -537 120 -537.25 104 -537.5 59 -537.75 40 -538 81 -538.25 126 -538.5 102 -538.75 80 -539 66 -539.25 65 -539.5 32 -539.75 83 -540 66 -540.25 64 -540.5 92 -540.75 84 -541 58 -541.25 72 -541.5 14 -541.75 78 -542 9 -542.25 71 -542.5 40 -542.75 118 -543 57 -543.25 100 -543.5 89 -543.75 64 -544 61 -544.25 86 -544.5 68 -544.75 76 -545 46 -545.25 85 -545.5 71 -545.75 61 -546 31 -546.25 68 -546.5 84 -546.75 68 -547 45 -547.25 94 -547.5 125 -547.75 33 -548 104 -548.25 70 -548.5 59 -548.75 33 -549 21 -549.25 1 -549.5 55 -549.75 41 -550 61 -550.25 75 -550.5 71 -550.75 81 -551 34 -551.25 63 -551.5 68 -551.75 56 -552 27 -552.25 61 -552.5 69 -552.75 45 -553 71 -553.25 90 -553.5 55 -553.75 105 -554 20 -554.25 47 -554.5 21 -554.75 10 -555 57 -555.25 77 -555.5 20 -555.75 56 -556 60 -556.25 105 -556.5 15 -556.75 8 -557 -8 -557.25 69 -557.5 18 -557.75 47 -558 6 -558.25 42 -558.5 27 -558.75 39 -559 12 -559.25 20 -559.5 41 -559.75 9 -560 52 -560.25 67 -560.5 39 -560.75 72 -561 40 -561.25 52 -561.5 73 -561.75 39 -562 -4 -562.25 72 -562.5 64 -562.75 52 -563 109 -563.25 12 -563.5 49 -563.75 -25 -564 9 -564.25 35 -564.5 59 -564.75 78 -565 15 -565.25 27 -565.5 52 -565.75 98 -566 10 -566.25 -3 -566.5 40 -566.75 -2 -567 16 -567.25 64 -567.5 82 -567.75 19 -568 28 -568.25 37 -568.5 6 -568.75 64 -569 35 -569.25 19 -569.5 18 -569.75 -33 -570 45 -570.25 -6 -570.5 19 -570.75 12 -571 9 -571.25 -6 -571.5 -1 -571.75 3 -572 47 -572.25 39 -572.5 16 -572.75 33 -573 10 -573.25 32 -573.5 18 -573.75 29 -574 68 -574.25 52 -574.5 9 -574.75 21 -575 34 -575.25 24 -575.5 7 -575.75 -63 -576 24 -576.25 32 -576.5 54 -576.75 19 -577 13 -577.25 11 -577.5 59 -577.75 31 -578 78 -578.25 -16 -578.5 39 -578.75 -12 -579 13 -579.25 21 -579.5 77 -579.75 25 -580 2 -580.25 -3 -580.5 -6 -580.75 0 -581 24 -581.25 -27 -581.5 29 -581.75 -11 -582 17 -582.25 -18 -582.5 -10 -582.75 51 -583 27 -583.25 -5 -583.5 17 -583.75 -66 -584 0 -584.25 19 -584.5 21 -584.75 20 -585 -21 -585.25 -8 -585.5 49 -585.75 -12 -586 4 -586.25 60 -586.5 29 -586.75 16 -587 54 -587.25 -10 -587.5 15 -587.75 -22 -588 -39 -588.25 15 -588.5 46 -588.75 29 -589 -31 -589.25 44 -589.5 -37 -589.75 12 -590 56 -590.25 51 -590.5 44 -590.75 22 -591 46 -591.25 -2 -591.5 59 -591.75 27 -592 77 -592.25 38 -592.5 74 -592.75 56 -593 -8 -593.25 0 -593.5 25 -593.75 54 -594 18 -594.25 110 -594.5 17 -594.75 -16 -595 10 -595.25 -71 -595.5 -25 -595.75 57 -596 5 -596.25 -29 -596.5 52 -596.75 37 -597 30 -597.25 24 -597.5 85 -597.75 28 -598 36 -598.25 2 -598.5 -48 -598.75 67 -599 -31 -599.25 8 -599.5 56 -599.75 71 -600 58 -600.25 40 -600.5 -8 -600.75 5 -601 17 -601.25 8 -601.5 73 -601.75 91 -602 42 -602.25 2 -602.5 64 -602.75 -16 -603 22 -603.25 55 -603.5 -33 -603.75 6 -604 -2 -604.25 -12 -604.5 71 -604.75 24 -605 53 -605.25 8 -605.5 28 -605.75 37 -606 29 -606.25 -16 -606.5 59 -606.75 11 -607 37 -607.25 8 -607.5 -6 -607.75 -12 -608 25 -608.25 69 -608.5 78 -608.75 64 -609 18 -609.25 7 -609.5 37 -609.75 81 -610 54 -610.25 2 -610.5 29 -610.75 2 -611 -1 -611.25 21 -611.5 48 -611.75 -5 -612 32 -612.25 2 -612.5 39 -612.75 12 -613 12 -613.25 -9 -613.5 50 -613.75 6 -614 0 -614.25 79 -614.5 19 -614.75 20 -615 85 -615.25 -10 -615.5 29 -615.75 36 -616 84 -616.25 31 -616.5 14 -616.75 4 -617 84 -617.25 -14 -617.5 46 -617.75 24 -618 -3 -618.25 -3 -618.5 0 -618.75 -23 -619 -20 -619.25 69 -619.5 30 -619.75 24 -620 -2 -620.25 89 -620.5 -31 -620.75 3 -621 62 -621.25 27 -621.5 29 -621.75 46 -622 54 -622.25 -19 -622.5 48 -622.75 4 -623 51 -623.25 -26 -623.5 69 -623.75 -97 -624 64 -624.25 -31 -624.5 78 -624.75 -17 -625 28 -625.25 -42 -625.5 77 -625.75 57 -626 15 -626.25 40 -626.5 -65 -626.75 -14 -627 77 -627.25 -7 -627.5 36 -627.75 2 -628 15 -628.25 -23 -628.5 13 -628.75 14 -629 47 -629.25 -70 -629.5 -54 -629.75 33 -630 28 -630.25 42 -630.5 -13 -630.75 -13 -631 29 -631.25 51 -631.5 59 -631.75 44 -632 -29 -632.25 51 -632.5 26 -632.75 71 -633 54 -633.25 60 -633.5 29 -633.75 90 -634 0 -634.25 11 -634.5 15 -634.75 13 -635 32 -635.25 75 -635.5 78 -635.75 -24 -636 13 -636.25 47 -636.5 -18 -636.75 -10 -637 0 -637.25 0 -637.5 29 -637.75 32 -638 -9 -638.25 -19 -638.5 5 -638.75 61 -639 36 -639.25 11 -639.5 27 -639.75 56 -640 4 -640.25 43 -640.5 15 -640.75 -59 -641 -19 -641.25 76 -641.5 32 -641.75 -21 -642 -35 -642.25 39 -642.5 20 -642.75 39 -643 -22 -643.25 -29 -643.5 -12 -643.75 17 -644 -3 -644.25 32 -644.5 54 -644.75 -25 -645 -26 -645.25 11 -645.5 91 -645.75 -3 -646 -24 -646.25 -56 -646.5 -49 -646.75 -47 -647 93 -647.25 36 -647.5 0 -647.75 86 -648 34 -648.25 34 -648.5 -23 -648.75 25 -649 -25 -649.25 -49 -649.5 -35 -649.75 78 -650 86 -650.25 -25 -650.5 -16 -650.75 77 -651 -16 -651.25 35 -651.5 3 -651.75 -19 -652 8 -652.25 19 -652.5 -30 -652.75 -23 -653 5 -653.25 23 -653.5 79 -653.75 6 -654 -46 -654.25 -15 -654.5 -17 -654.75 60 -655 78 -655.25 -25 -655.5 51 -655.75 -48 -656 53 -656.25 93 -656.5 54 -656.75 -45 -657 14 -657.25 98 -657.5 -2 -657.75 42 -658 -13 -658.25 52 -658.5 59 -658.75 74 -659 -3 -659.25 54 -659.5 60 -659.75 -27 -660 30 -660.25 25 -660.5 -6 -660.75 8 -661 24 -661.25 67 -661.5 5 -661.75 46 -662 24 -662.25 -33 -662.5 26 -662.75 106 -663 -18 -663.25 62 -663.5 37 -663.75 81 -664 37 -664.25 104 -664.5 17 -664.75 110 -665 -21 -665.25 74 -665.5 51 -665.75 35 -666 -78 -666.25 49 -666.5 43 -666.75 42 -667 55 -667.25 65 -667.5 48 -667.75 -49 -668 48 -668.25 86 -668.5 68 -668.75 2 -669 31 -669.25 -21 -669.5 16 -669.75 26 -670 87 -670.25 181 -670.5 87 -670.75 44 -671 107 -671.25 43 -671.5 88 -671.75 28 -672 13 -672.25 73 -672.5 7 -672.75 76 -673 44 -673.25 80 -673.5 14 -673.75 12 -674 32 -674.25 11 -674.5 5 -674.75 -23 -675 -18 -675.25 12 -675.5 -56 -675.75 -7 -676 47 -676.25 33 -676.5 0 -676.75 58 -677 158 -677.25 46 -677.5 64 -677.75 17 -678 30 -678.25 -80 -678.5 21 -678.75 -21 -679 -1 -679.25 5 -679.5 86 -679.75 36 -680 -20 -680.25 -34 -680.5 53 -680.75 6 -681 21 -681.25 41 -681.5 59 -681.75 39 -682 51 -682.25 8 -682.5 46 -682.75 43 -683 11 -683.25 11 -683.5 -19 -683.75 8 -684 15 -684.25 -16 -684.5 33 -684.75 32 -685 -36 -685.25 32 -685.5 11 -685.75 25 -686 49 -686.25 -53 -686.5 0 -686.75 -11 -687 -6 -687.25 -22 -687.5 8 -687.75 -18 -688 45 -688.25 -41 -688.5 17 -688.75 11 -689 32 -689.25 -40 -689.5 54 -689.75 34 -690 35 -690.25 50 -690.5 19 -690.75 -58 -691 -59 -691.25 70 -691.5 -55 -691.75 8 -692 21 -692.25 8 -692.5 40 -692.75 -27 -693 -41 -693.25 11 -693.5 21 -693.75 -24 -694 48 -694.25 13 -694.5 24 -694.75 -16 -695 -9 -695.25 0 -695.5 3 -695.75 16 -696 -3 -696.25 70 -696.5 31 -696.75 -48 -697 -6 -697.25 52 -697.5 12 -697.75 44 -698 50 -698.25 -7 -698.5 4 -698.75 -4 -699 8 -699.25 35 -699.5 -61 -699.75 -32 -700 103 diff --git a/Modules/Biophotonics/python/iMC/mc/data/colon_default.mci b/Modules/Biophotonics/python/iMC/mc/data/colon_default.mci deleted file mode 100644 index 9017b775cb..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/data/colon_default.mci +++ /dev/null @@ -1,14 +0,0 @@ -1.0 # file version -1 # number of runs - -temp.mco A # output filename, ASCII/Binary -1000000 # No. of photons -0.002 2 # dz, dr -500 1 1 # No. of dz, dr & da. - -2 # No. of layers -# n mua mus g d # One line for each layer -1.0 # n for medium above. -1.380 1.78741 20.00000 0.000 0.050 -1.380 1.78741 20.00000 0.000 0.050 -1.0 # n for medium below. diff --git a/Modules/Biophotonics/python/iMC/mc/data/correct.mci b/Modules/Biophotonics/python/iMC/mc/data/correct.mci deleted file mode 100644 index 3548fe2f84..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/data/correct.mci +++ /dev/null @@ -1,15 +0,0 @@ -1.0 # file version -1 # number of runs - -temp.mco A # output filename, ASCII/Binary -1000000 # No. of photons -0.002 2 # dz, dr -500 1 1 # No. of dz, dr & da. - -3 # No. of layers -# n mua mus g d # One line for each layer -1.0 # n for medium above. -1.000 0.02100 0.03200 4.300 540.000 -1.000 0.01000 0.01000 1.000 100.000 -100.100 1.01100 1.02100 103.100 10410.000 -1.0 # n for medium below. diff --git a/Modules/Biophotonics/python/iMC/mc/data/haemoglobin.txt b/Modules/Biophotonics/python/iMC/mc/data/haemoglobin.txt deleted file mode 100644 index b5e87f7035..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/data/haemoglobin.txt +++ /dev/null @@ -1,378 +0,0 @@ -lambda Hb02 Hb -nm cm-1/M cm-1/M -250 106112 112736 -252 105552 112736 -254 107660 112736 -256 109788 113824 -258 112944 115040 -260 116376 116296 -262 120188 117564 -264 124412 118876 -266 128696 120208 -268 133064 121544 -270 136068 122880 -272 137232 123096 -274 138408 121952 -276 137424 120808 -278 135820 119840 -280 131936 118872 -282 127720 117628 -284 122280 114820 -286 116508 112008 -288 108484 107140 -290 104752 98364 -292 98936 91636 -294 88136 85820 -296 79316 77100 -298 70884 69444 -300 65972 64440 -302 63208 61300 -304 61952 58828 -306 62352 56908 -308 62856 57620 -310 63352 59156 -312 65972 62248 -314 69016 65344 -316 72404 68312 -318 75536 71208 -320 78752 74508 -322 82256 78284 -324 85972 82060 -326 89796 85592 -328 93768 88516 -330 97512 90856 -332 100964 93192 -334 103504 95532 -336 104968 99792 -338 106452 104476 -340 107884 108472 -342 109060 110996 -344 110092 113524 -346 109032 116052 -348 107984 118752 -350 106576 122092 -352 105040 125436 -354 103696 128776 -356 101568 132120 -358 97828 133632 -360 94744 134940 -362 92248 136044 -364 89836 136972 -366 88484 137900 -368 87512 138856 -370 88176 139968 -372 91592 141084 -374 95140 142196 -376 98936 143312 -378 103432 144424 -380 109564 145232 -382 116968 145232 -384 125420 148668 -386 135132 153908 -388 148100 159544 -390 167748 167780 -392 189740 180004 -394 212060 191540 -396 231612 202124 -398 248404 212712 -400 266232 223296 -402 284224 236188 -404 308716 253368 -406 354208 270548 -408 422320 287356 -410 466840 303956 -412 500200 321344 -414 524280 342596 -416 521880 363848 -418 515520 385680 -420 480360 407560 -422 431880 429880 -424 376236 461200 -426 326032 481840 -428 283112 500840 -430 246072 528600 -432 214120 552160 -434 165332 552160 -436 132820 547040 -438 119140 501560 -440 102580 413280 -442 92780 363240 -444 81444 282724 -446 76324 237224 -448 67044 173320 -450 62816 103292 -452 58864 62640 -454 53552 36170 -456 49496 30698.8 -458 47496 25886.4 -460 44480 23388.8 -462 41320 20891.2 -464 39807.2 19260.8 -466 37073.2 18142.4 -468 34870.8 17025.6 -470 33209.2 16156.4 -472 31620 15310 -474 30113.6 15048.4 -476 28850.8 14792.8 -478 27718 14657.2 -480 26629.2 14550 -482 25701.6 14881.2 -484 25180.4 15212.4 -486 24669.6 15543.6 -488 24174.8 15898 -490 23684.4 16684 -492 23086.8 17469.6 -494 22457.6 18255.6 -496 21850.4 19041.2 -498 21260 19891.2 -500 20932.8 20862 -502 20596.4 21832.8 -504 20418 22803.6 -506 19946 23774.4 -508 19996 24745.2 -510 20035.2 25773.6 -512 20150.4 26936.8 -514 20429.2 28100 -516 21001.6 29263.2 -518 22509.6 30426.4 -520 24202.4 31589.6 -522 26450.4 32851.2 -524 29269.2 34397.6 -526 32496.4 35944 -528 35990 37490 -530 39956.8 39036.4 -532 43876 40584 -534 46924 42088 -536 49752 43592 -538 51712 45092 -540 53236 46592 -542 53292 48148 -544 52096 49708 -546 49868 51268 -548 46660 52496 -550 43016 53412 -552 39675.2 54080 -554 36815.2 54520 -556 34476.8 54540 -558 33456 54164 -560 32613.2 53788 -562 32620 52276 -564 33915.6 50572 -566 36495.2 48828 -568 40172 46948 -570 44496 45072 -572 49172 43340 -574 53308 41716 -576 55540 40092 -578 54728 38467.6 -580 50104 37020 -582 43304 35676.4 -584 34639.6 34332.8 -586 26600.4 32851.6 -588 19763.2 31075.2 -590 14400.8 28324.4 -592 10468.4 25470 -594 7678.8 22574.8 -596 5683.6 19800 -598 4504.4 17058.4 -600 3200 14677.2 -602 2664 13622.4 -604 2128 12567.6 -606 1789.2 11513.2 -608 1647.6 10477.6 -610 1506 9443.6 -612 1364.4 8591.2 -614 1222.8 7762 -616 1110 7344.8 -618 1026 6927.2 -620 942 6509.6 -622 858 6193.2 -624 774 5906.8 -626 707.6 5620 -628 658.8 5366.8 -630 610 5148.8 -632 561.2 4930.8 -634 512.4 4730.8 -636 478.8 4602.4 -638 460.4 4473.6 -640 442 4345.2 -642 423.6 4216.8 -644 405.2 4088.4 -646 390.4 3965.08 -648 379.2 3857.6 -650 368 3750.12 -652 356.8 3642.64 -654 345.6 3535.16 -656 335.2 3427.68 -658 325.6 3320.2 -660 319.6 3226.56 -662 314 3140.28 -664 308.4 3053.96 -666 302.8 2967.68 -668 298 2881.4 -670 294 2795.12 -672 290 2708.84 -674 285.6 2627.64 -676 282 2554.4 -678 279.2 2481.16 -680 277.6 2407.92 -682 276 2334.68 -684 274.4 2261.48 -686 272.8 2188.24 -688 274.4 2115 -690 276 2051.96 -692 277.6 2000.48 -694 279.2 1949.04 -696 282 1897.56 -698 286 1846.08 -700 290 1794.28 -702 294 1741 -704 298 1687.76 -706 302.8 1634.48 -708 308.4 1583.52 -710 314 1540.48 -712 319.6 1497.4 -714 325.2 1454.36 -716 332 1411.32 -718 340 1368.28 -720 348 1325.88 -722 356 1285.16 -724 364 1244.44 -726 372.4 1203.68 -728 381.2 1152.8 -730 390 1102.2 -732 398.8 1102.2 -734 407.6 1102.2 -736 418.8 1101.76 -738 432.4 1100.48 -740 446 1115.88 -742 459.6 1161.64 -744 473.2 1207.4 -746 487.6 1266.04 -748 502.8 1333.24 -750 518 1405.24 -752 533.2 1515.32 -754 548.4 1541.76 -756 562 1560.48 -758 574 1560.48 -760 586 1548.52 -762 598 1508.44 -764 610 1459.56 -766 622.8 1410.52 -768 636.4 1361.32 -770 650 1311.88 -772 663.6 1262.44 -774 677.2 1213 -776 689.2 1163.56 -778 699.6 1114.8 -780 710 1075.44 -782 720.4 1036.08 -784 730.8 996.72 -786 740 957.36 -788 748 921.8 -790 756 890.8 -792 764 859.8 -794 772 828.8 -796 786.4 802.96 -798 807.2 782.36 -800 816 761.72 -802 828 743.84 -804 836 737.08 -806 844 730.28 -808 856 723.52 -810 864 717.08 -812 872 711.84 -814 880 706.6 -816 887.2 701.32 -818 901.6 696.08 -820 916 693.76 -822 930.4 693.6 -824 944.8 693.48 -826 956.4 693.32 -828 965.2 693.2 -830 974 693.04 -832 982.8 692.92 -834 991.6 692.76 -836 1001.2 692.64 -838 1011.6 692.48 -840 1022 692.36 -842 1032.4 692.2 -844 1042.8 691.96 -846 1050 691.76 -848 1054 691.52 -850 1058 691.32 -852 1062 691.08 -854 1066 690.88 -856 1072.8 690.64 -858 1082.4 692.44 -860 1092 694.32 -862 1101.6 696.2 -864 1111.2 698.04 -866 1118.4 699.92 -868 1123.2 701.8 -870 1128 705.84 -872 1132.8 709.96 -874 1137.6 714.08 -876 1142.8 718.2 -878 1148.4 722.32 -880 1154 726.44 -882 1159.6 729.84 -884 1165.2 733.2 -886 1170 736.6 -888 1174 739.96 -890 1178 743.6 -892 1182 747.24 -894 1186 750.88 -896 1190 754.52 -898 1194 758.16 -900 1198 761.84 -902 1202 765.04 -904 1206 767.44 -906 1209.2 769.8 -908 1211.6 772.16 -910 1214 774.56 -912 1216.4 776.92 -914 1218.8 778.4 -916 1220.8 778.04 -918 1222.4 777.72 -920 1224 777.36 -922 1225.6 777.04 -924 1227.2 776.64 -926 1226.8 772.36 -928 1224.4 768.08 -930 1222 763.84 -932 1219.6 752.28 -934 1217.2 737.56 -936 1215.6 722.88 -938 1214.8 708.16 -940 1214 693.44 -942 1213.2 678.72 -944 1212.4 660.52 -946 1210.4 641.08 -948 1207.2 621.64 -950 1204 602.24 -952 1200.8 583.4 -954 1197.6 568.92 -956 1194 554.48 -958 1190 540.04 -960 1186 525.56 -962 1182 511.12 -964 1178 495.36 -966 1173.2 473.32 -968 1167.6 451.32 -970 1162 429.32 -972 1156.4 415.28 -974 1150.8 402.28 -976 1144 389.288 -978 1136 374.944 -980 1128 359.656 -982 1120 344.372 -984 1112 329.084 -986 1102.4 313.796 -988 1091.2 298.508 -990 1080 283.22 -992 1068.8 267.932 -994 1057.6 252.648 -996 1046.4 237.36 -998 1035.2 222.072 -1000 1024 206.784 \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/mc/dfmanipulations.py b/Modules/Biophotonics/python/iMC/mc/dfmanipulations.py deleted file mode 100644 index 6bb2c76258..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/dfmanipulations.py +++ /dev/null @@ -1,45 +0,0 @@ -''' -Created on Oct 19, 2015 - -@author: wirkert -''' - -from scipy.interpolate import interp1d -import pandas as pd - - -def fold_by_sliding_average(df, window_size): - """take a batch and apply a sliding average with given window size to - the reflectances. - window_size is elements to the left and to the right. - There will be some boundary effect on the edges.""" - # next line does the folding. - df.reflectances = pd.rolling_mean(df.reflectances.T, window_size, - center=True).T - # let's get rid of NaN columns which are created at the boundaries - df.dropna(axis="columns", inplace=True) - return df - - -def switch_reflectances(df, new_wavelengths, new_reflectances): - df.drop(df["reflectances"].columns, axis=1, level=1, inplace=True) - for i, nw in enumerate(new_wavelengths): - df["reflectances", nw] = new_reflectances[:, i] - return df - - -def interpolate_wavelengths(df, new_wavelengths): - """ interpolate image data to fit new_wavelengths. Current implementation - performs simple linear interpolation. Neither existing nor new _wavelengths - need to be sorted. """ - # build an interpolator using the inormation provided by the dataframes - # reflectance column - interpolator = interp1d(df.reflectances.columns.astype(float), - df.reflectances.as_matrix(), assume_sorted=False, - bounds_error=False) - # use this to create new reflectances - new_reflectances = interpolator(new_wavelengths) - # build a new dataframe out of this information and set the original df - # to the new information. This seems hacky, can't it be done easier? - switch_reflectances(df, new_wavelengths, new_reflectances) - return df diff --git a/Modules/Biophotonics/python/iMC/mc/factories.py b/Modules/Biophotonics/python/iMC/mc/factories.py deleted file mode 100644 index dd6c317f9c..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/factories.py +++ /dev/null @@ -1,115 +0,0 @@ -''' -Created on Oct 15, 2015 - -@author: wirkert -''' - -from mc.tissuemodels import AbstractTissue, GenericTissue, PhantomTissue -from mc.batches import AbstractBatch -from mc.batches import GenericBatch, LessGenericBatch, GenericMeanScatteringBatch -from mc.batches import ColonMuscleBatch, ColonMuscleMeanScatteringBatch -from mc.batches import VisualizationBatch, IntralipidPhantomBatch - - -class AbstractMcFactory(object): - ''' - Monte Carlo Factory. - Will create fitting models and batches, dependent on your task - ''' - - def create_tissue_model(self): - return AbstractTissue() - - def create_batch_to_simulate(self): - return AbstractBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class GenericMcFactory(AbstractMcFactory): - - def create_tissue_model(self): - return GenericTissue() - - def create_batch_to_simulate(self): - return GenericBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class LessGenericMcFactory(GenericMcFactory): - - def create_batch_to_simulate(self): - return LessGenericBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class ColonMuscleMcFactory(GenericMcFactory): - - def create_batch_to_simulate(self): - return ColonMuscleBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class GenericMeanScatteringFactory(GenericMcFactory): - - def create_batch_to_simulate(self): - return GenericMeanScatteringBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class ColonMuscleMeanScatteringFactory(GenericMcFactory): - - def create_batch_to_simulate(self): - return ColonMuscleMeanScatteringBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class VisualizationMcFactory(AbstractMcFactory): - - def create_tissue_model(self): - return GenericTissue() - - def create_batch_to_simulate(self): - return VisualizationBatch() - - def __init__(self): - ''' - Constructor - ''' - - -class PhantomFactory(AbstractMcFactory): - - def create_tissue_model(self): - return PhantomTissue() - - def create_batch_to_simulate(self): - return IntralipidPhantomBatch() - - def __init__(self): - ''' - Constructor - ''' diff --git a/Modules/Biophotonics/python/iMC/mc/plot.py b/Modules/Biophotonics/python/iMC/mc/plot.py deleted file mode 100644 index 2706a15c2b..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/plot.py +++ /dev/null @@ -1,43 +0,0 @@ -''' -Created on Oct 16, 2015 - -@author: wirkert -''' - - -import numpy as np -import matplotlib.pyplot as plt - - -class PlotFunctor(object): - """helping functor necessary because we need to save color for plotting""" - - def __init__(self, axes, wavelengths, nr_plot_elements): - self.axes = axes - self.sortedIndices = sorted(range(len(wavelengths)), - key=lambda k: wavelengths[k]) - self.sortedWavelenghts = wavelengths[self.sortedIndices] - self.nr_plot_elements = nr_plot_elements - self.i = 0 - - - def __call__(self, r): - pass - # set color so it slowly moves from blue to red - plt_color = (1. / float(self.nr_plot_elements) * self.i, - 0., - 1. - (1. / float(self.nr_plot_elements) * self.i)) - self.axes.plot(self.sortedWavelenghts, r[self.sortedIndices], "-o", - color=plt_color) - self.i += 1 - return self.i - -def plot(batch, axes=None): - if axes is None: - axes = plt.gca() - - f = PlotFunctor(axes, batch._wavelengths, batch.reflectances.shape[0]) - - np.apply_along_axis(f, - axis=1, - arr=batch.reflectances) diff --git a/Modules/Biophotonics/python/iMC/mc/sim.py b/Modules/Biophotonics/python/iMC/mc/sim.py deleted file mode 100644 index f629a25d99..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/sim.py +++ /dev/null @@ -1,211 +0,0 @@ -''' -Created on Sep 8, 2015 - -This file contains methods which wrap the mcml simulation so it can be -conveniently called from python. One example for a mcml simulation would be -gpumcml: -https://code.google.com/p/gpumcml/ - -@author: wirkert -''' - -import os -import contextlib -import logging - -import subprocess32 - -""" helper method to change to the correct path and back again """ -@contextlib.contextmanager -def cd(newPath): - savedPath = os.getcwd() - os.chdir(newPath) - yield - os.chdir(savedPath) - - -class MciWrapper(object): - ''' - this class provides a wrapper to the mcml monte carlo file. - Its purpose is to create a .mci file which the mcml simulation can use to - create the simulation - ''' - - def set_mci_filename(self, mci_filename): - self.mci_filename = mci_filename - - def set_mco_filename(self, mco_filename): - """path of the mco file. - This can be either a path relative to the mcml executable - or an absolute path. - BUG: it seems that it can only be relative file name - """ - self.mco_filename = mco_filename - - def set_nr_photons(self, nr_photons): - self.nr_photons = nr_photons - - def add_layer(self, n=None, ua=None, us=None, g=None, d=None): - """adds a layer below the currently existing ones. - - Arguments: - n: Refraction index of medium - ua: absorption coefficient [1/m] - us: scattering coefficient [1/m] - g: anisotropy factor - d: thickness of layer [m] - """ - if n is None: - n = 1. - if ua is None: - ua = 0. - if us is None: - us = 0. - if g is None: - g = 1. - if d is None: - d = 500.*10 ** -6 - self.layers.append([n, ua, us, g, d]) - - def set_layer(self, layer_nr, n, ua, us, g, d): - """set a layer with a specific layer_nr (stariting with layer_nr 0). - Note that the layer must already exist, otherwise an error will occure - """ - self.layers[layer_nr] = [n, ua, us, g, d] - - def set_file_version(self, file_version): - self.file_version = file_version - - def set_nr_runs(self, nr_runs): - self.nr_runs = nr_runs - - def set_dz_dr(self, dz, dr): - self.dz = dz - self.dr = dr - - def set_nr_dz_dr_da(self, nr_dz, nr_dr, nr_da): - self.nr_dz = nr_dz - self.nr_dr = nr_dr - self.nr_da = nr_da - - def set_n_medium_above(self, n_above): - self.n_above = n_above - - def set_n_medium_below(self, n_below): - self.n_below = n_below - - def create_mci_file(self): - """this method creates the mci file at the location self.mci_filename""" - open(self.mci_filename, 'a').close() - f = open(self.mci_filename, 'w') - # write general information - f.write(str(self.file_version) + " # file version\n") - f.write(str(self.nr_runs) + " # number of runs\n\n") - # write the data for run - f.write(self.mco_filename + " A # output filename, ASCII/Binary\n") - f.write(str(self.nr_photons) + " # No. of photons\n") - f.write(repr(self.dz) + " " + repr(self.dr) + " # dz, dr\n") - f.write(repr(self.nr_dz) + " " + - repr(self.nr_dr) + " " + - repr(self.nr_da) + " # No. of dz, dr & da.\n\n") - # write layer information - f.write(str(len(self.layers)) + " # No. of layers\n") - f.write("# n mua mus g d # One line for each layer\n") - f.write(repr(self.n_above) + " # n for medium above.\n") - for layer in self.layers: - - # factors (/100.; *100.) to convert to mcml expected units: - f.write("%.3f" % layer[0] + " " + # n - "%.5f" % (layer[1] / 100.) + " " + # ua - "%.5f" % (layer[2] / 100.) + " " + # us - "%.3f" % layer[3] + " " + # g - "%.3f" % (layer[4] * 100.) + "\n") # d - f.write(repr(self.n_below) + " # n for medium below.\n") - f.close() - if not os.path.isfile(self.mci_filename): - raise IOError("input file for monte carlo simulation not " + - "succesfully created") - - def __init__(self): - # set standard parameters - self.file_version = 1.0 - self.nr_photons = 10**6 - self.nr_runs = 1 - self.dz = 0.002 - self.dr = 2 - self.nr_dz = 500 - self.nr_dr = 1 - self.nr_da = 1 - self.n_above = 1.0 - self.n_below = 1.0 - # initialize to 0 layers - self.layers = [] - - -class SimWrapper(object): - - def set_mci_filename(self, mci_filename): - """the full path to the input file. E.g. ./data/my.mci - """ - self.mci_filename = mci_filename - - def set_mcml_executable(self, mcml_executable): - """ the full path of the excutable. E.g. ./mcml/mcml.exe""" - self.mcml_executable = mcml_executable - - def run_simulation(self): - """this method runs a monte carlo simulation""" - mcml_path, mcml_file = os.path.split(self.mcml_executable) - abs_mci_filename = os.path.abspath(self.mci_filename) - # note: the -A option makes gpumcml much faster, but is not available - # in original mcml. Maybe a switch should be introduced here - args = ("./" + mcml_file, "-A", abs_mci_filename) - # switch to folder where mcml resides in and execute it. - with cd(mcml_path): - try: - popen = subprocess32.Popen(args, stdout=subprocess32.PIPE) - popen.wait(timeout=100) - except: - logging.error("couldn't run simulation") - # popen.kill() - - def __init__(self): - pass - - -def get_diffuse_reflectance(mco_filename): - """ - extract reflectance from mco file. - Attention: mco_filename specifies full path. - - Returns: the reflectance - """ - with open(mco_filename) as myFile: - for line in myFile: - if "Diffuse reflectance" in line: - return float(line.split(' ', 1)[0]) - - -def get_specular_reflectance(mco_filename): - """ - extract reflectance from mco file. - Attention: mco_filename specifies full path. - - Returns: the reflectance - """ - with open(mco_filename) as myFile: - for line in myFile: - if "Specular reflectance" in line: - return float(line.split(' ', 1)[0]) - - -def get_total_reflectance(mco_filename): - """ - extract reflectance from mco file. - Attention: mco_filename specifies full path. - - Returns: the reflectance - """ - return get_diffuse_reflectance(mco_filename) + \ - get_specular_reflectance(mco_filename) - diff --git a/Modules/Biophotonics/python/iMC/mc/test/__init__.py b/Modules/Biophotonics/python/iMC/mc/test/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/mc/test/test_dfmanipulations.py b/Modules/Biophotonics/python/iMC/mc/test/test_dfmanipulations.py deleted file mode 100644 index 7e62886813..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/test/test_dfmanipulations.py +++ /dev/null @@ -1,78 +0,0 @@ -''' -Created on Oct 19, 2015 - -@author: wirkert -''' -import unittest - -import numpy as np -from pandas.util.testing import assert_frame_equal - -from mc.batches import ColonMuscleBatch -import mc.dfmanipulations as dfmani - -class Test(unittest.TestCase): - - def setUp(self): - # create a colon batch with 2 samples - self.test_batch = ColonMuscleBatch() - self.test_batch.create_parameters(2) - - # artificially add 10 fake "reflectances" to this batch - # at 10 fake "wavelengths" - WAVELENGHTS = np.linspace(450, 720, 10) - reflectance1 = np.arange(0, 30, 3) - reflectance2 = np.arange(30, 60, 3) - for w in WAVELENGHTS: - self.test_batch.df["reflectances", w] = np.NAN - for r1, r2, w in zip(reflectance1, reflectance2, WAVELENGHTS): - self.test_batch.df["reflectances", w][0] = r1 - self.test_batch.df["reflectances", w][1] = r2 - - # shortcut to dataframe that we are interested in: - self.df = self.test_batch.df - - def test_sliding_average(self): - # by test design folding should not alter elements (only at boundaries, - # which are excluded by array slicing: - expected_elements = self.df.reflectances.iloc[:, 1:-1].copy() - dfmani.fold_by_sliding_average(self.df, 3) - - assert_frame_equal(self.df.reflectances, expected_elements) - - def test_interpolation(self): - new_wavelengths = [465, 615, 555] - - dfmani.interpolate_wavelengths(self.df, new_wavelengths) - - expected = np.array([[1.5, 16.5, 10.5], [31.5, 46.5, 40.5]]) - np.testing.assert_almost_equal(self.df.reflectances.as_matrix(), - expected, - err_msg="test if interpolation " + - "works fine on batches") - - def test_select_n(self): - """ this is less a test and more a showing of how to select n elements - from a dataframe.""" - # draw one sample. Look into documentation for sample to see all the - # options. Sample is quite powerfull. - self.df = self.df.sample(1) - self.assertEqual(self.df.shape[0], 1, - "one sample selected") - - def test_sortout_bands(self): - """ this is less a test and more a showing of how to sortout specific - bands from a dataframe """ - # drop the 510 and 720 nm band - band_names_to_sortout = [510, 720] - self.df.drop(band_names_to_sortout, axis=1, level=1, inplace=True) - - df_r = self.df["reflectances"] - self.assertTrue(not (510 in df_r.columns)) - self.assertTrue(not 720 in df_r.columns) - self.assertTrue(690 in df_r.columns) - - -if __name__ == "__main__": - # import sys;sys.argv = ['', 'Test.testName'] - unittest.main() diff --git a/Modules/Biophotonics/python/iMC/mc/test/test_sim.py b/Modules/Biophotonics/python/iMC/mc/test/test_sim.py deleted file mode 100644 index 313341c081..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/test/test_sim.py +++ /dev/null @@ -1,125 +0,0 @@ -''' -Created on Sep 8, 2015 - -@author: wirkert -''' -import unittest -import filecmp -import os - -from mc.sim import MciWrapper, SimWrapper, \ - get_total_reflectance, get_diffuse_reflectance - - -path_to_gpumcml = "/home/wirkert/workspace/monteCarlo/gpumcml/" + \ - "fast-gpumcml/gpumcml.sm_20" -skip_gpu_tests = not os.path.exists(path_to_gpumcml) - - -class Test(unittest.TestCase): - - def setUp(self): - self.mci_filename = "temp.mci" - self.mco_filename = "temp.mco" - # create a mci_wrapper which shall create a mci file - self.mci_wrapper = MciWrapper() - self.mci_wrapper.set_mci_filename(self.mci_filename) - self.mci_wrapper.set_mco_filename(self.mco_filename) - self.mci_wrapper.set_nr_photons(10 ** 6) - self.mci_wrapper.add_layer(1.0, 2.1, 3.2, 4.3, 5.4) - self.mci_wrapper.add_layer(6.5, 7.8, 8.9, 9.10, 10.11) - self.mci_wrapper.add_layer(100.1001, 101.10001, 102.100001, - 103.1000001, 104.10000001) - self.mci_wrapper.set_layer(1, 1, 1, 1, 1, 1) - # expected mci file - self.correct_mci_filename = "./mc/data/correct.mci" - # path to the externaly installed mcml simulation. This is machine - # dependent. Thus tests depending on the execution of mcml will only - # be performed if this file exists. - # Should the file be located somewhere else on your computer, - # change this path to your actual location. - - def tearDown(self): - os.remove(self.mci_filename) - mcml_path, mcml_file = os.path.split(path_to_gpumcml) - created_mco_file = mcml_path + "/" + self.mco_filename - if os.path.isfile(created_mco_file): - os.remove(created_mco_file) - - def test_mci_wrapper(self): - self.mci_wrapper.create_mci_file() - self.assertTrue(os.path.isfile(self.mci_filename), - "mci file was created") - self.assertTrue(filecmp.cmp(self.mci_filename, - self.correct_mci_filename, shallow=False), - "the written mci file is the same as the stored " + - "reference file") - - @unittest.skipIf(skip_gpu_tests, "skip if gpumcml not installed") - def test_sim_wrapper(self): - mcml_path, mcml_file = os.path.split(path_to_gpumcml) - if os.path.isfile(path_to_gpumcml): - self.mci_wrapper.create_mci_file() - sim_wrapper = SimWrapper() - sim_wrapper.set_mci_filename(self.mci_filename) - sim_wrapper.set_mcml_executable(path_to_gpumcml) - sim_wrapper.run_simulation() - self.assertTrue(os.path.isfile(os.path.join(mcml_path, - self.mco_filename)), - "mco file was created") - - @unittest.skipIf(skip_gpu_tests, "skip if gpumcml not installed") - def test_mci_wrapper_book_example(self): - """see if our result matches the one from - Biomedical Optics - Principles and Imaging - page 55 (Table 3.1)""" - # create a book_p55_mci which shall create a mci file - book_p55_mci = MciWrapper() - book_p55_mci.set_mci_filename(self.mci_filename) - book_p55_mci.set_mco_filename(self.mco_filename) - book_p55_mci.set_nr_photons(10**6) - book_p55_mci.add_layer(1, 1000, 9000, 0.75, 0.0002) - - mcml_path, mcml_file = os.path.split(path_to_gpumcml) - if os.path.isfile(path_to_gpumcml): - book_p55_mci.create_mci_file() - sim_wrapper = SimWrapper() - sim_wrapper.set_mci_filename(self.mci_filename) - sim_wrapper.set_mcml_executable(path_to_gpumcml) - sim_wrapper.run_simulation() - self.assertTrue(os.path.isfile(mcml_path + "/" + self.mco_filename), - "mco file was created") - refl = get_diffuse_reflectance(os.path.join(mcml_path, - self.mco_filename)) - self.assertAlmostEqual(refl, 0.09734, 3, - "correct reflectance determined " + - "according to book table 3.1") - - @unittest.skipIf(skip_gpu_tests, "skip if gpumcml not installed") - def test_mci_wrapper_book_example_2(self): - """see if our result matches the one from - Biomedical Optics - Principles and Imaging - page 56 (Table 3.2)""" - # create a book_p56_mci which shall create a mci file - book_p56_mci = MciWrapper() - book_p56_mci.set_mci_filename(self.mci_filename) - book_p56_mci.set_mco_filename(self.mco_filename) - book_p56_mci.set_nr_photons(10**6) - book_p56_mci.add_layer(1.5, 1000, 9000, 0., 1) - - mcml_path, mcml_file = os.path.split(path_to_gpumcml) - if os.path.isfile(path_to_gpumcml): - book_p56_mci.create_mci_file() - sim_wrapper = SimWrapper() - sim_wrapper.set_mci_filename(self.mci_filename) - sim_wrapper.set_mcml_executable(path_to_gpumcml) - sim_wrapper.run_simulation() - self.assertTrue(os.path.isfile(mcml_path + "/" + self.mco_filename), - "mco file was created") - refl = get_total_reflectance(os.path.join(mcml_path, - self.mco_filename)) - self.assertAlmostEqual(refl, 0.26, delta=0.01, - msg="correct reflectance determined " + - "according to book table 3.2") diff --git a/Modules/Biophotonics/python/iMC/mc/test/test_tissuemodels.py b/Modules/Biophotonics/python/iMC/mc/test/test_tissuemodels.py deleted file mode 100644 index bd708c2fe7..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/test/test_tissuemodels.py +++ /dev/null @@ -1,50 +0,0 @@ -''' -Created on Sep 9, 2015 - -@author: wirkert -''' - -import unittest -import filecmp -import os - -from mc.tissuemodels import GenericTissue - -this_dir, this_filename = os.path.split(__file__) -DATA_PATH = os.path.join(this_dir, "..", "data") - - -class TestTissueModels(unittest.TestCase): - - def setUp(self): - self.mci_filename = "temp.mci" - self.mco_filename = "temp.mco" - # in this file we stored the expected result created from the - # "old" implementation of our algorithm: - self.correct_mci_filename = os.path.join(DATA_PATH, "colon_default.mci") - - def tearDown(self): - os.remove(self.mci_filename) - - def test_tissue_model(self): - # create nice colon model - tissue = GenericTissue(nr_layers=2) - tissue.set_mci_filename(self.mci_filename) - tissue.set_mco_filename(self.mco_filename) - tissue.wavelength = 500. * 10 ** -9 - # just use the default parameters for this test - # now create the simulation file - tissue.create_mci_file() - # and assert its correct - self.assertTrue(os.path.isfile(self.mci_filename), - "mci file was created") - self.assertTrue(filecmp.cmp(self.mci_filename, - self.correct_mci_filename, - shallow=False), - "the written mci file is the same as the stored " + - "reference file") - - -if __name__ == "__main__": - # import sys;sys.argv = ['', 'Test.testName'] - unittest.main() diff --git a/Modules/Biophotonics/python/iMC/mc/test/test_ua.py b/Modules/Biophotonics/python/iMC/mc/test/test_ua.py deleted file mode 100644 index d29f2f5f4c..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/test/test_ua.py +++ /dev/null @@ -1,40 +0,0 @@ -''' -Created on Sep 8, 2015 - -@author: wirkert -''' - -import unittest - -from mc.usuag import Ua - -class test_ua(unittest.TestCase): - - def setUp(self): - self.ua_l2 = Ua() - self.ua532 = self.ua_l2(532.*10 ** -9) / 100. - self.ua800 = self.ua_l2(800.*10 ** -9) / 100. - - def test_uA532(self): - self.assertTrue(3. < self.ua532 < 4., "test if calculated ua_l2 takes " + - "reasonable values " + - "(according to \"Determination of optical" + - " properties of normal and adenomatous human colon " + - "tissues in vitro using integrating sphere " + - "techniques\")") - - def test_uA800(self): - self.assertTrue(0.05 < self.ua800 < 0.15, "test if calculated ua_l2 " + - "takes reasonable values " + - "(according to \"Differences in" + - " optical properties between healthy and " + - "pathological human colon tissues using a Ti:sapphire" + - " laser: an in vitro study using the Monte Carlo " + - "inversion technique\")") - - def test_saO2_makes_difference(self): - self.ua_l2.saO2 = 1.0 - self.assertNotAlmostEqual(self.ua532, - self.ua_l2(532.*10 ** -9) / 100., - msg="changing oxygenation changes result") - diff --git a/Modules/Biophotonics/python/iMC/mc/test/test_usg.py b/Modules/Biophotonics/python/iMC/mc/test/test_usg.py deleted file mode 100644 index 2af36b493c..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/test/test_usg.py +++ /dev/null @@ -1,26 +0,0 @@ -''' -Created on Oct 23, 2015 - -@author: wirkert -''' -import unittest - -from mc.usuag import UsgJacques - - -class TestUs(unittest.TestCase): - - def setUp(self): - self.usg = UsgJacques() - - def test_no_rayleigh_high_wavelengths(self): - self.usg.a_ray = 2.*100 - self.usg.a_mie = 20.*100 - w = 500. * 10 ** -9 - print self.usg(w)[0] / 100. - # todo write test - - -if __name__ == "__main__": - # import sys;sys.argv = ['', 'Test.testName'] - unittest.main() diff --git a/Modules/Biophotonics/python/iMC/mc/tissuemodels.py b/Modules/Biophotonics/python/iMC/mc/tissuemodels.py deleted file mode 100644 index f6a31821c1..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/tissuemodels.py +++ /dev/null @@ -1,149 +0,0 @@ -''' -Created on Sep 9, 2015 - -@author: wirkert -''' - -import numpy as np - -from mc.sim import MciWrapper -from mc.usuag import Ua, UsgJacques, UsgIntralipid - - -class AbstractTissue(object): - ''' - Initializes a abstract tissue model" - ''' - - def set_nr_photons(self, nr_photons): - self._mci_wrapper.set_nr_photons(nr_photons) - - def set_mci_filename(self, mci_filename): - self._mci_wrapper.set_mci_filename(mci_filename) - - def set_mco_filename(self, mco_filename): - self._mci_wrapper.set_mco_filename(mco_filename) - - def get_mco_filename(self): - return self._mci_wrapper.mco_filename - - def set_wavelength(self, wavelength): - self.wavelength = wavelength - - def create_mci_file(self): - # set layers - for i, ua in enumerate(self.uas): - self._mci_wrapper.set_layer(i, # layer nr - self.ns[i], # refraction index - self.uas[i](self.wavelength), # ua - self.usgs[i](self.wavelength)[0], # us - self.usgs[i](self.wavelength)[1], # g - self.ds[i]) # d - # now that the layers have been updated: create file - self._mci_wrapper.create_mci_file() - - def __str__(self): - """ Overwrite this method! - print the current model""" - model_string = "" - return model_string - - def __init__(self, ns, uas, usgs, ds): - self._mci_wrapper = MciWrapper() - - self.wavelength = 500.*10**9 # standard wavelength, should be set. - self.uas = uas - self.usgs = usgs - self.ds = ds - self.ns = ns - # initially create layers. these will be overwritten as soon - # as create_mci_file is called. - for i in enumerate(uas): - self._mci_wrapper.add_layer() - - -class GenericTissue(AbstractTissue): - ''' - Initializes a 3-layer generic tissue model - ''' - - def set_dataframe_row(self, df_row): - """take one example (one row) of a created batch and set the tissue to - resemble the structure specified by this row - - Args: - df_row: one row of a dataframe created by a batch.""" - layers = [l for l in df_row.index.levels[0] if "layer" in l] - for i, l in enumerate(layers): - self.set_layer(i, - df_row[l, "vhb"], - df_row[l, "sao2"], - df_row[l, "a_mie"], - df_row[l, "b_mie"], - df_row[l, "d"], - df_row[l, "n"], - df_row[l, "g"]) - - def set_layer(self, layer_nr=0, - bvf=None, saO2=None, a_mie=None, b_mie=None, d=None, - n=None, g=None): - """Helper function to set one layer.""" - if bvf is None: - bvf = 0.02 - if saO2 is None: - saO2 = 0.7 - if a_mie is None: - a_mie = 10. * 100 - if d is None: - d = 500. * 10 ** -6 - if b_mie is None: - b_mie = 1.286 - if n is None: - n = 1.38 - if g is None: - g = 0. - # build obejct for absorption coefficient determination - self.uas[layer_nr].bvf = bvf - self.uas[layer_nr].saO2 = saO2 - # and one for scattering coefficient - self.usgs[layer_nr].a_mie = a_mie - self.usgs[layer_nr].a_ray = 0. - self.usgs[layer_nr].b_mie = b_mie - self.usgs[layer_nr].g = g - self.ds[layer_nr] = d - self.ns[layer_nr] = n - - def __str__(self): - """print the current model""" - model_string = "" - for i, ua in enumerate(self.uas): - layer_string = "layer " + str(i) + \ - " - vhb: " + "%.1f" % (self.uas[i].bvf * 100.) + \ - "%; sao2: " + "%.1f" % (self.uas[i].saO2 * 100.) + \ - "%; a_mie: " + "%.2f" % (self.usgs[i].a_mie / 100.) + \ - "cm^-1; a_ray: " + "%.2f" % (self.usgs[i].a_ray / 100.) + \ - "cm^-1; b_mie: " + "%.3f" % self.usgs[i].b_mie + \ - "; d: " + "%.0f" % (self.ds[i] * 10 ** 6) + "um" + \ - "; n: " + "%.2f" % (self.ns[i]) + \ - "; g: " + "%.2f" % self.usgs[i].g + "\n" - model_string += layer_string - return model_string - - def __init__(self, nr_layers=3): - uas = [] - usgs = [] - for i in range(nr_layers): - uas.append(Ua()) - usgs.append(UsgJacques()) - ds = np.ones(nr_layers, dtype=float) * 500.*10 ** -6 - ns = np.ones(nr_layers, dtype=float) * 1.38 - super(GenericTissue, self).__init__(ns, uas, usgs, ds) - - -class PhantomTissue(GenericTissue): - - def __init__(self, nr_layers=1): - super(PhantomTissue, self).__init__(nr_layers=1) - self.usgs = [UsgIntralipid()] - - diff --git a/Modules/Biophotonics/python/iMC/mc/usuag.py b/Modules/Biophotonics/python/iMC/mc/usuag.py deleted file mode 100644 index d60d8173f6..0000000000 --- a/Modules/Biophotonics/python/iMC/mc/usuag.py +++ /dev/null @@ -1,217 +0,0 @@ -''' -Created on Sep 8, 2015 - -@author: wirkert -''' - -import math -import os - -import numpy as np -from scipy.interpolate import interp1d - - -this_dir, this_filename = os.path.split(__file__) -DATA_PATH = os.path.join(this_dir, "data") - -def get_haemoglobin_extinction_coefficients(reference_filename=None): - """ - helper method to get reference data for eHbO2 and eHb from Scott Prahls - reference file: - http://omlc.org/spectra/hemoglobin/summary.html - """ - if reference_filename is None: - reference_filename = os.path.join(DATA_PATH, "haemoglobin.txt") - # table with wavelength at 1st row, - # HbO2 molar extinction coefficient [cm**-1/(moles/l)] at 2nd row, - # Hb molar extinction coefficient [cm**-1/(moles/l)] at 3rd row - haemoLUT = np.loadtxt(reference_filename, skiprows=2) - # we calculate everything in [m] instead of [nm] and [1/cm] - haemoLUT[:, 0] = haemoLUT[:, 0] * 10 ** -9 - haemoLUT[:, 1:] = haemoLUT[:, 1:] * 10 ** 2 - # get the data into an interpolation map for oxy and deoxy haemoglobin - eHbO2 = interp1d(haemoLUT[:, 0], haemoLUT[:, 1]) - eHb = interp1d(haemoLUT[:, 0], haemoLUT[:, 2]) - return eHbO2, eHb - - -def get_beta_carotin_extinction_coefficients(reference_filename=None): - """ - Reference data taken from - http://omlc.org/spectra/PhotochemCAD/data/041-abs.txt - """ - if reference_filename is None: - reference_filename = os.path.join(DATA_PATH, "beta_carotin.txt") - # table with wavelength at 1st row, - # beta carotin molar extinction coefficient [cm**-1/(M)] - betaLUT = np.loadtxt(reference_filename, skiprows=2) - # we calculate everything in [m] instead of [nm] and [1/cm] - betaLUT[:, 0] = betaLUT[:, 0] * 10 ** -9 - betaLUT[:, 1:] = betaLUT[:, 1:] * 10 ** 2 - # get the data into an interpolation map - eBc = interp1d(betaLUT[:, 0], betaLUT[:, 1], bounds_error=False, - fill_value=0.) - return eBc - - -def get_bilirubin_extinction_coefficients(reference_filename=None): - """ - Reference data taken from - http://omlc.org/spectra/PhotochemCAD/data/041-abs.txt - """ - if reference_filename is None: - reference_filename = os.path.join(DATA_PATH, "bilirubin.txt") - # table with wavelength at 1st row, - # beta carotin molar extinction coefficient [cm**-1/(M)] - biliLUT = np.loadtxt(reference_filename, skiprows=2) - # we calculate everything in [m] instead of [nm] and [1/cm] - biliLUT[:, 0] = biliLUT[:, 0] * 10 ** -9 - biliLUT[:, 1:] = biliLUT[:, 1:] * 10 ** 2 - # get the data into an interpolation map - eBili = interp1d(biliLUT[:, 0], biliLUT[:, 1], bounds_error=False, - fill_value=0.) - return eBili - - -class Ua(object): - - def __init__(self): - self.bvf = 0.02 # % - self.cHb = 120. # g*Hb/l - self.saO2 = 0. # % - self.eHbO2, self.eHb = \ - get_haemoglobin_extinction_coefficients() - - self.cBetaCarotinUgProDl = 0. # 2000. - # g / l - self.cBili = 0. # 1.23 * 10 ** -2 - self.eBc = get_beta_carotin_extinction_coefficients() - self.eBili = get_bilirubin_extinction_coefficients() - - - def __call__(self, wavelength): - """ determine ua [1/m] as combination of - Haemoglobin extinction coefficients. - For more on this equation, please refer to - http://omlc.org/spectra/hemoglobin/ - """ - ua_haemoglobin = math.log(10) * self.cHb * \ - (self.saO2 * self.eHbO2(wavelength) + - (1 - self.saO2) * self.eHb(wavelength)) \ - / 64500. * self.bvf - ua_bilirubin = math.log(10) * self.cBili / 574.65 * \ - self.eBili(wavelength) - # second line is to convert from ug/dl to g/ mole - ua_beta_carotin = math.log(10) * self.cBetaCarotinUgProDl / \ - 536.8726 * 10 ** -5 * \ - self.eBc(wavelength) - - return ua_haemoglobin + ua_bilirubin + ua_beta_carotin - - -class UaMuscle(): - """helper class for setting ua in muscle layer. - for ua_sm in the muscle layer we don't use mie theory but the - approximation presented in - Rowe et al. - "Modelling and validation of spectral reflectance for the colon" - calculated to retrieve an absorption of 11.2 cm-1 at 515nm - """ - def __init__(self): - self.ua = Ua() - - def __call__(self, wavelength): - A = 1.7923385088285804 - self.ua.bvf = 0.1 * A - self.ua.saO2 = 0.7 - self.ua.cHb = 120. - return self.ua(wavelength) - - -class UsgJacques(object): - - def __init__(self): - """ - To be set externally: - - a': - """ - self.a_ray = 0. * 100. - self.a_mie = 20. * 100. - self.b_mie = 1.286 - self.g = 0. - - def __call__(self, wavelength): - """ - Calculate the scattering parameters relevant for monte carlo simulation. - - Uses equation (2) from: Optical properties of biological tissues: - a Review - - Args - ____ - wavelength: - wavelength of the incident light [m] - - Returns: - ____ - (us, g) - scattering coefficient us [1/m] and anisotropy factor g - """ - norm_wavelength = (wavelength / (500 * 10 ** -9)) - - us_ray = self.a_ray * norm_wavelength ** (-4) - us_mie = self.a_mie * norm_wavelength ** (-self.b_mie) - - us_prime = (us_ray + us_mie) # * 100. to convert to m^-1 - # actually we calculated the reduced scattering coefficent, so - # assume g is 0 - us = us_prime / (1 - self.g) - - return us, self.g - - -class UsGMuscle(object): - """helper object for setting us in muscle layer. - for us in the muscle layer we don't use mie theory but the - approximation presented in - Rowe et al. - "Modelling and validation of spectral reflectance for the colon" - """ - - def __init__(self): - pass - - - def __call__(self, wavelength): - us = 168.52 * (wavelength * 10 ** 9) ** -0.332 / (1. - 0.96) * 100. - g = 0.96 - return us, g - - -class UsgIntralipid(object): - """helper object for setting us and g in intralipid - We use the formulas from - http://omlc.org/spectra/intralipid/ to calculate - """ - - def __init__(self): - self.a_ray = 0. * 100. - self.a_mie = 20. * 100. - self.b_mie = 2.33 - self.g = 0.85 - - def __call__(self, wavelength): - - norm_wavelength = (wavelength / (500 * 10 ** -9)) - - us_ray = self.a_ray * norm_wavelength ** (-4) - us_mie = self.a_mie * norm_wavelength ** (-self.b_mie) - - us_prime = (us_ray + us_mie) # * 100. to convert to m^-1 - - g = 2.25 * (wavelength * 10**9)**-0.155 - - us = us_prime / (1 - g) - - return us, g diff --git a/Modules/Biophotonics/python/iMC/msi/__init__.py b/Modules/Biophotonics/python/iMC/msi/__init__.py deleted file mode 100644 index 0e9a801a5f..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 15:54:35 2015 - -@author: wirkert -""" - diff --git a/Modules/Biophotonics/python/iMC/msi/data/Transmission_15-49-35-978_filter700nm.txt b/Modules/Biophotonics/python/iMC/msi/data/Transmission_15-49-35-978_filter700nm.txt deleted file mode 100755 index 5f619b446a..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/data/Transmission_15-49-35-978_filter700nm.txt +++ /dev/null @@ -1,2064 +0,0 @@ -Data from Transmission_15-49-35-978.txt Node - -Date: Mon Jun 01 15:49:35 CEST 2015 -User: thomaskirchnerbackup -Spectrometer: HR+C3363 -Autoset integration time: false -Trigger mode: 0 -Integration Time (sec): 1.600000E-2 -Scans to average: 1 -Electric dark correction enabled: true -Nonlinearity correction enabled: false -Boxcar width: 0 -XAxis mode: Wavelengths -Stop averaging: false -Number of Pixels in Spectrum: 2048 ->>>>>Begin Spectral Data<<<<< -187.255 70.50 -187.731 70.51 -188.206 70.51 -188.682 -0 -189.158 303.75 -189.634 135.85 -190.109 109.35 -190.585 9.89 -191.061 5400 -191.536 -476.47 -192.012 17100 -192.488 -54 -192.963 46.61 -193.439 -211.22 -193.914 114.18 -194.389 225 -194.865 137.65 -195.34 270 -195.816 -8100 -196.291 407.81 -196.766 -276.92 -197.242 51.43 -197.717 591.43 -198.192 -140.63 -198.667 135 -199.142 161.8 -199.618 -990 -200.093 139.75 -200.568 2.79 -201.043 -794.12 -201.518 101.61 -201.993 -50.4 -202.468 -3.35 -202.943 90 -203.418 -252.34 -203.893 -42.35 -204.368 112.5 -204.842 100.41 -205.317 331.58 -205.792 -203.77 -206.267 -900 -206.741 43.55 -207.216 -488.57 -207.691 69.74 -208.165 33.51 -208.64 276.92 -209.115 135 -209.589 33.51 -210.064 100.49 -210.538 -10800 -211.013 -0 -211.487 -144 -211.962 0 -212.436 185.05 -212.91 172.6 -213.385 14.33 -213.859 103.85 -214.333 96.43 -214.808 -582.35 -215.282 12600 -215.756 39.01 -216.23 -24.11 -216.704 -380.77 -217.178 40.15 -217.653 264.71 -218.127 11700 -218.601 -93.6 -219.075 81.82 -219.549 -14400 -220.023 308.22 -220.496 22.84 -220.97 -29.14 -221.444 -121.35 -221.918 -38.63 -222.392 28.72 -222.866 1800 -223.339 102.27 -223.813 106.21 -224.287 63.22 -224.76 -203.77 -225.234 -1042.11 -225.708 -38.79 -226.181 5.92 -226.655 94.41 -227.128 -138.46 -227.602 -43.9 -228.075 -26.21 -228.549 623.08 -229.022 56.25 -229.496 -25.23 -229.969 46.61 -230.442 119.58 -230.916 270 -231.389 26.87 -231.862 -787.5 -232.335 -0 -232.809 431.51 -233.282 -203.23 -233.755 14.06 -234.228 134.16 -234.701 -101.12 -235.174 76.34 -235.647 70.39 -236.12 43.71 -236.593 -32.37 -237.066 190.68 -237.539 210.28 -238.012 210.94 -238.485 14.34 -238.958 57.94 -239.43 308.57 -239.903 -55.1 -240.376 168.75 -240.849 321.43 -241.321 360 -241.794 -7.09 -242.267 -110.2 -242.739 30.58 -243.212 -31.03 -243.684 5.29 -244.157 -39.13 -244.629 9.57 -245.102 -1136.84 -245.574 -152.83 -246.047 -18.48 -246.519 0 -246.992 27.95 -247.464 -38.03 -247.936 8.74 -248.408 -371.74 -248.881 90 -249.353 2.51 -249.825 72.69 -250.297 157.98 -250.769 340.54 -251.242 -18.37 -251.714 -25.1 -252.186 163.64 -252.658 -668.57 -253.13 43.09 -253.602 -105.88 -254.074 29.89 -254.546 78.88 -255.017 22.31 -255.489 43.69 -255.961 27.36 -256.433 23.68 -256.905 -87.38 -257.377 29.03 -257.848 101.61 -258.32 -232.26 -258.792 -23.14 -259.263 225 -259.735 67.16 -260.206 -562.5 -260.678 450 -261.15 -16200 -261.621 104.13 -262.093 -100.93 -262.564 33.75 -263.035 119.74 -263.507 128.57 -263.978 43.71 -264.449 810 -264.921 72.97 -265.392 63 -265.863 474.55 -266.335 65.77 -266.806 26.03 -267.277 56.25 -267.748 -3600 -268.219 43.49 -268.69 64.29 -269.161 -411.43 -269.632 -41.12 -270.103 50.28 -270.574 43.9 -271.045 -373.58 -271.516 -15.08 -271.987 64.75 -272.458 60.27 -272.929 59.21 -273.4 -63.38 -273.87 741.18 -274.341 6.92 -274.812 -112.5 -275.282 12.16 -275.753 38.3 -276.224 124.14 -276.694 -578.57 -277.165 -33.96 -277.636 234.78 -278.106 3.86 -278.577 -48.65 -279.047 29.61 -279.517 -22.84 -279.988 -87.31 -280.458 11.16 -280.929 -10800 -281.399 -265.91 -281.869 -55.9 -282.34 246.58 -282.81 -37.76 -283.28 -388.64 -283.75 60.45 -284.22 -14.36 -284.691 -257.14 -285.161 102.27 -285.631 20.07 -286.101 168.75 -286.571 116.52 -287.041 67.92 -287.511 19.42 -287.981 -173.08 -288.451 84.37 -288.921 69.23 -289.39 -3.72 -289.86 0 -290.33 7.17 -290.8 21.6 -291.27 31500 -291.739 -102.27 -292.209 52.94 -292.679 20.22 -293.148 112.5 -293.618 49.54 -294.088 87.91 -294.557 55.45 -295.027 114.89 -295.496 900 -295.966 12.05 -296.435 -59.21 -296.904 331.58 -297.374 178.02 -297.843 -220.41 -298.313 -246.77 -298.782 450 -299.251 128.57 -299.72 11.25 -300.19 23.14 -300.659 44.55 -301.128 69.23 -301.597 -58.24 -302.066 -25.35 -302.535 19.78 -303.004 -60.67 -303.473 86.3 -303.942 293.48 -304.411 1125 -304.88 12.23 -305.349 -21.18 -305.818 121.62 -306.287 215.22 -306.756 -11.84 -307.225 60.34 -307.693 29.51 -308.162 37.89 -308.631 -37.76 -309.1 17.82 -309.568 68.82 -310.037 59.58 -310.506 81.38 -310.974 21.18 -311.443 105.08 -311.911 -8.85 -312.38 -115.2 -312.848 37.67 -313.317 63.38 -313.785 109.35 -314.254 21.11 -314.722 -43.2 -315.19 245.45 -315.659 -81.82 -316.127 258.9 -316.595 -16.77 -317.063 476.47 -317.532 -33.75 -318 63.53 -318.468 11.16 -318.936 101.61 -319.404 48.91 -319.872 0 -320.34 44.72 -320.808 -26.87 -321.276 71.05 -321.744 -92.52 -322.212 53.31 -322.68 16200 -323.148 -715.91 -323.616 214.68 -324.083 107.52 -324.551 3.14 -325.019 15.95 -325.487 -209.48 -325.954 11.18 -326.422 -18.6 -326.89 -101.61 -327.357 288 -327.825 120.47 -328.292 85.04 -328.76 -65.67 -329.228 -45.69 -329.695 -35.53 -330.162 -303.75 -330.63 0 -331.097 0 -331.565 41.54 -332.032 0 -332.499 -86.17 -332.967 52.43 -333.434 41.54 -333.901 246.77 -334.368 12.05 -334.835 83.01 -335.303 101.41 -335.77 -25.9 -336.237 296.34 -336.704 19.1 -337.171 -47.37 -337.638 -80.9 -338.105 27.41 -338.572 62.23 -339.039 -50.7 -339.506 64.73 -339.973 0 -340.439 -172.8 -340.906 -100.49 -341.373 -26.39 -341.84 34.24 -342.307 1440 -342.773 41.31 -343.24 6.54 -343.707 48.18 -344.173 -21.69 -344.64 -52.65 -345.106 12.23 -345.573 68.3 -346.039 -12.16 -346.506 33.4 -346.972 -20.66 -347.439 60.7 -347.905 13.35 -348.372 -1.5 -348.838 22.62 -349.304 58.7 -349.77 -16.32 -350.237 -14.32 -350.703 -42.57 -351.169 16.71 -351.635 10.62 -352.102 5.62 -352.568 -12.53 -353.034 7.15 -353.5 -6.18 -353.966 -37.23 -354.432 1.27 -354.898 17.31 -355.364 -65.77 -355.83 -25.55 -356.296 -26.71 -356.762 -7.26 -357.227 2.74 -357.693 9.59 -358.159 3.23 -358.625 -9.59 -359.09 -10.49 -359.556 7.01 -360.022 9.83 -360.488 9.76 -360.953 -9.1 -361.419 -7.91 -361.884 4.83 -362.35 4.13 -362.815 -0.86 -363.281 10.41 -363.746 -1.98 -364.212 -5.27 -364.677 0 -365.143 12.01 -365.608 0 -366.073 -9.66 -366.539 -1.3 -367.004 6.13 -367.469 13.65 -367.934 -8.58 -368.399 4.52 -368.865 0 -369.33 -4.49 -369.795 -10.07 -370.26 3.41 -370.725 -1.21 -371.19 6.18 -371.655 13.9 -372.12 8.63 -372.585 -7.93 -373.05 -1.84 -373.515 -3.98 -373.979 5.92 -374.444 2.8 -374.909 -7.58 -375.374 -0.98 -375.839 10.89 -376.303 4.17 -376.768 8.22 -377.233 0.44 -377.697 15.92 -378.162 -15.93 -378.626 -3.97 -379.091 -1.29 -379.556 -0.49 -380.02 -6.48 -380.485 -7.32 -380.949 0 -381.413 -2.81 -381.878 2.27 -382.342 -0.38 -382.806 4 -383.271 0.75 -383.735 5.76 -384.199 8 -384.663 5.29 -385.128 2.28 -385.592 2.08 -386.056 -5.6 -386.52 5.33 -386.984 6.92 -387.448 -4.68 -387.912 -8.79 -388.376 -0.71 -388.84 0.93 -389.304 2.74 -389.768 -3.72 -390.232 0.93 -390.696 2.48 -391.16 0 -391.623 -0.89 -392.087 4.05 -392.551 0.51 -393.015 2.94 -393.478 5.03 -393.942 7.63 -394.406 0.73 -394.869 0.47 -395.333 0.52 -395.796 2.78 -396.26 0.51 -396.723 -4.75 -397.187 0 -397.65 0.25 -398.114 2.78 -398.577 -1.45 -399.041 -6.15 -399.504 0 -399.967 1.95 -400.43 2.06 -400.894 -2.95 -401.357 -1.1 -401.82 -1.52 -402.283 2.15 -402.746 -0.86 -403.21 0.95 -403.673 0.42 -404.136 -3.42 -404.599 -1.46 -405.062 -0.79 -405.525 0.59 -405.988 3.17 -406.451 1.14 -406.913 -0.74 -407.376 -2.42 -407.839 3.43 -408.302 2.36 -408.765 1.76 -409.228 0.53 -409.69 -2.5 -410.153 -0.49 -410.616 1.49 -411.078 4.88 -411.541 1.27 -412.004 1.97 -412.466 -1.29 -412.929 -2.17 -413.391 -0.76 -413.854 -1.06 -414.316 0 -414.778 0.3 -415.241 -1.03 -415.703 -0.43 -416.166 0.29 -416.628 -3.02 -417.09 0.71 -417.552 -1.7 -418.015 -0.28 -418.477 -1.05 -418.939 1.9 -419.401 -0.13 -419.863 -1.23 -420.325 1.69 -420.787 0.39 -421.25 0.26 -421.712 -2.89 -422.174 -0.94 -422.635 1.26 -423.097 2.28 -423.559 -0.13 -424.021 2.43 -424.483 -1.65 -424.945 -2.66 -425.407 1.11 -425.868 1.76 -426.33 0.91 -426.792 1.99 -427.254 -1.2 -427.715 -0.59 -428.177 0.68 -428.638 2.35 -429.1 -1.49 -429.562 -0.67 -430.023 -1.57 -430.485 -0.85 -430.946 -0.87 -431.407 2.02 -431.869 -0.51 -432.33 0.61 -432.792 1.65 -433.253 -0.81 -433.714 -3.13 -434.175 0 -434.637 -1.85 -435.098 1.75 -435.559 1.45 -436.02 0 -436.481 -1.51 -436.942 -0.09 -437.404 0.26 -437.865 0.94 -438.326 -0.89 -438.787 -0.44 -439.248 0.51 -439.709 1.08 -440.169 0.57 -440.63 0.17 -441.091 -1.89 -441.552 0.97 -442.013 -1.9 -442.474 -2.27 -442.934 1.11 -443.395 0.81 -443.856 -0.38 -444.316 0.23 -444.777 0.55 -445.238 0.52 -445.698 0.29 -446.159 -0.53 -446.619 0.9 -447.08 2.23 -447.54 -1.09 -448.001 0.89 -448.461 0.51 -448.921 0.66 -449.382 -0.15 -449.842 0 -450.302 -2.32 -450.763 -1.75 -451.223 0.14 -451.683 0.15 -452.143 -0.58 -452.604 0.76 -453.064 -0.49 -453.524 -2.23 -453.984 0 -454.444 -0.07 -454.904 0.47 -455.364 -1.87 -455.824 0.59 -456.284 0.74 -456.744 -0.19 -457.204 -2.07 -457.664 0 -458.123 0.12 -458.583 -0.62 -459.043 -0.74 -459.503 0.18 -459.963 -0.42 -460.422 0.23 -460.882 1.68 -461.342 -0.62 -461.801 -0.45 -462.261 -1.45 -462.72 -0.44 -463.18 0.75 -463.639 -0.21 -464.099 -1.98 -464.558 -0.4 -465.018 -0.1 -465.477 -1.16 -465.936 -0.53 -466.396 0.38 -466.855 -0.38 -467.314 -0.09 -467.774 0 -468.233 -1.23 -468.692 -0.66 -469.151 -1.29 -469.61 -0.79 -470.07 -0.16 -470.529 -0.16 -470.988 0.47 -471.447 0.63 -471.906 0.31 -472.365 -0.44 -472.824 -0.44 -473.283 0 -473.742 0.14 -474.2 -0.03 -474.659 0.03 -475.118 0.07 -475.577 -0.33 -476.036 0.35 -476.494 0.16 -476.953 -0.18 -477.412 0.59 -477.87 -0.55 -478.329 -0.61 -478.788 0.64 -479.246 0.22 -479.705 -0.19 -480.163 -0.21 -480.622 -0.52 -481.08 -0.95 -481.539 -0.32 -481.997 0.19 -482.455 -0.15 -482.914 -0.24 -483.372 -0.36 -483.83 0.05 -484.289 -0.07 -484.747 -0.42 -485.205 -0.18 -485.663 0.02 -486.122 -0.17 -486.58 -0.1 -487.038 -0.25 -487.496 -0.14 -487.954 0.02 -488.412 0.02 -488.87 0.33 -489.328 0.19 -489.786 -0.1 -490.244 0.08 -490.702 -0.21 -491.159 -0.11 -491.617 0.11 -492.075 0.13 -492.533 0.34 -492.991 0.18 -493.448 0.23 -493.906 0.23 -494.364 0.31 -494.821 -0.12 -495.279 0.32 -495.737 0.13 -496.194 0.02 -496.652 0.21 -497.109 0.08 -497.567 -0.23 -498.024 -0.14 -498.481 -0.08 -498.939 0.11 -499.396 -0.06 -499.854 -0.14 -500.311 0.26 -500.768 0.27 -501.225 0.42 -501.683 0.29 -502.14 -0.3 -502.597 -0.22 -503.054 -0.04 -503.511 0.3 -503.968 -0.63 -504.425 -0.24 -504.882 0.19 -505.339 -0.26 -505.796 0.13 -506.253 0 -506.71 0.18 -507.167 0.08 -507.624 0.14 -508.081 0.05 -508.538 0.05 -508.995 -0.15 -509.451 0.04 -509.908 0.2 -510.365 -0.07 -510.821 -0.07 -511.278 -0.16 -511.735 0.03 -512.191 -0.29 -512.648 -0.17 -513.104 0.23 -513.561 0 -514.017 -0.24 -514.474 -0.01 -514.93 0.31 -515.387 0.02 -515.843 0.16 -516.299 -0.07 -516.756 0.12 -517.212 -0.02 -517.668 0.13 -518.125 0.08 -518.581 0.18 -519.037 0.09 -519.493 -0.1 -519.949 0.16 -520.405 0.13 -520.861 0.13 -521.317 0.16 -521.773 -0.02 -522.229 -0.11 -522.685 0.09 -523.141 0.48 -523.597 0.28 -524.053 0.14 -524.509 0.29 -524.965 -0.08 -525.421 -0.02 -525.876 -0.17 -526.332 0.01 -526.788 0.03 -527.244 -0.04 -527.699 -0.1 -528.155 0.05 -528.61 0.03 -529.066 0 -529.522 -0.07 -529.977 -0.14 -530.433 -0.05 -530.888 0.03 -531.344 0.08 -531.799 0.29 -532.254 -0.03 -532.71 -0.08 -533.165 -0.16 -533.62 -0.26 -534.076 -0.3 -534.531 0.03 -534.986 0.1 -535.441 -0.14 -535.897 -0.03 -536.352 0.1 -536.807 0.02 -537.262 0.27 -537.717 -0.1 -538.172 0 -538.627 0.07 -539.082 0.38 -539.537 -0.27 -539.992 -0.1 -540.447 0.04 -540.902 -0.08 -541.356 -0.16 -541.811 0.04 -542.266 0 -542.721 0.05 -543.176 -0.01 -543.63 0.09 -544.085 0.17 -544.54 -0.04 -544.994 -0.05 -545.449 0.08 -545.903 0.01 -546.358 -0.03 -546.812 -0.12 -547.267 -0.12 -547.721 -0.13 -548.176 -0.04 -548.63 0.08 -549.085 -0.07 -549.539 -0.11 -549.993 0.11 -550.448 -0.08 -550.902 -0.01 -551.356 -0.01 -551.81 -0.08 -552.264 -0.14 -552.719 0.13 -553.173 0.1 -553.627 -0.07 -554.081 0.03 -554.535 0.11 -554.989 -0.04 -555.443 0.04 -555.897 0.08 -556.351 0.12 -556.805 -0.06 -557.259 -0.23 -557.712 -0.03 -558.166 0.05 -558.62 0.15 -559.074 -0.31 -559.528 -0.14 -559.981 0.09 -560.435 0.09 -560.889 0.09 -561.342 -0.06 -561.796 0.25 -562.25 -0.1 -562.703 0.15 -563.157 -0.09 -563.61 0.01 -564.064 -0.16 -564.517 -0.14 -564.97 -0.19 -565.424 -0.04 -565.877 -0.2 -566.331 -0.01 -566.784 0.13 -567.237 0.04 -567.69 0.14 -568.144 0.17 -568.597 -0.04 -569.05 -0.07 -569.503 -0.04 -569.956 -0.11 -570.409 0 -570.862 0.06 -571.315 -0.04 -571.768 0.21 -572.221 0.07 -572.674 -0.07 -573.127 0.2 -573.58 -0.02 -574.033 0.08 -574.486 0 -574.939 0.07 -575.392 -0.08 -575.844 0.04 -576.297 0.05 -576.75 -0.15 -577.202 -0.05 -577.655 0.08 -578.108 -0.12 -578.56 -0.1 -579.013 -0.11 -579.465 0.23 -579.918 0.02 -580.37 0.21 -580.823 0.34 -581.275 0.18 -581.728 0.02 -582.18 -0.06 -582.632 0.14 -583.085 -0.13 -583.537 0.06 -583.989 0.02 -584.442 -0.05 -584.894 -0.02 -585.346 -0.03 -585.798 0.08 -586.25 0.05 -586.702 -0.05 -587.155 0.05 -587.607 0.02 -588.059 0.17 -588.511 0.01 -588.963 0.08 -589.415 -0.03 -589.866 0.05 -590.318 0.03 -590.77 0.02 -591.222 -0.02 -591.674 0.06 -592.126 0 -592.577 0.09 -593.029 -0.1 -593.481 0.04 -593.932 0 -594.384 -0.02 -594.836 -0.05 -595.287 0.02 -595.739 -0.11 -596.19 -0.02 -596.642 0.11 -597.093 0.15 -597.545 0.07 -597.996 -0.06 -598.448 0.02 -598.899 -0.04 -599.35 -0.07 -599.802 -0.01 -600.253 0.02 -600.704 -0.06 -601.155 -0.15 -601.607 -0.12 -602.058 -0.11 -602.509 -0.01 -602.96 -0.06 -603.411 0.11 -603.862 0.08 -604.313 0.2 -604.764 -0.06 -605.215 0.02 -605.666 -0.07 -606.117 -0.06 -606.568 0.11 -607.019 -0.13 -607.47 -0.02 -607.921 -0.12 -608.371 -0.23 -608.822 0.02 -609.273 0.06 -609.724 0.13 -610.174 0.08 -610.625 0.11 -611.076 0.06 -611.526 -0.06 -611.977 -0.06 -612.427 -0.02 -612.878 0.08 -613.328 0.01 -613.779 0.04 -614.229 0.05 -614.68 -0.07 -615.13 -0.06 -615.58 -0.15 -616.031 0.01 -616.481 0 -616.931 -0.15 -617.382 -0.12 -617.832 0.01 -618.282 0.17 -618.732 -0.02 -619.182 -0.07 -619.632 -0.28 -620.083 -0.04 -620.533 -0.14 -620.983 0.08 -621.433 0.05 -621.883 0.09 -622.333 0.05 -622.783 -0.11 -623.232 -0.11 -623.682 0.13 -624.132 0.09 -624.582 -0.01 -625.032 -0.08 -625.481 0.11 -625.931 -0.02 -626.381 0.02 -626.831 0 -627.28 0.08 -627.73 0.15 -628.179 -0.16 -628.629 0.02 -629.079 0.14 -629.528 0.08 -629.978 -0.13 -630.427 -0.15 -630.876 0.16 -631.326 0.04 -631.775 0.04 -632.225 0.09 -632.674 -0.07 -633.123 -0.12 -633.573 -0.03 -634.022 -0.05 -634.471 0.13 -634.92 0.17 -635.369 0.01 -635.818 0.01 -636.268 -0.14 -636.717 0.02 -637.166 0.11 -637.615 0.08 -638.064 -0.04 -638.513 -0.13 -638.962 -0.01 -639.411 0.14 -639.859 0.1 -640.308 -0.04 -640.757 0.15 -641.206 0.04 -641.655 -0.14 -642.103 0.01 -642.552 0.04 -643.001 0.07 -643.45 -0.04 -643.898 0.11 -644.347 0 -644.795 0.17 -645.244 0 -645.692 -0.03 -646.141 -0.03 -646.589 -0.07 -647.038 0.18 -647.486 0.03 -647.935 0.08 -648.383 0.11 -648.831 -0.06 -649.28 -0.03 -649.728 0.03 -650.176 -0.05 -650.625 -0.01 -651.073 0.07 -651.521 -0.04 -651.969 0.07 -652.417 0 -652.865 0.04 -653.313 -0.09 -653.761 -0.01 -654.209 0.11 -654.657 0.12 -655.105 0.16 -655.553 -0.13 -656.001 -0.06 -656.449 -0.04 -656.897 -0.06 -657.345 0.12 -657.793 0.06 -658.24 0.03 -658.688 -0.02 -659.136 0.05 -659.584 -0.09 -660.031 -0.05 -660.479 0.11 -660.926 0.17 -661.374 -0.04 -661.822 0.11 -662.269 0.03 -662.717 -0.09 -663.164 0.02 -663.611 0.12 -664.059 0.11 -664.506 0.08 -664.954 -0.03 -665.401 0.05 -665.848 -0.04 -666.296 0.02 -666.743 0.02 -667.19 0.13 -667.637 -0.07 -668.084 -0.06 -668.532 -0.11 -668.979 -0.1 -669.426 -0.03 -669.873 -0.02 -670.32 0.25 -670.767 -0.01 -671.214 -0.02 -671.661 0.22 -672.108 0.21 -672.555 0.14 -673.002 0.23 -673.448 0.15 -673.895 0.16 -674.342 0.04 -674.789 0.17 -675.235 0.12 -675.682 0.19 -676.129 0.03 -676.576 0.37 -677.022 0.15 -677.469 0.16 -677.915 -0.05 -678.362 0.24 -678.808 0.33 -679.255 0.2 -679.701 0.22 -680.148 0.21 -680.594 0.07 -681.041 0.21 -681.487 0.21 -681.933 0.36 -682.38 0.29 -682.826 0.5 -683.272 0.48 -683.718 0.49 -684.165 0.79 -684.611 1.09 -685.057 1.31 -685.503 1.83 -685.949 3.15 -686.395 4.55 -686.841 7.27 -687.287 11.74 -687.733 19.13 -688.179 29.95 -688.625 44.29 -689.071 56.79 -689.517 66.46 -689.963 72.42 -690.408 73.42 -690.854 75.79 -691.3 76.21 -691.746 77.76 -692.191 77.99 -692.637 79.37 -693.083 80.64 -693.528 83.42 -693.974 85.5 -694.419 85.33 -694.865 87.07 -695.311 86.82 -695.756 85.95 -696.201 85.16 -696.647 82.87 -697.092 82.21 -697.538 82.19 -697.983 82.97 -698.428 82.35 -698.874 82.57 -699.319 83.05 -699.764 83.78 -700.209 83.92 -700.655 84.64 -701.1 84.21 -701.545 84.33 -701.99 84.34 -702.435 85.04 -702.88 84.41 -703.325 86.05 -703.77 87.18 -704.215 88.7 -704.66 88.74 -705.105 88.61 -705.55 85.02 -705.995 79.77 -706.44 69.94 -706.884 58.82 -707.329 46.78 -707.774 35.81 -708.219 27.19 -708.663 19.34 -709.108 14.29 -709.553 10.15 -709.997 7.17 -710.442 5.26 -710.886 3.41 -711.331 2.8 -711.775 2.18 -712.22 1.45 -712.664 1.32 -713.109 0.94 -713.553 0.72 -713.998 0.73 -714.442 0.43 -714.886 0.27 -715.331 0.25 -715.775 0.54 -716.219 0.14 -716.663 0.47 -717.107 0.19 -717.552 0.09 -717.996 0.24 -718.44 0.14 -718.884 0.23 -719.328 0.27 -719.772 0.13 -720.216 0.17 -720.66 0.2 -721.104 0.08 -721.548 -0.05 -721.992 0.1 -722.436 0.08 -722.879 0.07 -723.323 0.4 -723.767 0.21 -724.211 0.08 -724.654 0.21 -725.098 0.06 -725.542 -0.13 -725.985 -0.12 -726.429 -0.12 -726.873 0.03 -727.316 0.06 -727.76 0.11 -728.203 0.08 -728.647 -0.01 -729.09 0.05 -729.534 0.09 -729.977 -0.01 -730.42 0.11 -730.864 0.11 -731.307 -0.07 -731.75 -0.11 -732.194 0.02 -732.637 0.01 -733.08 0.28 -733.523 0.24 -733.966 0 -734.41 -0.16 -734.853 0.03 -735.296 -0.11 -735.739 -0.07 -736.182 0.16 -736.625 0.21 -737.068 0.3 -737.511 -0.04 -737.954 -0.09 -738.396 0.19 -738.839 -0.24 -739.282 -0.08 -739.725 -0.15 -740.168 0.16 -740.61 -0.02 -741.053 -0.16 -741.496 0.01 -741.939 0.01 -742.381 0.01 -742.824 -0.13 -743.266 0.1 -743.709 0.27 -744.151 0.05 -744.594 -0.23 -745.036 -0.19 -745.479 0.08 -745.921 -0.12 -746.364 -0.12 -746.806 -0.17 -747.248 0.23 -747.691 0.32 -748.133 -0.11 -748.575 0.12 -749.017 0.06 -749.46 -0.01 -749.902 -0.21 -750.344 0.2 -750.786 -0.33 -751.228 -0.01 -751.67 0.01 -752.112 0.06 -752.554 0.18 -752.996 -0.05 -753.438 0.16 -753.88 -0.27 -754.322 -0.16 -754.764 0.19 -755.206 0.18 -755.648 0.06 -756.09 0.2 -756.531 -0.06 -756.973 0.31 -757.415 0.35 -757.856 -0.08 -758.298 0.32 -758.74 -0.02 -759.181 0.24 -759.623 0.04 -760.065 0.02 -760.506 -0.07 -760.948 -0.06 -761.389 -0.15 -761.83 0.12 -762.272 0.23 -762.713 0.32 -763.155 -0.19 -763.596 -0.45 -764.037 -0.04 -764.479 0.09 -764.92 0.01 -765.361 0.1 -765.802 0.22 -766.243 -0.03 -766.685 0.18 -767.126 -0.05 -767.567 0.53 -768.008 0.1 -768.449 0 -768.89 -0.1 -769.331 0.01 -769.772 -0.26 -770.213 0.14 -770.654 0 -771.095 -0.24 -771.535 0.05 -771.976 0.05 -772.417 0.03 -772.858 0.29 -773.299 -0.08 -773.739 0.01 -774.18 0.25 -774.621 0.39 -775.061 -0.04 -775.502 0.4 -775.942 0.41 -776.383 0.15 -776.824 0 -777.264 0.43 -777.705 0.43 -778.145 -0.07 -778.585 -0.08 -779.026 -0.27 -779.466 -0.03 -779.906 0.4 -780.347 0.03 -780.787 0.01 -781.227 -0.01 -781.668 -0.1 -782.108 0.46 -782.548 0.21 -782.988 0.59 -783.428 0 -783.868 -0.2 -784.308 -0.07 -784.748 -0.01 -785.188 0 -785.628 -0.22 -786.068 0.48 -786.508 0.28 -786.948 0.18 -787.388 -0.16 -787.828 -0.18 -788.268 -0.03 -788.708 0.23 -789.147 0.19 -789.587 0.38 -790.027 0.25 -790.467 0 -790.906 -0.18 -791.346 -0.03 -791.785 0.06 -792.225 -0.57 -792.665 0.2 -793.104 -0.11 -793.544 -0.2 -793.983 0.11 -794.422 0.3 -794.862 -0.11 -795.301 0.38 -795.741 -0.38 -796.18 0.06 -796.619 -0.11 -797.059 -0.1 -797.498 0.11 -797.937 0.08 -798.376 0 -798.815 0.43 -799.255 0.38 -799.694 0.08 -800.133 -0.05 -800.572 -0.49 -801.011 -0.2 -801.45 -0.03 -801.889 -0.03 -802.328 0.24 -802.767 -0.09 -803.206 0.55 -803.645 -0.31 -804.083 0.14 -804.522 0.3 -804.961 0.12 -805.4 -0.36 -805.839 0.14 -806.277 0.14 -806.716 -0.04 -807.155 0.16 -807.593 -0.3 -808.032 0.12 -808.471 -0.18 -808.909 0.29 -809.348 0.45 -809.786 0.09 -810.225 -0.23 -810.663 0.18 -811.101 0.23 -811.54 0.51 -811.978 0 -812.417 0.04 -812.855 0.2 -813.293 0.17 -813.731 -0.09 -814.17 -0.19 -814.608 0.06 -815.046 0.21 -815.484 -0.04 -815.922 -0.04 -816.36 0.1 -816.798 0.02 -817.236 0.35 -817.674 -0.09 -818.112 0 -818.55 0.2 -818.988 -0.08 -819.426 -0.36 -819.864 0 -820.302 0.18 -820.74 -0.22 -821.178 0.12 -821.615 0.1 -822.053 -0.1 -822.491 -0.18 -822.929 0.18 -823.366 0.25 -823.804 0.17 -824.241 0.39 -824.679 0.19 -825.117 0 -825.554 -0.1 -825.992 0.29 -826.429 -0.33 -826.867 0.23 -827.304 0 -827.741 0.34 -828.179 0.58 -828.616 0.11 -829.053 -0.11 -829.491 0.31 -829.928 0.29 -830.365 -0.22 -830.802 -0.13 -831.24 -0.57 -831.677 0.15 -832.114 -0.37 -832.551 0.02 -832.988 0.22 -833.425 0 -833.862 -0.45 -834.299 0.04 -834.736 -0.14 -835.173 -0.09 -835.61 -0.33 -836.047 -0.07 -836.484 0.19 -836.92 0.12 -837.357 -0.09 -837.794 0.35 -838.231 -0.31 -838.668 0.32 -839.104 -0.34 -839.541 0.2 -839.978 0.19 -840.414 -0.25 -840.851 0.1 -841.287 -0.17 -841.724 0.27 -842.16 -0.37 -842.597 -0.27 -843.033 0.3 -843.47 0.55 -843.906 -0.48 -844.342 -0.36 -844.779 -0.38 -845.215 0.66 -845.651 -0.55 -846.088 -0.36 -846.524 -0.03 -846.96 0.34 -847.396 -0.05 -847.832 -0.34 -848.269 0.24 -848.705 -0.71 -849.141 -0.21 -849.577 -0.03 -850.013 0.21 -850.449 -0.03 -850.885 0.08 -851.321 0.64 -851.757 0.68 -852.192 -0.3 -852.628 0.58 -853.064 0.36 -853.5 0.22 -853.936 -0.14 -854.372 0.25 -854.807 0.42 -855.243 0.23 -855.679 -0.06 -856.114 -0.38 -856.55 0.15 -856.985 0.29 -857.421 0.43 -857.857 0.48 -858.292 0.36 -858.728 0.72 -859.163 -0.12 -859.598 0.39 -860.034 0.59 -860.469 0.12 -860.905 -0.24 -861.34 0.9 -861.775 -0.12 -862.21 -0.55 -862.646 -0.24 -863.081 0.09 -863.516 0.62 -863.951 -0.84 -864.386 -0.25 -864.821 0.54 -865.257 0.06 -865.692 -0.03 -866.127 0.06 -866.562 -0.1 -866.997 0.46 -867.432 -0.36 -867.866 -0.3 -868.301 0.27 -868.736 0.48 -869.171 0.07 -869.606 0.03 -870.041 0.77 -870.475 -0.03 -870.91 -0.17 -871.345 0.44 -871.779 0.17 -872.214 -0.53 -872.649 0.14 -873.083 0.11 -873.518 0.04 -873.952 0.07 -874.387 -0.53 -874.821 -0.32 -875.256 -0.14 -875.69 -0.48 -876.125 -0.75 -876.559 0.11 -876.993 1.02 -877.428 -0.11 -877.862 0.22 -878.296 0.68 -878.731 -0.51 -879.165 0.43 -879.599 -1.17 -880.033 -0.11 -880.467 0.07 -880.901 0.56 -881.336 0.19 -881.77 0.8 -882.204 1.04 -882.638 -0.27 -883.072 -0.44 -883.506 0.08 -883.939 0.27 -884.373 0.2 -884.807 -0.12 -885.241 0.6 -885.675 0.28 -886.109 0.19 -886.542 0.87 -886.976 1.75 -887.41 -0.41 -887.844 0.72 -888.277 -0.61 -888.711 0.72 -889.144 0.04 -889.578 0.29 -890.012 0 -890.445 0.21 -890.879 -0.79 -891.312 0.21 -891.745 0.39 -892.179 0.34 -892.612 -0.92 -893.046 0.26 -893.479 0.9 -893.912 -0.49 -894.345 -0.31 -894.779 -0.39 -895.212 0.17 -895.645 0.84 -896.078 -0.18 -896.511 0 -896.945 0 -897.378 -0.09 -897.811 -0.91 -898.244 0.49 -898.677 0.19 -899.11 -0.8 -899.543 -0.09 -899.976 0.65 -900.409 -0.29 -900.841 -0.67 -901.274 -0.24 -901.707 1.15 -902.14 -0.5 -902.573 0.34 -903.005 0.5 -903.438 0.86 -903.871 -0.5 -904.303 -0.1 -904.736 -0.36 -905.169 0.71 -905.601 -0.62 -906.034 0.52 -906.466 -0.11 -906.899 0.89 -907.331 -0.46 -907.764 1.2 -908.196 0.05 -908.629 1.16 -909.061 0.16 -909.493 1.59 -909.926 1.5 -910.358 1.49 -910.79 -0.11 -911.222 2.14 -911.655 0.61 -912.087 -0.18 -912.519 -0.17 -912.951 0.53 -913.383 0.35 -913.815 -0.53 -914.247 -0.24 -914.679 2 -915.111 0.9 -915.543 -1.49 -915.975 -1.89 -916.407 0.55 -916.839 1 -917.271 -0.81 -917.703 -0.7 -918.134 0.19 -918.566 -0.82 -918.998 -0.58 -919.43 0.45 -919.861 0.06 -920.293 -0.13 -920.725 -0.39 -921.156 -0.26 -921.588 0.2 -922.019 0.07 -922.451 0.2 -922.882 0.49 -923.314 0 -923.745 -0.49 -924.177 0.42 -924.608 0.14 -925.039 0.63 -925.471 -3.04 -925.902 0.79 -926.333 -0.29 -926.765 0.52 -927.196 1.22 -927.627 0.36 -928.058 1.38 -928.489 1.27 -928.921 2.33 -929.352 -2.11 -929.783 -1.35 -930.214 -2.41 -930.645 0 -931.076 -0.77 -931.507 1.16 -931.938 1.15 -932.369 0.23 -932.8 -0.39 -933.23 0.16 -933.661 0.88 -934.092 1.68 -934.523 0.16 -934.954 0.41 -935.384 1.2 -935.815 -0.33 -936.246 0.81 -936.676 1.8 -937.107 -1.17 -937.538 -1.4 -937.968 1.54 -938.399 1.7 -938.829 -2.14 -939.26 -0.78 -939.69 -0.53 -940.121 -1.11 -940.551 -2.13 -940.981 0.61 -941.412 -1.23 -941.842 -0.44 -942.272 -0.45 -942.703 -2.33 -943.133 0.18 -943.563 -1.75 -943.993 -2.54 -944.423 0.27 -944.854 -0.85 -945.284 -1.04 -945.714 -0.47 -946.144 0.55 -946.574 0.58 -947.004 0.57 -947.434 1.08 -947.864 1.43 -948.294 0.6 -948.724 -0.42 -949.153 1.04 -949.583 0.82 -950.013 0.11 -950.443 0.11 -950.873 0.92 -951.302 1.37 -951.732 0.43 -952.162 -0.94 -952.591 -1.46 -953.021 2.59 -953.451 -2.59 -953.88 -1.14 -954.31 -0.23 -954.739 -0.12 -955.169 -2.41 -955.598 -1.05 -956.028 0.81 -956.457 -1.19 -956.886 -1.07 -957.316 2.25 -957.745 1.26 -958.174 0.63 -958.604 1.33 -959.033 -1.53 -959.462 -1.52 -959.891 -3.42 -960.321 0 -960.75 2.76 -961.179 3.52 -961.608 -2.31 -962.037 -2.28 -962.466 0.57 -962.895 0.14 -963.324 -0.96 -963.753 1.14 -964.182 0 -964.611 -0.43 -965.04 -4.87 -965.469 2.85 -965.897 -0.29 -966.326 -0.46 -966.755 -0.46 -967.184 2.18 -967.612 1.86 -968.041 -3.15 -968.47 -5.56 -968.898 1.3 -969.327 1.63 -969.756 3.69 -970.184 -0.5 -970.613 -0.16 -971.041 -3.54 -971.47 0.7 -971.898 -0.52 -972.327 1.9 -972.755 0.69 -973.183 -1.22 -973.612 -3.38 -974.04 3.44 -974.468 -2.12 -974.897 -1.66 -975.325 3.9 -975.753 1.33 -976.181 3.11 -976.609 0 -977.037 -2.63 -977.466 -0.81 -977.894 0.81 -978.322 -1.76 -978.75 0.19 -979.178 -0.98 -979.606 -1.1 -980.034 -3.35 -980.462 -1.11 -980.889 6.78 -981.317 -3.81 -981.745 -6.38 -982.173 -0.44 -982.601 1.75 -983.028 3.07 -983.456 3.13 -983.884 -2.93 -984.312 5.23 -984.739 0.25 -985.167 -0.24 -985.594 3.59 -986.022 3.31 -986.45 -7.18 -986.877 0.76 -987.305 0.26 -987.732 -6.62 -988.159 -5.36 -988.587 3.67 -989.014 1.57 -989.442 -2.17 -989.869 -6.23 -990.296 -2.88 -990.724 0.96 -991.151 -1.39 -991.578 -2.61 -992.005 0 -992.432 3.35 -992.859 -9.57 -993.287 4.06 -993.714 -0.94 -994.141 9.31 -994.568 -5.5 -994.995 4.01 -995.422 6.11 -995.849 10.28 -996.276 -0.35 -996.703 4.97 -997.129 2.86 -997.556 5.1 -997.983 0.34 -998.41 4.91 -998.837 4.97 -999.263 -1.38 -999.69 -3.33 -1000.117 -6.12 -1000.543 3.92 -1000.97 -9.06 -1001.397 -1.9 -1001.823 1.28 -1002.25 -2.51 -1002.676 -6.06 -1003.103 -1.61 -1003.529 -6.3 -1003.956 -1.49 -1004.382 0 -1004.809 0.36 -1005.235 3.54 -1005.661 6.18 -1006.088 -5.62 -1006.514 -1.94 -1006.94 -11.56 -1007.366 -3.57 -1007.793 -0.37 -1008.219 -7.33 -1008.645 -5.68 -1009.071 0.42 -1009.497 -11.95 -1009.923 4.68 -1010.349 2.5 -1010.775 4.38 -1011.201 -0.37 -1011.627 0.83 -1012.053 1.3 -1012.479 -6.09 -1012.905 -8.7 -1013.331 4.39 -1013.757 -2.78 -1014.182 -4.7 -1014.608 -5.59 -1015.034 2.86 -1015.46 7.87 -1015.885 2.81 -1016.311 14.54 -1016.737 2.86 -1017.162 1.02 -1017.588 -6.08 -1018.013 -10.6 -1018.439 5.79 -1018.865 3.54 -1019.29 -6.29 -1019.715 -6.88 -1020.141 1.56 -1020.566 -0.58 -1020.992 0.55 -1021.417 2.12 -1021.842 14.08 -1022.268 8.29 -1022.693 0.55 -1023.118 -13.02 -1023.543 4.47 -1023.969 -0.69 -1024.394 0 -1024.819 3.49 -1025.244 -3.87 -1025.669 -20.01 -1026.094 -7.1 -1026.519 7.23 -1026.944 3.64 -1027.369 9.1 -1027.794 7.98 -1028.219 11.93 -1028.644 15.23 -1029.069 -9.57 -1029.494 2.11 -1029.918 9.82 -1030.343 2.82 -1030.768 3.45 -1031.193 -7.7 -1031.617 13.55 -1032.042 -12.28 -1032.467 -13.25 -1032.891 9.24 -1033.316 0.84 -1033.741 -7.04 -1034.165 20.32 -1034.59 31.57 -1035.014 3.97 -1035.439 -6.09 -1035.863 12.65 -1036.288 3.28 -1036.712 2.02 -1037.136 3 -1037.561 -2.94 -1037.985 -6.86 -1038.409 9.1 -1038.834 3.37 -1039.258 12.76 -1039.682 12.08 -1040.106 32.3 -1040.53 -1.87 -1040.954 -24.08 -1041.379 3.85 -1041.803 -1.93 -1042.227 -20.24 -1042.651 15.72 -1043.075 17.92 -1043.499 -5.06 -1043.923 -10.36 -1044.346 -12.13 -1044.77 24.82 -1045.194 -21.95 -1045.618 3.58 -1046.042 16.51 -1046.466 -6.67 -1046.889 20.48 -1047.313 -6.99 -1047.737 15.57 -1048.16 12.78 -1048.584 -26.61 -1049.008 13.94 -1049.431 -13.27 -1049.855 4.12 -1050.278 10.99 -1050.702 20.35 -1051.125 21.65 -1051.549 -1.59 -1051.972 8.34 -1052.396 8.35 -1052.819 2.71 -1053.242 5.37 -1053.666 -20.87 -1054.089 13.2 -1054.512 8.08 -1054.936 -42.45 -1055.359 -22.08 -1055.782 -20.04 -1056.205 6.86 -1056.628 -56.12 -1057.051 -5.14 -1057.475 -5.18 -1057.898 -29.62 -1058.321 -37.82 -1058.744 -18.49 -1059.167 -1.39 -1059.59 -22.43 -1060.012 12.52 -1060.435 -2 -1060.858 17.13 -1061.281 -54.48 -1061.704 -23.87 -1062.127 -2.33 -1062.549 -8.36 -1062.972 8.35 -1063.395 -8.79 -1063.818 0 -1064.24 7.29 -1064.663 -12.27 -1065.086 -17.55 -1065.508 20.67 -1065.931 28.65 -1066.353 -75.74 -1066.776 -62.38 -1067.198 29.03 -1067.621 10.9 -1068.043 -6.16 -1068.465 -7.71 -1068.888 66.86 -1069.31 26.9 -1069.732 12.16 -1070.155 3.14 -1070.577 31.19 -1070.999 -55.31 -1071.421 27.58 -1071.844 0 -1072.266 50.94 -1072.688 -51.92 -1073.11 -12.3 -1073.532 12.16 -1073.954 -56.25 -1074.376 -34.18 -1074.798 27.11 -1075.22 66.89 -1075.642 43.03 -1076.064 -56.57 -1076.486 -16.73 -1076.908 10.76 -1077.33 40.22 -1077.751 342 -1078.173 50.2 -1078.595 40.15 -1079.017 -112.5 -1079.438 -3.35 -1079.86 14.62 -1080.282 42.49 -1080.703 -85.34 -1081.125 -35.5 -1081.546 79.79 -1081.968 -6.92 -1082.39 -192.86 -1082.811 7.16 -1083.232 -13.38 -1083.654 -86.17 -1084.075 -115.2 -1084.497 39.13 -1084.918 51.51 -1085.339 116.38 -1085.761 38.85 -1086.182 -132.17 -1086.603 37.67 -1087.024 -67.16 -1087.446 -194.78 -1087.867 105.88 -1088.288 60.45 -1088.709 -93.1 -1089.13 40.91 -1089.551 5.59 -1089.972 165.79 -1090.393 194.59 -1090.814 9.64 -1091.235 -135.85 -1091.656 120.9 -1092.077 229.09 -1092.498 22.66 -1092.919 89.74 -1093.34 -90 -1093.76 -8.74 -1094.181 -50.94 -1094.602 113.59 -1095.023 151.4 -1095.443 -110.2 -1095.864 267.57 -1096.285 165.31 -1096.705 -109.35 -1097.126 -100.8 -1097.546 52.43 -1097.967 104.85 -1098.387 -152.11 -1098.808 229.09 -1099.228 169.41 -1099.649 68.13 -1100.069 8.6 -1100.49 -36 -1100.91 18.27 -1101.33 201.72 -1101.751 60.34 -1102.171 33.54 -1102.591 13.71 -1103.011 -67.29 -1103.431 3.72 -1103.852 68.13 diff --git a/Modules/Biophotonics/python/iMC/msi/data/testMsi.nrrd b/Modules/Biophotonics/python/iMC/msi/data/testMsi.nrrd deleted file mode 100644 index 82708c6160..0000000000 Binary files a/Modules/Biophotonics/python/iMC/msi/data/testMsi.nrrd and /dev/null differ diff --git a/Modules/Biophotonics/python/iMC/msi/imgmani.py b/Modules/Biophotonics/python/iMC/msi/imgmani.py deleted file mode 100644 index ceb06a581b..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/imgmani.py +++ /dev/null @@ -1,66 +0,0 @@ -''' -Created on Aug 28, 2015 - -@author: wirkert -''' - -import numpy as np - - -def collapse_image(img): - """ helper method which transorms the n x m x nrWavelengths image to a - (n*m) x nrWavelength image. - - note that this function doesn't take an object of class Msi but - msi.get_image() """ - return img.reshape(-1, img.shape[-1]) - - -def remove_masked_elements(img): - """ helper method which removes masked pixels. - Note that by applying this method, the img loses it's shape.""" - collapsed_image = collapse_image(img) - # if one reflectance is masked msis are defined to have all refl. - # masked. Thus we can just have a look at the first column - one_column = collapsed_image[:, 0] - if (isinstance(one_column, np.ma.masked_array)): - masked_elems = np.where(one_column.mask) - collapsed_image = np.delete(collapsed_image, masked_elems, 0) - return collapsed_image - - -def select_n_reflectances(img, n): - """ randomly select n reflectances from image. - The output is of shape n x nr_wavelengths """ - collapsed_image = collapse_image(img) - perms = np.random.permutation(collapsed_image.shape[0]) - first_n_perms = perms[0:n] - return collapsed_image[first_n_perms, :] - - -def get_bands(img, bands): - """get the bands bands (np.array) from the multispectral image. - Example: image is 2048x2048x8. get_bands(img, [0,3] will return - img[:,:,[0,3]]. The advantage of this function is that the image does not - need to be 2d + wavelength.""" - original_shape = img.shape - collapsed_image = collapse_image(img) - img_bands = collapsed_image[ :, bands] - new_nr_bands = 1 - if hasattr(bands, "__len__"): - new_nr_bands = len(bands) - new_shape = original_shape[:-1] + (new_nr_bands,) - return np.reshape(img_bands, new_shape) - - -def sortout_bands(img, bands): - """delete bands bands (np.array) from the multispectral image. - Example: image is 2048x2048x8. sortout_bands(img, [0,3] will return - img[:,:,[1,2,4,5,6,7]]. The advantage of this function is that the image does not - need to be 2d + wavelength. - - TODO SW: Test""" - all_bands = np.arange(img.shape[-1]) - bands_to_get = np.setdiff1d(all_bands, bands) - return get_bands(img, bands_to_get) - diff --git a/Modules/Biophotonics/python/iMC/msi/io/__init__.py b/Modules/Biophotonics/python/iMC/msi/io/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/msi/io/msireader.py b/Modules/Biophotonics/python/iMC/msi/io/msireader.py deleted file mode 100644 index 6bb7413ad8..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/msireader.py +++ /dev/null @@ -1,22 +0,0 @@ -''' -Created on Aug 25, 2015 - -@author: wirkert -''' - -import pickle - -class MsiReader(object): - ''' - The MsiReader reads the Msi from the serialized python object. - This is the prefered way of reading an Msi. - ''' - - def __init__(self): - pass - - def read(self, filename_to_read): - msi_file = open(filename_to_read, 'r') - msi = pickle.load(msi_file) - msi_file.close() - return msi diff --git a/Modules/Biophotonics/python/iMC/msi/io/msiwriter.py b/Modules/Biophotonics/python/iMC/msi/io/msiwriter.py deleted file mode 100644 index 815c465a54..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/msiwriter.py +++ /dev/null @@ -1,25 +0,0 @@ -''' -Created on Aug 25, 2015 - -@author: wirkert -''' - -import pickle - -from writer import Writer - -class MsiWriter(Writer): - ''' - The MsiReader writing the Msi as a serialized python object. - ''' - - def __init__(self, msiToWrite): - """ - initialize the write with a specific multi spectral image (class Msi) - """ - self.msiToWrite = msiToWrite - - def write (self, uri): - f = open(uri, 'w') - pickle.dump(self.msiToWrite, f) - f.close() diff --git a/Modules/Biophotonics/python/iMC/msi/io/nrrdreader.py b/Modules/Biophotonics/python/iMC/msi/io/nrrdreader.py deleted file mode 100644 index 637ac7ab43..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/nrrdreader.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Aug 10 16:29:20 2015 - -@author: wirkert -""" - -import logging -import numpy as np - -import SimpleITK as sitk - -from msi.io.reader import Reader -from msi.msi import Msi - - -class NrrdReader(Reader): - - def __init__(self): - pass - - def read(self, fileToRead): - """ read the nrrd image. - TODO: properties are not correctly extracted from nrrd.""" - - image = None - - try: - reader = sitk.ImageFileReader() - reader.SetFileName(fileToRead) - - image = reader.Execute() - image = sitk.GetArrayFromImage(image) - - except RuntimeError as re: - # image could not be read - logging.warning("image " + fileToRead + - " could not be loaded: " + - str(re)) - # rethrow exception after logging - raise - - # if image is too low dimensional singleton dimensions - # are added when saving. Done because sitk can only handle dimensions - # 2,3,4. This removes these singleton dimensions again. - squeezed_image = np.squeeze(image) - msi = Msi(squeezed_image) - return msi diff --git a/Modules/Biophotonics/python/iMC/msi/io/nrrdwriter.py b/Modules/Biophotonics/python/iMC/msi/io/nrrdwriter.py deleted file mode 100644 index a07694a0e0..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/nrrdwriter.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 09:48:18 2015 - -@author: wirkert -""" - -import logging -import numpy as np - -import SimpleITK as sitk - -from msi.io.writer import Writer - - -class NrrdWriter(Writer): - - def __init__(self, msiToWrite): - """ - initialize the write with a specific multi spectral image (class Msi) - """ - self.msiToWrite = msiToWrite - - def write(self, uri): - """ - write the msi image to the specified uri - """ - img_to_write = self.msiToWrite.get_image() - - # sitk can only write images of dimension 2,3,4. This hack is - # to fake 1d images as being 2d. 1d images e.g. occure after taking - # the mean of an image. - if len(img_to_write.shape) == 1: - img_to_write = np.reshape(img_to_write, (1, 1, img_to_write.shape[0])) - - img = sitk.GetImageFromArray(img_to_write, isVector=True) - sitk.WriteImage(img, uri) - logging.info("written file " + uri + " to disk") - return None diff --git a/Modules/Biophotonics/python/iMC/msi/io/pngreader.py b/Modules/Biophotonics/python/iMC/msi/io/pngreader.py deleted file mode 100644 index 48ee12e81e..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/pngreader.py +++ /dev/null @@ -1,58 +0,0 @@ -''' -Created on Sep 28, 2015 - -@author: wirkert -''' - - -import os -import itertools - -# PIL always rescales the image, thus PIL and skimage (which uses PIL) cannot -# be used -import png -import numpy as np - -from msi.io.reader import Reader -from msi.msi import Msi - - -class PngReader(Reader): - """ - Assumes bitdepth 16bit. - TODO SW: document and test""" - - def __init__(self): - pass - - - def read(self, fileToRead): - """ read the msi from pngs. - The fileToRead is a string prefix, all files starting with this - prefix will be summarized to one msi""" - - path, file_prefix = os.path.split(fileToRead) - files = os.listdir(path) - files_to_read = [os.path.join(path, f) for f in files - if f.startswith(file_prefix)] - files_to_read.sort() - image_array = [toImage(f) - for f in files_to_read] - image = reduce(lambda x, y: np.dstack((x, y)), image_array) - - msi = Msi(image) - return msi - - -def toImage(f): - reader = png.Reader(f) - column_count, row_count, pngdata, params = reader.asDirect() - plane_count = params['planes'] - image_2d = np.vstack(itertools.imap(np.uint16, pngdata)) - # this is needed for rgb images. probably better would be a mean in case - # we convert "real" rgb data. This is just for rgb images which - # contain the same values for r,g and b for every pixel. - image_3d = np.reshape(image_2d, - (row_count, column_count, plane_count)) - return image_3d[:, :, 0] - diff --git a/Modules/Biophotonics/python/iMC/msi/io/reader.py b/Modules/Biophotonics/python/iMC/msi/io/reader.py deleted file mode 100644 index 99d6b678c3..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/reader.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 7 13:39:16 2015 - -@author: wirkert -""" - - -class Reader: - """ - Abstract reader base class - """ - - def __init__(self): - pass - - def read(self, fileToRead): - return None - diff --git a/Modules/Biophotonics/python/iMC/msi/io/spectrometerreader.py b/Modules/Biophotonics/python/iMC/msi/io/spectrometerreader.py deleted file mode 100644 index b182201d7a..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/spectrometerreader.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 7 12:04:18 2015 - -@author: wirkert -""" - -import numpy as np -from msi.io.reader import Reader -from msi.msi import Msi - - -class SpectrometerReader(Reader): - - def __init__(self): - pass - - def read(self, file_to_read): - # our spectrometer like to follow german standards in files, we need - # to switch to english ones - transformed="" - replacements = {',': '.', '\r\n': ''} - with open(file_to_read) as infile: - for line in infile: - for src, target in replacements.iteritems(): - line = line.replace(src, target) - transformed = "\n".join([transformed, line]) - - for num, line in enumerate(transformed.splitlines(), 1): - if ">>>>>Begin" in line: - break - - for num_end, line in enumerate(transformed.splitlines(), 1): - if ">>>>>End" in line: - num_end -= 1 - break - string_only_spectrum = "\n".join(transformed.splitlines()[num:num_end]) - data_vector = np.fromstring(string_only_spectrum, - sep="\t").reshape(-1, 2) - msi = Msi(data_vector[:, 1], - {'wavelengths': data_vector[:, 0] * 10 ** -9}) - return msi - diff --git a/Modules/Biophotonics/python/iMC/msi/io/tiffreader.py b/Modules/Biophotonics/python/iMC/msi/io/tiffreader.py deleted file mode 100644 index fdc7bae5fb..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/tiffreader.py +++ /dev/null @@ -1,100 +0,0 @@ -''' -Created on Sep 28, 2015 - -@author: wirkert -''' - - -import os - -import Image -import scipy -import numpy as np - -from msi.io.reader import Reader -from msi.msi import Msi - - -def sort_by_filter(s1, s2): - ''' - Sorting function which takes two strings and sorts them lexigraphically by - the last character before the file extension. - - say: - - blabla_w2_F0.tiff < blabla_w0_F1.tiff - - This is done to sort by the filter index, which is always written as the - last thing by the tiff writer. - ''' - s1_prefix = os.path.splitext(s1)[0] - s2_prefix = os.path.splitext(s2)[0] - - result = 0 - if s1_prefix < s2_prefix: - result = 1 - elif s1_prefix > s2_prefix: - result = -1 - - return result - - -class TiffReader(Reader): - """ - AAATTTEEENTION: Some big bug hiding somewhere here, ordering of files - is corrupted, no time now to fix. TODO SW - - Assumes bitdepth 16bit on a 12bit camera. - TODO SW: document and test""" - - # static member to globally set resizing for all images read by the reader - # 1.0 for no resizing - RESIZE_FACTOR = 1.0 - - def __init__(self, shift_bits=4): - self.shift_bits = shift_bits - - def read(self, file_to_read, resize_factor=None, - sorting_function=sort_by_filter): - """ read the msi from tiffs. - The fileToRead is a string prefix, all files starting with this - prefix will be summarized to one msi. they will be sorted as specified - in the sorting_function - - Args: - sorting_function: the function which defines the sorting of the - strings that match the prefix. Pass none if normal - lexicographical sorting is wished - file_to_read: the prefix of the tiff file which shall be read - """ - - if resize_factor is None: - resize_factor = TiffReader.RESIZE_FACTOR - - path, file_prefix = os.path.split(file_to_read) - files = os.listdir(path) - files_to_read = [os.path.join(path, f) for f in files - if file_prefix[2:] in f] - files_to_read.sort(cmp=sorting_function) - image_array = [self.to_image(f, resize_factor=resize_factor) - for f in files_to_read] - image = reduce(lambda x, y: np.dstack((x, y)), image_array) - - msi = Msi(image) - return msi - - def to_image(self, f, resize_factor): - im = Image.open(f) - im_array = np.array(im) - - im_array >>= self.shift_bits - - if do_resize(resize_factor): - im_array = scipy.misc.imresize(im_array, resize_factor, - interp="bilinear", mode="F") - - return im_array.astype('float') - - -def do_resize(resize_factor): - return not np.isclose(resize_factor, 1.0) and (resize_factor is not None) diff --git a/Modules/Biophotonics/python/iMC/msi/io/tiffringreader.py b/Modules/Biophotonics/python/iMC/msi/io/tiffringreader.py deleted file mode 100644 index b0bf6177b9..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/tiffringreader.py +++ /dev/null @@ -1,100 +0,0 @@ -''' -Created on Nov 2, 2015 - -@author: wirkert -''' - -import os -import logging - -import Image -import scipy -import numpy as np - -from msi.io.reader import Reader -from msi.msi import Msi - - -class TiffRingReader(Reader): - ''' - TODO SW: document and test - ''' - - # static member to globally set resizing for all images read by the reader - # 1.0 for no resizing - RESIZE_FACTOR = 1.0 - - def __init__(self, shift_bits=4): - self.shift_bits = shift_bits - - def read(self, fileToRead, n, resize_factor=None, - segmentation=None): - """ read the msi from tiffs. - The fileToRead is the first file to read, - then n files will be read to one msi from a - sorted file list - - segmentation: tiff filename of the segmentation. If none, it will be - tried to get a segmentation from npy files with filenames like the - tiff files + _seg.tiff. If this fails, no segmentation will be - assumed - """ - - if resize_factor is None: - resize_factor = TiffRingReader.RESIZE_FACTOR - - path, file_name = os.path.split(fileToRead) - files = os.listdir(path) - files_in_folder = [os.path.join(path, f) for f in files if - os.path.isfile(os.path.join(path, f)) and - f.endswith('.tiff')] - - files_in_folder.sort() - position = files_in_folder.index(fileToRead) - # take n images from found position - image_array = [self.to_image(f, resize_factor) - for f in files_in_folder[position:position + n]] - image = reduce(lambda x, y: np.dstack((x, y)), image_array) - - # in case of 1 dimensional image: add a fake last dimension, since - # we always assume the last dimension to be the wavelength domain. - # TODO SW: Test this and implement for other readers - if n is 1: - image = np.expand_dims(image, -1) - - msi = Msi(image) - - # we pass an explicic image as segmentation - if segmentation is not None: - segmentation = self.to_image(segmentation, resize_factor) - else: # otherwise: search for numpy segmentations - try: - segmentation_array = [to_segmentation(f) - for f in - files_in_folder[position:position + n]] - if do_resize(resize_factor): - segmentation = reduce(lambda x, y: x & y, segmentation_array) - segmentation = scipy.misc.imresize(segmentation, resize_factor, - interp="bilinear") - except: - logging.info("didn't find segmentation for all images") - return msi, segmentation - - def to_image(self, f, resize_factor): - im = Image.open(f) - im_array = np.array(im) - im_array >>= self.shift_bits - - if do_resize(resize_factor): - im_array= scipy.misc.imresize(im_array, resize_factor, - interp="bilinear", mode="F") - return im_array.astype('float') - - -def to_segmentation(f): - seg = np.load(f + ".seg.npy") - return seg - - -def do_resize(resize_factor): - return not np.isclose(resize_factor, 1.0) and (resize_factor is not None) diff --git a/Modules/Biophotonics/python/iMC/msi/io/tiffwriter.py b/Modules/Biophotonics/python/iMC/msi/io/tiffwriter.py deleted file mode 100644 index 36506aa850..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/tiffwriter.py +++ /dev/null @@ -1,72 +0,0 @@ - - -import logging - -import numpy as np -from libtiff import TIFF - -from msi.io.writer import Writer - - -class TiffWriter(Writer): - """ - The tiff write will store nr_wavelength tiff files for one msi - """ - - def __init__(self, msi_to_write, convert_to_nm=True, scale_to_16_bit=False): - """ - initialize the write with a specific multi spectral image (class Msi) - """ - self.msi_to_write = msi_to_write - self.convert_to_nm = convert_to_nm - self.scale_to_16_bit = scale_to_16_bit - - def write(self, uri_prefix): - """ - write the msi image to the specified uri_prefix - - Args: - uri_prefix: the prefix off the uri. E.g. C:\example the image - write will automatically extend this prefix path to include the - wavelengths information and add a suffix. Your final - file may look similar to: C:\example_w_470nm_F0.tiff - convert_to_nm: if the wavelengths are saved in m they are hard to - write as string. Thus they can be automatically expanded to nm. - """ - img_to_write = self.msi_to_write.get_image() - - max_image_value = np.max(img_to_write) - - if self.scale_to_16_bit: - img_to_write *= 2**16 / max_image_value - - nr_wavelengths = self.msi_to_write.get_wavelengths().size - for wavelength_index in np.arange(nr_wavelengths): - full_uri = self._build_full_uri(uri_prefix, wavelength_index) - self._write_single_image(full_uri, - img_to_write[:, :, wavelength_index]) - - logging.info("written file " + full_uri + " to disk") - return None - - @staticmethod - def _write_single_image(full_uri, image_array): - """ - internally used method to write single tiff image - """ - tiff = TIFF.open(full_uri, mode='w') - tiff.write_image(image_array.astype('uint16'), write_rgb=False) - tiff.close() - - def _build_full_uri(self, uri_prefix, wavelength_index): - """ - Helper method to build full path of one image - Returns: full uri containing the desired properties. - """ - wavelength = self.msi_to_write.get_wavelengths()[wavelength_index] - if self.convert_to_nm: - wavelength *= 10**9 - full_uri = uri_prefix + "_w_" + str(wavelength) +\ - "_F" + str(wavelength_index) + ".tiff" - - return full_uri diff --git a/Modules/Biophotonics/python/iMC/msi/io/writer.py b/Modules/Biophotonics/python/iMC/msi/io/writer.py deleted file mode 100644 index 9342ff00fe..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/io/writer.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 09:47:31 2015 - -@author: wirkert -""" - - -class Writer(): - """ - Abstract writer base class - """ - - def __init__(self): - pass - - def write(self, fileToWrite): - return None \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/msi/msi.py b/Modules/Biophotonics/python/iMC/msi/msi.py deleted file mode 100644 index 5638d44ad7..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/msi.py +++ /dev/null @@ -1,128 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 6 18:21:36 2015 - -@author: wirkert -""" - -import numpy as np - - -class Msi(): - """ a multi spectral image stack consisting of: - - image: a rows x columns x nrWavelengths dimensional array - properties: additional, application dependent properties - """ - - def __init__(self, image=None, properties=None): - if image is None: - image = np.array([]) - if properties is None: - properties = {} - self._image = image - self._properties = properties - self._assure_basic_properties() - - self._test_image() - - def get_image(self): - return self._image - - def set_image(self, image, wavelengths=None): - """ - Put a new image into this msi - Args: - image: the rows x columns x nrWavelengths dimensional array - np.array. - wavelengths: a np.array of size nrWavelengths. If the number of - wavelengths hasn't change this is not needed. - """ - self._image = image - if wavelengths is not None: - self.set_wavelengths(wavelengths) - self._assure_basic_properties() - self._test_image() - - def get_wavelengths(self): - """ shortcut to get the wavelengths property - The wavelengths are given in [m] units and need not be sorted. """ - if 'wavelengths' not in self.get_properties(): - return None - return self._properties['wavelengths'] - - def set_wavelengths(self, wavelengths): - """ shortcut to set the wavelengths property """ - w_prop = {"wavelengths":wavelengths} - self.add_property(w_prop) - self._test_image() - - def get_properties(self): - return self._properties - - def add_property(self, newProperty): - """ add a new property(ies) to the existing properties """ - self._properties.update(newProperty) - self._test_image() - - def set_mask(self, mask): - """" applies a masked to the Msi. After this call, the image is of - type MaskedArray. If the image was already masked, the existing - masked will be "or ed" with the new mask. mask is a boolean array of - the same shape as self.get_image() - - Args: - mask: a mask of the same size as the image. 1s stand for pixels - masked out, 0s for pixels not masked.""" - if not isinstance(self.get_image(), np.ma.MaskedArray): - self.set_image(np.ma.masked_array(self.get_image(), mask, - fill_value=999999)) - else: - self.get_image()[mask] = np.ma.masked - - def __eq__(self, other): - """ - overrite the == operator - Two Msi s are the same if they contain the same image and properties. - Note: properties not implemented yet! - """ - if isinstance(other, Msi): - samesame = np.array_equal(other.get_image(), self.get_image()) - return samesame - return NotImplemented - - def __ne__(self, other): - """ != operator implemented by inverting to ==""" - result = self.__eq__(other) - if result is NotImplemented: - return result - return not result - - def _assure_basic_properties(self): - """ - helper method to automatically add the basic properties: - wavelength - to the msi if not added explicicly. basic wavelengths will just be - integers from 0 to 1 - """ - if self._image.size > 0 and ( - ("wavelengths" not in self._properties.keys() or - self._properties["wavelengths"].size == 0)): - self._properties["wavelengths"] = np.arange(self._image.shape[-1]) - if self._image.size == 0 and "wavelengths" not in self._properties.keys(): - self._properties["wavelengths"] = np.array([]) - - def _test_image(self): - """ - helper method which tests for the integrity of the msi. - E.g. the number of wavelengths must match the number of bands. - """ - # either both image and wavelength property are empty - if self._image.size == 0 and len(self._properties["wavelengths"]) != 0: - raise RuntimeError("dimension of image and wavelength mismatch: " + - "image size is zero, but wavelengths are set") - # or both are same - elif self._image.shape[-1] != len(self._properties["wavelengths"]): - raise RuntimeError("dimension of image and wavelength mismatch: " + - "image size and wavelenths do not match") - diff --git a/Modules/Biophotonics/python/iMC/msi/msimanipulations.py b/Modules/Biophotonics/python/iMC/msi/msimanipulations.py deleted file mode 100644 index 9169fa35c1..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/msimanipulations.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 13:42:00 2015 - -@author: wirkert -""" - -import logging -import copy -import numpy as np - -from scipy.interpolate import interp1d - -from imgmani import collapse_image -import imgmani -from msi import Msi - - -''' -The msi manipulations module includes usefull convenience operations on msis. - -E.g. calculate_mean_spectrum to calculate the average spectrum on all the image -data or interpolate_wavelengths to change to a different wavelenght set by -simple interpolation. - -All methods take a msi and change it in place. They also return the same msi -object for convenience (can e.g. be used to chain msi manipulations). -''' - - -def apply_segmentation(msi, segmentation): - """ applies a segmentation to an msi. - - If the msi has imaging data of n x m x nr_wavelengths the segmentation - has to be a numpy array of n x m size. pixelvalues with values different - than zero will be included in the segmentation. - By applying the segmentation, not segmented elements will be np.ma.masked. - - Alternatively, one can input a msi with the mentioned n x m numpy array - in from of a msi as segmentation (for convenience to be able to use the - same reader for msis and segmentations) - """ - if (isinstance(segmentation, Msi)): - # expects just an image, but if a Msi is passed it's also ok - segmentation = segmentation.get_image() - segmentation = np.squeeze(segmentation) - mask = (0 == segmentation) - # mask needs to be expanded to cover all wavlengths - wholeMask = np.zeros_like(msi.get_image(), dtype="bool") - # doesn't seem elegant - for i in range(wholeMask.shape[-1]): - wholeMask[:, :, i] = mask - - msi.set_mask(wholeMask) - return msi - - -def calculate_mean_spectrum(msi): - """ reduce this image to only its mean spectrum. - If the msi.get_image() is a masked array these values will be ignored when - calculating the mean spectrum """ - # reshape to collapse all but last dimension (which contains reflectances) - collapsedImage = collapse_image(msi.get_image()) - msi.set_image(np.mean(collapsedImage, axis=0)) - # returns the same msi. - return msi - - -def interpolate_wavelengths(msi, newWavelengths): - """ interpolate image data to fit newWavelengths. Current implementation - performs simple linear interpolation. Neither existing nor new wavelengths - need to be sorted. """ - interpolator = interp1d(msi.get_wavelengths(), msi.get_image(), assume_sorted=False) - msi.set_image(interpolator(newWavelengths), wavelengths=newWavelengths) - return msi - - -def normalize_integration_times(msi): - """ divides by integration times """ - if ('integration times' not in msi.get_properties()): - logging.warn("warning: trying to normalize integration times for " - "image without the integration time property") - return msi - - original_shape = msi.get_image().shape - collapsed_image = collapse_image(msi.get_image()) - collapsed_image = collapsed_image / msi.get_properties()['integration times'] - msi.set_image(collapsed_image.reshape(original_shape)) - - msi.add_property({'integration times': - np.ones_like(msi.get_properties()['integration times'])}) - return msi - - -def dark_correction(msi, dark): - """" subtract dark current from multi spectral image. - - The dark msi should either be of the same shape - as msi or 1xnr_wavelengths (see tests).""" - msi.set_image(msi.get_image() - dark.get_image()) - return msi - - -def flatfield_correction(msi, flatfield): - """ divide by flatfield to remove dependencies on light source form and - imaging system. - - The flatfield msi should either be of the same shape - as msi or 1xnr_wavelengths (see tests).""" - # we copy the flatfield to ensure it is unchanged by the normalization - flatfield_copy = copy.copy(flatfield) - normalize_integration_times(flatfield_copy) - normalize_integration_times(msi) - - msi.set_image(msi.get_image() / flatfield_copy.get_image()) - return msi - - -def image_correction(msi, flatfield, dark): - """ do the usual image correction: - msi = ((msi - dark) / integration_time) / ((flatfield - dark) / integration_time) - this function changes only the msi, flatfield and dark image - are left unchanged. - """ - # we need a copy of flatfield since otherwise the dark correction - # changes the flatfield - dark_correction(msi, dark) - flatfield_copy = copy.copy(flatfield) - dark_correction(flatfield_copy, dark) - flatfield_correction(msi, flatfield_copy) - return msi - - -def get_bands(msi, bands): - """ - TODO SW: document and test - """ - msi.set_image(imgmani.get_bands(msi.get_image(), bands)) - if msi.get_wavelengths() is not None: - msi.set_wavelengths(msi.get_wavelengths()[bands]) - return msi - diff --git a/Modules/Biophotonics/python/iMC/msi/normalize.py b/Modules/Biophotonics/python/iMC/msi/normalize.py deleted file mode 100644 index 880bbffed4..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/normalize.py +++ /dev/null @@ -1,53 +0,0 @@ - -import numpy as np -from sklearn.preprocessing import Normalizer - - -from imgmani import collapse_image - - -class Normalize(): - - def __init__(self): - pass - - def normalize(self, msi): - pass - - -class NormalizeIQ(Normalize): - """Normalize by image quotient""" - def __init__(self, iqBand=None): - if iqBand is None: - iqBand = 0 - self.iqBand = iqBand - - def normalize(self, msi): - # todo: guard if iqBand is outside of image dimension - original_shape = msi.get_image().shape - collapsed_image = collapse_image(msi.get_image()) - iqDimension = collapsed_image[ :, self.iqBand] - normalized_image = collapsed_image / iqDimension[:, None] - msi.set_image(np.reshape(normalized_image, original_shape)) - - -class NormalizeMean(Normalize): - """Normalize by image mean""" - def __init__(self): - pass - - def normalize(self, msi, norm="l1"): - original_shape = msi.get_image().shape - collapsed_image = collapse_image(msi.get_image()) - # temporarily save mask, since scipy normalizer removes mask - is_masked_array = isinstance(msi.get_image(), np.ma.MaskedArray) - if is_masked_array: - mask = msi.get_image().mask - normalizer = Normalizer(norm=norm) - normalized_image = normalizer.transform(collapsed_image) - if is_masked_array: - normalized_image = np.ma.MaskedArray(normalized_image, mask=mask) - msi.set_image(np.reshape(normalized_image, original_shape)) - - -standard_normalizer = NormalizeMean() diff --git a/Modules/Biophotonics/python/iMC/msi/plot.py b/Modules/Biophotonics/python/iMC/msi/plot.py deleted file mode 100644 index 0ae653b2ce..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/plot.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 11:13:31 2015 - -@author: wirkert -""" - -import copy -import logging - -import numpy as np -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1 import make_axes_locatable - -import imgmani -import msimanipulations as msimani - -def plot(msi, axes=None, color=None): - """ - create a plot for the Msi with x axes being the wavelengths and - y-axes being the corresponding image values (e.g. reflectances, absorptions) - Takes image masks into account: - doesn't plot a spectrum containing masked elements - """ - if axes is None: - axes = plt.gca() - - sortedIndices = sorted(range(len(msi.get_wavelengths())), - key=lambda k: msi.get_wavelengths()[k]) - sortedWavelenghts = msi.get_wavelengths()[sortedIndices] - # reshape to collapse all but last dimension (which contains reflectances) - collapsedImage = imgmani.collapse_image(msi.get_image()) - # todo: simply use np.ma.compress_rows - - # print "filtered ", filteredImage.shape - i = 0 - for i in range(collapsedImage.shape[0]): - if (collapsedImage[i, 0] is not np.ma.masked): - axes.plot(sortedWavelenghts, - collapsedImage[i, :][sortedIndices], "-o", color=color) - - -def plot_images(msi): - """plot the images as a 2d image array, one image for - each wavelength.""" - nr_wavelengths = msi.get_image().shape[-1] - f, axarr = plt.subplots(1, nr_wavelengths) - for i, a in enumerate(axarr): - one_band_image = imgmani.get_bands(msi.get_image(), i) - im = a.imshow(np.squeeze(one_band_image)) - a.set_title("band nr " + str(i), fontsize=5) - divider_dsp = make_axes_locatable(a) - cax_dsp = divider_dsp.append_axes("right", size="10%", pad=0.1) - cbar = plt.colorbar(im, cax=cax_dsp) - cbar.ax.tick_params(labelsize=5) - a.xaxis.set_visible(False) - a.yaxis.set_visible(False) - - -def plotMeanError(msi, axes=None): - """ - create a plot for the Msi with x axes being the wavelengths and - y-axes being the corresponding mean image values - (e.g. reflectances, absorptions). Plots also standard deviation bands - Takes image masks into account: - doesn't plot a spectrum containing masked elements - """ - if axes is None: - axes = plt.gca() - # sort the wavelengths - sortedIndices = sorted(range(len(msi.get_wavelengths())), - key=lambda k: msi.get_wavelengths()[k]) - sortedWavelenghts = msi.get_wavelengths()[sortedIndices] - # copy the msi, since it will be altered (mean will be built) - msi_copy = copy.deepcopy(msi) - image = msi_copy.get_image() - image = imgmani.collapse_image(image) - std_curve = np.ma.std(image, axis=0) - msimani.calculate_mean_spectrum(msi_copy) - # calculate std - logging.info("percentual std: " + - str(std_curve / msi_copy.get_image() * 100.)) - # plot as errorbar - axes.errorbar(sortedWavelenghts, msi_copy.get_image()[sortedIndices], - yerr=std_curve, fmt='-o') diff --git a/Modules/Biophotonics/python/iMC/msi/test/__init__.py b/Modules/Biophotonics/python/iMC/msi/test/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/msi/test/helpers.py b/Modules/Biophotonics/python/iMC/msi/test/helpers.py deleted file mode 100644 index 4565f7e63a..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/helpers.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 09:53:52 2015 - -@author: wirkert -""" - -import numpy as np -from msi.msi import Msi - - -def getFakeMsi(): - - # build a fake multispectral image with 5 dimensions. - image = np.concatenate((np.ones((5, 5, 1)), - np.ones((5, 5, 1)) * 2, - np.ones((5, 5, 1)) * 3, - np.ones((5, 5, 1)) * 4, - np.ones((5, 5, 1)) * 5), - axis=-1) - msi = Msi(image) - - msi.set_wavelengths(np.array([5, 4, 3, 2, 1])) - - return msi diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_imgmani.py b/Modules/Biophotonics/python/iMC/msi/test/test_imgmani.py deleted file mode 100644 index c6960958ca..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_imgmani.py +++ /dev/null @@ -1,96 +0,0 @@ -''' -Created on Aug 28, 2015 - -@author: wirkert -''' -import unittest -import numpy as np - -import msi.msimanipulations as msimani -import msi.imgmani as imgmani -import msi.test.helpers as helpers -from msi.imgmani import remove_masked_elements, select_n_reflectances - - -class TestImgMani(unittest.TestCase): - - def setUp(self): - self.msi = helpers.getFakeMsi() - # set one pixel to special values - self.specialValue = np.arange(self.msi.get_image().shape[-1]) * 2 - self.msi.get_image()[2, 2, :] = self.specialValue - # create a segmentation which sets all elements to invalid but the - # one pixel with the special value - self.segmentation = np.zeros(self.msi.get_image().shape[0:-1]) - self.segmentation[2, 2] = 1 - # apply this segmentation to the msi - msimani.apply_segmentation(self.msi, self.segmentation) - self.image = self.msi.get_image() - - def tearDown(self): - self.msi = None - self.specialValue = None - self.segmentation = None - self.image = None - - def test_collapse_image(self): - image = self.image - newShapedImage = imgmani.collapse_image(image) - - self.assertEqual(newShapedImage.shape, - (image.shape[0] * image.shape[1], image.shape[2]), - "collapsed image has correct shape") - np.testing.assert_equal(newShapedImage[2 * 5 + 2, :], - self.msi.get_image()[2, 2, :], - "values have been correctly transformed") - - def test_collapse_image_retains_data(self): - newShapedImage = imgmani.collapse_image(self.image) - self.msi.get_image()[2, 2, 0] = 5000. - - self.assertEqual(newShapedImage[2 * 5 + 2, 0], 5000., - "collapse_image does not copy data") - - def test_remove_masked_elements(self): - value = self.msi.get_image()[2, 2, :] - image_without_masked = remove_masked_elements(self.image) - np.testing.assert_array_equal(image_without_masked[0, :], value, - "mask correctly removed") - self.assertEqual(image_without_masked.shape, - (1, self.image.shape[-1]), - "shape of image without mask correct") - - def test_select_n_reflectances_selects(self): - n = 10 - new_image = select_n_reflectances(self.image, n) - self.assertEqual(new_image.shape, (n, self.image.shape[-1]), - "correct shape after selection") - - def test_select_n_reflectances_permutes(self): - image_shape = self.image.shape - new_first_layer = np.random.random_sample(image_shape[0:-1]) - self.image[:, :, 0] = new_first_layer - shuffled_image = select_n_reflectances(self.image, - image_shape[0] * image_shape[1]) - # restore_shape - shuffled_image = np.reshape(shuffled_image, image_shape) - self.assertFalse(np.allclose(shuffled_image[:, :, 0], - new_first_layer), - "image has been shuffled") - - def test_get_bands_from_int(self): - new_image_bands = imgmani.get_bands(self.image, 2) - self.assertEqual(new_image_bands.shape, (5, 5, 1), - "new image has correct shape") - self.assertEqual(new_image_bands[2, 2, :], self.specialValue[2], - "new image has correct values") - - def test_get_bands_from_array(self): - new_image_bands = imgmani.get_bands(self.image, np.array([0, 1, 2])) - self.assertEqual(new_image_bands.shape, (5, 5, 3), - "new image has correct shape") - np.testing.assert_allclose(new_image_bands[2, 2, :], - self.specialValue[:3], - err_msg="new image has correct values") - - diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_msi.py b/Modules/Biophotonics/python/iMC/msi/test/test_msi.py deleted file mode 100644 index 128a0691df..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_msi.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Mar 27 19:12:40 2015 - -@author: wirkert -""" - -import unittest -import numpy as np - -from msi.msi import Msi -from msi.test import helpers - - -class TestMsi(unittest.TestCase): - - def setUp(self): - self.msi = helpers.getFakeMsi() - - def tearDown(self): - pass - - def test_create(self): - self.assertTrue(True, "Created msi during setup") - - def test_add_property(self): - self.msi.add_property({'test':np.array([1, 2, 3])}) - self.assertTrue(np.array_equal(self.msi.get_properties()['test'], - np.array([1, 2, 3])), "property successfully added to msi") - - def test_properties_not_shared(self): - msi1 = Msi() - msi2 = Msi() - msi1.add_property({"integration time": np.array([1, 2, 3])}) - - self.assertTrue('integration time' not in msi2.get_properties()) - - def test_add_dummy_wavelengths_automatically(self): - msi_no_wavelengths_set = Msi() - msi_no_wavelengths_set.set_image(self.msi.get_image()) - - nr_wavelengths = msi_no_wavelengths_set.get_image().shape[-1] - - np.testing.assert_equal(msi_no_wavelengths_set.get_wavelengths(), - np.arange(nr_wavelengths), - "correct dummy wavelength values set") - - - - diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_msimanipulations.py b/Modules/Biophotonics/python/iMC/msi/test/test_msimanipulations.py deleted file mode 100644 index 9b895a6cf4..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_msimanipulations.py +++ /dev/null @@ -1,203 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 13:52:23 2015 - -@author: wirkert -""" - - -import unittest -import copy -import numpy as np - -from msi.test import helpers -import msi.msimanipulations as mani - - -class TestMsiManipulations(unittest.TestCase): - - def setUp(self): - self.msi = helpers.getFakeMsi() - self.specialmsi = helpers.getFakeMsi() - - # set one pixel to special values - self.specialValue = np.arange(self.specialmsi.get_image().shape[-1]) * 2 - self.specialmsi.get_image()[2, 2, :] = self.specialValue - - # create a segmentation which sets all elements to invalid but the - # one pixel with the special value - self.segmentation = np.zeros(self.specialmsi.get_image().shape[0:-1]) - self.segmentation[2, 2] = 1 - - def tearDown(self): - pass - - def test_apply_segmentation(self): - - mani.apply_segmentation(self.specialmsi, self.segmentation) - - validImageEntries = self.specialmsi.get_image() \ - [~self.specialmsi.get_image().mask] - - np.testing.assert_equal(validImageEntries, self.specialValue, - "image has been correctly segmented") - - def test_calculate_mean_spectrum(self): - - mani.calculate_mean_spectrum(self.specialmsi) - - np.testing.assert_equal(np.array([0.96, 2., 3.04, 4.08, 5.12]), - self.specialmsi.get_image(), - "mean spectrum is correctly calculated on image with " + - "no mask applied") - - def test_calculate_mean_spectrum_masked_image(self): - - mani.apply_segmentation(self.specialmsi, self.segmentation) - mani.calculate_mean_spectrum(self.specialmsi) - - np.testing.assert_equal(self.specialValue, self.specialmsi.get_image(), - "mean spectrum is correctly calculated on image with " + - "mask applied") - - def test_interpolate(self): - # create not sorted new wavelengths - newWavelengths = np.array([4.0, 2.5, 3.5, 1.5]) - mani.interpolate_wavelengths(self.msi, newWavelengths) - - np.testing.assert_equal(newWavelengths, self.msi.get_wavelengths(), - "wavelengths correctly updated") - # check if first image pixel was correctly calculated - # (hopefully true for all then) - np.testing.assert_equal(np.array([2.0, 3.5, 2.5, 4.5]), - self.msi.get_image()[0, 0, :], - "image elements correctly interpolated") - - def test_normalize_integration_times(self): - old_shape = self.msi.get_image().shape - integration_times = np.array([1., 2., 3., 4., 5.]) - self.msi.add_property({'integration times': integration_times}) - mani.normalize_integration_times(self.msi) - - np.testing.assert_equal(self.msi.get_image()[1, 3, :], - np.ones_like(integration_times), - "normalized integration times") - np.testing.assert_equal(self.msi.get_properties()['integration times'], - np.ones_like(integration_times), - "integration time property set to ones") - self.assertEqual(self.msi.get_image().shape, old_shape, - "shape did not change from normalizing") - - def test_normalize_integration_times_none_given(self): - msi_copy = copy.deepcopy(self.msi) - mani.normalize_integration_times(msi_copy) - np.testing.assert_equal(msi_copy.get_image(), self.msi.get_image(), - "nothing change by normalizing without" + \ - "integration times given") - - def test_dark_correction(self): - desired_image_data = copy.copy(self.msi.get_image()) - desired_image_data -= 1 - - dark = copy.copy(self.msi) - dark.set_image(np.ones_like(dark.get_image())) - - mani.dark_correction(self.msi, dark) - - np.testing.assert_equal(self.msi.get_image(), - desired_image_data, - "dark image correctly accounted for") - np.testing.assert_equal(dark.get_image(), - np.ones_like(dark.get_image()), - "dark image unchanged by dark correction") - - def test_dark_correction_with_single_value(self): - desired_image_data = copy.copy(self.specialmsi.get_image()) - desired_image_data -= 1 - - dark = copy.copy(self.specialmsi) - dark.set_image(np.ones_like(dark.get_image())) - mani.calculate_mean_spectrum(dark) - - mani.dark_correction(self.specialmsi, dark) - - np.testing.assert_equal(self.specialmsi.get_image(), - desired_image_data, - "dark image correctly accounted for from singular dark value") - np.testing.assert_equal(dark.get_image(), - np.ones_like(dark.get_image()), - "dark image unchanged by dark correction") - - def test_flatfield_correction(self): - desired_image_data = np.ones_like(self.specialmsi.get_image()) - desired_image_data[2, 2, 0] = np.nan - - mani.flatfield_correction(self.specialmsi, self.specialmsi) - - np.testing.assert_equal(self.specialmsi.get_image(), - desired_image_data, - "correct image by itself should lead to only 1s ") - - def test_flatfield_correction_differing_integration_times(self): - MSI_INTEGRATION_TIME = 3.0 - FLATFIELD_INTEGRATION_TIME = 2.0 - desired_image_data = np.ones_like(self.specialmsi.get_image()) * \ - FLATFIELD_INTEGRATION_TIME / MSI_INTEGRATION_TIME - desired_image_data[2, 2, 0] = np.nan - self.specialmsi.add_property({"integration times": - np.ones_like( - self.specialmsi.get_image()[0, 0, :]) - * MSI_INTEGRATION_TIME}) - flatfield = copy.deepcopy(self.specialmsi) - flatfield.add_property({"integration times": - np.ones_like( - flatfield.get_image()[0, 0, :]) - * FLATFIELD_INTEGRATION_TIME}) - # for testing if flatfield does not changed by correction we copy it - flatfield_copy = copy.deepcopy(flatfield) - - mani.flatfield_correction(self.specialmsi, flatfield_copy) - - np.testing.assert_almost_equal(self.specialmsi.get_image(), - desired_image_data, 15, - "corrected image is a division of integration times") - np.testing.assert_equal(flatfield.get_image(), - flatfield_copy.get_image(), - "flatfield doesn't change by correction") - - def test_flatfield_correction_with_single_value(self): - desired_image_data = np.ones_like(self.msi.get_image()) - flatfield = copy.copy(self.msi) - mani.calculate_mean_spectrum(flatfield) - unchanged_flatfield = copy.deepcopy(flatfield) - - mani.flatfield_correction(self.msi, flatfield) - - np.testing.assert_equal(self.msi.get_image(), - desired_image_data, - "flatfield correctly accounted for from singular reference value") - np.testing.assert_equal(flatfield, unchanged_flatfield, - "flatfield not changed by algorithm") - - def test_image_correction(self): - dark = copy.copy(self.msi) - dark.set_image(np.ones_like(dark.get_image()) * 0.5) - flatfield = copy.copy(self.msi) - flatfield_copy = copy.deepcopy(flatfield) - dark_copy = copy.deepcopy(dark) - - mani.image_correction(self.msi, flatfield, dark) - - np.testing.assert_equal(flatfield.get_image(), - flatfield_copy.get_image(), - "image correction didn't change flatfield") - np.testing.assert_equal(dark.get_image(), dark_copy.get_image(), - "image correction didn't change dark image") - np.testing.assert_almost_equal(self.msi.get_image(), - np.ones_like(self.msi.get_image()), - 15, "image correctly corrected :-)") - - - - - diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_msireaderwriter.py b/Modules/Biophotonics/python/iMC/msi/test/test_msireaderwriter.py deleted file mode 100644 index a3bed221b0..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_msireaderwriter.py +++ /dev/null @@ -1,40 +0,0 @@ -''' -Created on Aug 25, 2015 - -@author: wirkert -''' -import unittest -import os -import numpy as np - -import msi.test.helpers as helpers -from msi.io.msiwriter import MsiWriter -from msi.io.msireader import MsiReader - - -class Test(unittest.TestCase): - - def setUp(self): - self.msi = helpers.getFakeMsi() - self.test_file_path = "test_msi.msi" - - def tearDown(self): - # remove the hopefully written file - os.remove(self.test_file_path) - - def test_read_and_write(self): - reader = MsiReader() - writer = MsiWriter(self.msi) - writer.write(self.test_file_path) - read_msi = reader.read(self.test_file_path) - - np.testing.assert_array_equal(self.msi.get_image(), - read_msi.get_image(), - "data array of msi stays same" + - "after read and write") - np.testing.assert_array_equal( - self.msi.get_properties()["wavelengths"], - read_msi.get_properties()["wavelengths"], - "properties of msi stay same after read and write") - - diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_normalize.py b/Modules/Biophotonics/python/iMC/msi/test/test_normalize.py deleted file mode 100644 index 72f2a844c6..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_normalize.py +++ /dev/null @@ -1,74 +0,0 @@ -''' -Created on Aug 20, 2015 - -@author: wirkert -''' -import unittest -import numpy as np - -import msi.normalize as norm -import msi.test.helpers as helpers - - -class TestNormalize(unittest.TestCase): - - def setUp(self): - self.specialmsi = helpers.getFakeMsi() - # set one pixel to special values - self.specialValue = np.arange(self.specialmsi.get_image().shape[-1]) * 2 - self.specialmsi.get_image()[2, 2, :] = self.specialValue - - def tearDown(self): - pass - - def test_normalizeIQ(self): - original_shape = self.specialmsi.get_image().shape # shape should stay - # value 4.0 is in band 3 - desired_matrix = self.specialmsi.get_image() / 4.0 - # except for special value, where it is 8 - desired_matrix[2, 2, :] = self.specialmsi.get_image()[2, 2, :] / 6.0 - # the same after normalization - iq_normalizer = norm.NormalizeIQ(3) - iq_normalizer.normalize(self.specialmsi) - - self.assertEqual(self.specialmsi.get_image().shape, original_shape, - "shape not changed by normalization") - np.testing.assert_equal(self.specialmsi.get_image(), - desired_matrix, - "msi correctly normalized by iq") - - def test_normalizeMean(self): - original_shape = self.specialmsi.get_image().shape # shape should stay - desired_matrix = self.specialmsi.get_image() / 15.0 - desired_matrix[2, 2, :] = self.specialmsi.get_image()[2, 2, :] / 20.0 - # the same after normalization - mean_normalizer = norm.NormalizeMean() - mean_normalizer.normalize(self.specialmsi) - - self.assertEqual(self.specialmsi.get_image().shape, original_shape, - "shape not changed by normalization") - np.testing.assert_equal(self.specialmsi.get_image(), - desired_matrix, - "msi correctly normalized by mean") - - def test_normalizeMean_with_masked_elemnets(self): - original_shape = self.specialmsi.get_image().shape # shape should stay - # set mask so it masks the special value - mask = np.zeros_like(self.specialmsi.get_image()) - mask [2, 2, :] = 1 - mask = mask.astype(bool) - masked_msi_image = np.ma.MaskedArray(self.specialmsi.get_image(), - mask=mask) - self.specialmsi.set_image(masked_msi_image) - desired_matrix = masked_msi_image / 15.0 - # the same after normalization - mean_normalizer = norm.NormalizeMean() - mean_normalizer.normalize(self.specialmsi) - - self.assertEqual(self.specialmsi.get_image().shape, original_shape, - "shape not changed by normalization") - np.testing.assert_equal(self.specialmsi.get_image(), - desired_matrix, - "msi correctly normalized by mean") - np.testing.assert_equal(mask, self.specialmsi.get_image().mask) - diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_nrrdreader.py b/Modules/Biophotonics/python/iMC/msi/test/test_nrrdreader.py deleted file mode 100644 index da5083a125..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_nrrdreader.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Aug 10 16:43:31 2015 - -@author: wirkert -""" - -import unittest -from msi.io.nrrdreader import NrrdReader -import numpy as np - - -class TestNrrdReader(unittest.TestCase): - - def setUp(self): - self.nrrdReader = NrrdReader() - self.msi = self.nrrdReader.read('./msi/data/testMsi.nrrd') - - def test_read_does_not_crash(self): - # if we got this far, at least an image was read. - self.assertTrue(len(self.msi.get_image().shape) == 3, - "read image has correct basic shape dimensions") - self.assertTrue(self.msi.get_image().shape[-1] == 5, - "read image has correct number of image stacks") - self.assertTrue(np.array_equal(self.msi.get_image()[2, 2, :], - np.array([1, 2, 3, 4, 5])), - "read image contains correct data") - - def test_read_non_existing_image_returns_exception(self): - with self.assertRaises(RuntimeError): - self.nrrdReader.read("./msi/data/asdf.nrrd") diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_nrrdwriter.py b/Modules/Biophotonics/python/iMC/msi/test/test_nrrdwriter.py deleted file mode 100644 index c442b76159..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_nrrdwriter.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Thu Aug 13 09:52:47 2015 - -@author: wirkert -""" - -import unittest -import os -import numpy as np - -import msi.msimanipulations as msimani -from msi.io.nrrdreader import NrrdReader -from msi.io.nrrdwriter import NrrdWriter -from msi.test import helpers - - -class TestNrrdWriter(unittest.TestCase): - - def setUp(self): - # setup file and the path where it shall be written to - self.msi = helpers.getFakeMsi() - self.fileUriToWrite = "testfile.nrrd" - - def tearDown(self): - # remove the hopefully written file - os.remove(self.fileUriToWrite) - - def test_imageWriterCreatesFile(self): - writer = NrrdWriter(self.msi) - writer.write(self.fileUriToWrite) - self.assertTrue(os.path.isfile(self.fileUriToWrite), - "file was written to disk") - - def test_imageWriterCreatesCorrectFile(self): - - writer = NrrdWriter(self.msi) - writer.write(self.fileUriToWrite) - - reader = NrrdReader() - msi = reader.read(self.fileUriToWrite) - self.assertTrue(msi == helpers.getFakeMsi(), - "image correctly written and read") - - def test_write_one_d_image_works(self): - writer = NrrdWriter(self.msi) - msimani.calculate_mean_spectrum(self.msi) - writer.write(self.fileUriToWrite) - - reader = NrrdReader() - msi = reader.read(self.fileUriToWrite) - np.testing.assert_array_equal(msi.get_image(), - np.array([1, 2, 3, 4, 5]), - "1d image correctly written and read") diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_spectrometerreader.py b/Modules/Biophotonics/python/iMC/msi/test/test_spectrometerreader.py deleted file mode 100644 index b993a434bf..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_spectrometerreader.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 7 18:02:08 2015 - -@author: wirkert -""" - -import unittest - -from msi.io.spectrometerreader import SpectrometerReader - - -class TestSpectrometer(unittest.TestCase): - - def setUp(self): - self.exampleFileName = "./msi/data/Transmission_15-49-35-978_filter700nm.txt" - self.reader = SpectrometerReader() - - def tearDown(self): - pass - - def test_create(self): - self.assertTrue(True, "Created empty reader during setup") - - def test_read_spectrum(self): - msi = self.reader.read(self.exampleFileName) - - self.assertAlmostEqual(msi.get_image()[0], - 70.50, - msg="first spectral element is read correctly") - self.assertAlmostEqual(msi.get_image()[-1], - 68.13, - msg="last sprectral element is read correctly") - self.assertTrue(msi.get_image().size == 2048, - "correct number of elements read") - - def test_read_wavelengths(self): - msi = self.reader.read(self.exampleFileName) - - self.assertAlmostEqual(msi.get_wavelengths()[0], - 187.255 * 10 ** -9, - msg="first wavelength element is read correctly") - self.assertAlmostEqual(msi.get_wavelengths()[-1], - 1103.852 * 10 ** -9, - msg="last wavelength element is read correctly") - self.assertTrue(msi.get_wavelengths().size == 2048, - "correct number of elements read") diff --git a/Modules/Biophotonics/python/iMC/msi/test/test_tiffwriter.py b/Modules/Biophotonics/python/iMC/msi/test/test_tiffwriter.py deleted file mode 100644 index a2e880b80c..0000000000 --- a/Modules/Biophotonics/python/iMC/msi/test/test_tiffwriter.py +++ /dev/null @@ -1,40 +0,0 @@ - -import unittest -import os - -from msi.io.tiffwriter import TiffWriter -from msi.io.tiffreader import TiffReader -from msi.test import helpers - - -class TestTiffWriter(unittest.TestCase): - - def setUp(self): - # setup file and the path where it shall be written to - self.msi = helpers.getFakeMsi() - self.msi.set_image(self.msi.get_image()) - self.fileUriToWrite = os.path.join(os.getcwd(), "testfiles") - - def tearDown(self): - # remove the hopefully written files - folder, file_prefix = os.path.split(self.fileUriToWrite) - image_files = [f for f in os.listdir(folder) if - os.path.isfile(os.path.join(folder, f))] - image_files = [f for f in image_files if f.startswith(file_prefix)] - # expand to full path - image_files = [os.path.join(folder, f) for f in image_files] - for f in image_files: - os.remove(f) - - def test_imageWriterCreatesFile(self): - writer = TiffWriter(self.msi, convert_to_nm=False) - writer.write(self.fileUriToWrite) - - def test_imageWriterCreatesCorrectFile(self): - writer = TiffWriter(self.msi, convert_to_nm=False) - writer.write(self.fileUriToWrite) - - reader = TiffReader(shift_bits=0) - msi = reader.read(self.fileUriToWrite) - self.assertTrue(msi == helpers.getFakeMsi(), - "image correctly written and read") diff --git a/Modules/Biophotonics/python/iMC/regression/__init__.py b/Modules/Biophotonics/python/iMC/regression/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/regression/domain_adaptation.py b/Modules/Biophotonics/python/iMC/regression/domain_adaptation.py deleted file mode 100644 index 316f378aa9..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/domain_adaptation.py +++ /dev/null @@ -1,88 +0,0 @@ -''' -Created on Oct 20, 2015 - -@author: wirkert -''' - -import numpy as np -from sklearn.cross_validation import KFold -from sklearn.grid_search import GridSearchCV -from sklearn.linear_model.logistic import LogisticRegressionCV -from sklearn.ensemble.forest import RandomForestClassifier - - -def prepare_data_for_weights_estimation(X_s, X_t): - nr_s = X_s.shape[0] - nr_t = X_t.shape[0] - source_labels = np.zeros(nr_s) - target_labels = np.ones(nr_t) - X_all = np.concatenate((X_s, X_t)) - all_labels = np.concatenate((source_labels, target_labels)) - return X_all, all_labels - - -def estimate_weights_random_forests(X_s, X_t, X_w): - - X_all, all_labels = prepare_data_for_weights_estimation(X_s, X_t) - # train logistic regression - kf = KFold(X_all.shape[0], 10, shuffle=True) - param_grid_rf = [ - {"n_estimators": np.array([500]), - "max_depth": np.array([6]), - # "max_features": np.array([1, 2, 4, 8, 16]), - "min_samples_leaf": np.array([100])}] - rf = GridSearchCV(RandomForestClassifier(50, max_depth=10, - class_weight="auto", n_jobs=-1), - param_grid_rf, cv=kf, n_jobs=-1) - rf = RandomForestClassifier(100, max_depth=6, min_samples_leaf=200, - class_weight="auto", n_jobs=-1) - rf.fit(X_all, all_labels) - # print "best parameters for rf weights determination: ", rf.best_estimator_ - probas = rf.predict_proba(X_w) - weights = probas[:, 1] / probas[:, 0] - return weights - - -def estimate_weights_logistic_regresssion(X_s, X_t): - """ estimate a logistic regressor to predict the probability of a sample - to be generated by one class or the other. - If one class is over or under represented weights will be adapted. - - Parameters: - X_s: samples from the source domain - X_t: samples from the target domain - - Returns: - weigths for X_s """ - X_all, all_labels = prepare_data_for_weights_estimation(X_s, X_t) - - kf = KFold(X_all.shape[0], 10, shuffle=True) - best_lr = LogisticRegressionCV(class_weight="auto", - Cs=np.logspace(4, 8, 10), - fit_intercept=False) - best_lr.fit(X_all, all_labels) - - weights = X_s.shape[0] / X_t.shape[0] * np.exp(np.dot(X_s, best_lr.coef_.T) - + best_lr.intercept_) - return weights - - -def resample(X, y, w, nr_samples=None): - """bootstrapping: resample with replacement according to weights - - Returns: - (X_new, w_new): the chosen samples and the new weights. - by design these new weights are all equal to 1.""" - if (nr_samples is None): - nr_samples = X.shape[0] - w = w / np.sum(w) # normalize - # create index array with samples to draw: - total_nr_samples = X.shape[0] # nr total samples - chosen_samples = np.random.choice(total_nr_samples, - size=nr_samples, - replace=True, p=np.squeeze(w)) - if y.ndim == 1: - y_chosen = y[chosen_samples] - else: - y_chosen = y[chosen_samples, :] - return X[chosen_samples, :], y_chosen, np.ones(nr_samples) diff --git a/Modules/Biophotonics/python/iMC/regression/estimation.py b/Modules/Biophotonics/python/iMC/regression/estimation.py deleted file mode 100644 index 7b84e88974..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/estimation.py +++ /dev/null @@ -1,130 +0,0 @@ - - -""" - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -""" -''' -Created on Oct 21, 2015 - -@author: wirkert -''' - -import math -import logging -import time - -import tensorflow as tf -import numpy as np -import SimpleITK as sitk - -from regression.tensorflow_estimator import multilayer_perceptron, cnn -import msi.imgmani as imgmani - - -def SAMDistance(x, y): - return math.acos(np.dot(x, y) / (np.linalg.norm(x) * np.linalg.norm(y))) - - -def estimate_image(msi, regressor): - """given an Msi and an regressor estimate the parmaeters for this image - - Paramters: - msi: multi spectral image - regressor: regressor, must implement the predict method""" - - # estimate parameters - collapsed_msi = imgmani.collapse_image(msi.get_image()) - # in case of nan values: set to 0 - collapsed_msi[np.isnan(collapsed_msi)] = 0. - collapsed_msi[np.isinf(collapsed_msi)] = 0. - - start = time.time() - estimated_parameters = regressor.predict(collapsed_msi) - end = time.time() - estimation_time = end - start - logging.info("time necessary for estimating image parameters: " + - str(estimation_time) + "s") - # restore shape - feature_dimension = 1 - if len(estimated_parameters.shape) > 1: - feature_dimension = estimated_parameters.shape[-1] - - estimated_paramters_as_image = np.reshape( - estimated_parameters, (msi.get_image().shape[0], - msi.get_image().shape[1], - feature_dimension)) - # save as sitk nrrd. - sitk_img = sitk.GetImageFromArray(estimated_paramters_as_image, - isVector=True) - return sitk_img, estimation_time - - -def estimate_image_tensorflow(msi, model_checkpoint_dir): - # estimate parameters - collapsed_msi = imgmani.collapse_image(msi.get_image()) - # in case of nan values: set to 0 - collapsed_msi[np.isnan(collapsed_msi)] = 0. - collapsed_msi[np.isinf(collapsed_msi)] = 0. - - - tf.reset_default_graph() - - keep_prob = tf.placeholder("float") - nr_wavelengths = len(msi.get_wavelengths()) - x = tf.placeholder("float", [None, nr_wavelengths, 1, 1]) - - x_test_image = np.reshape(msi.get_image(), [-1, nr_wavelengths, 1, 1]) - - # Construct the desired model - # pred, regularizers = multilayer_perceptron(x, nr_wavelengths, 100, 1, - # keep_prob) - pred = cnn(x, 1, keep_prob) - - # Initializing the variables - init = tf.initialize_all_variables() - - saver = tf.train.Saver() - - with tf.Session() as sess: - sess.run(tf.initialize_all_variables()) - # restore model: - ckpt = tf.train.get_checkpoint_state(model_checkpoint_dir) - - if ckpt and ckpt.model_checkpoint_path: - saver.restore(sess, ckpt.model_checkpoint_path) - - start = time.time() - estimated_parameters = pred.eval({x: x_test_image, - keep_prob:1.0}) - end = time.time() - estimation_time = end - start - logging.info("time necessary for estimating image parameters: " + - str(estimation_time) + "s") - # restore shape - feature_dimension = 1 - if len(estimated_parameters.shape) > 1: - feature_dimension = estimated_parameters.shape[-1] - - estimated_paramters_as_image = np.reshape( - estimated_parameters, (msi.get_image().shape[0], - msi.get_image().shape[1], - feature_dimension)) - # save as sitk nrrd. - sitk_img = sitk.GetImageFromArray(estimated_paramters_as_image, - isVector=True) - - return sitk_img, estimation_time - - -def standard_score(estimator, X, y): - """our standard scoring method is the median absolute error""" - return np.median(np.abs(estimator.predict(X) - y)) - diff --git a/Modules/Biophotonics/python/iMC/regression/linear.py b/Modules/Biophotonics/python/iMC/regression/linear.py deleted file mode 100644 index dcd96977a7..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/linear.py +++ /dev/null @@ -1,95 +0,0 @@ -''' -Created on Oct 19, 2015 - -@author: wirkert -''' - -import numpy as np -from scipy.interpolate import interp1d - -from mc.usuag import get_haemoglobin_extinction_coefficients - -class LinearSaO2Unmixing(object): - ''' - classdocs - ''' - - def __init__(self): - # oxygenated haemoglobin extinction coefficients - eHb02 = 0 - eHb = 0 - - # oxygenated haemoglobin extinction coefficients - eHbO2 = np.array([34772.8, - 27840.93333, - 23748.8 , - 21550.8 , - 21723.46667, - 28064.8 , - 39131.73333, - 45402.93333, - 42955.06667, - 40041.73333, - 42404.4 , - 36333.6 , - 22568.26667, - 6368.933333, - 1882.666667, - 1019.333333, - 664.6666667, - 473.3333333, - 376.5333333, - 327.2 , - 297.0666667],) - # deoxygenated haemoglobin extinction coefficients - eHb = [18031.73333 , - 15796.8 , - 17365.33333 , - 21106.53333 , - 26075.06667 , - 32133.2 , - 39072.66667 , - 46346.8 , - 51264 , - 50757.33333 , - 45293.33333 , - 36805.46667 , - 26673.86667 , - 17481.73333 , - 10210.13333 , - 7034 , - 5334.533333 , - 4414.706667 , - 3773.96 , - 3257.266667 , - 2809.866667] - nr_total_wavelengths = len(eHb) - # to account for scattering losses we allow a constant offset - scattering = np.ones(nr_total_wavelengths) - # put eHbO2, eHb and scattering term in one measurement matrix - self.H = np.vstack((eHbO2, eHb, scattering)).T - self.lsq_solution_matrix = np.dot(np.linalg.inv(np.dot(self.H.T, - self.H)), - self.H.T) - - - def fit(self, X, y, weights=None): - """only implemented to fit to the standard sklearn framework.""" - pass - - def predict(self, X): - """predict like in sklearn: - - Parameters: - X: nrsamples x nr_features matrix of samples to predict for - regression - - Returns: - y: array of shape [nr_samples] with values for predicted - oxygenation """ - # do least squares estimation - oxy_test, deoxy, s = np.dot(self.lsq_solution_matrix, X.T) - # calculate oxygenation = oxygenated blood / total blood - saO2 = oxy_test / (oxy_test + deoxy) - - return np.clip(saO2, 0., 1.) diff --git a/Modules/Biophotonics/python/iMC/regression/preprocessing.py b/Modules/Biophotonics/python/iMC/regression/preprocessing.py deleted file mode 100644 index 494f7a82db..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/preprocessing.py +++ /dev/null @@ -1,94 +0,0 @@ -''' -Created on Oct 26, 2015 - -@author: wirkert -''' - -import numpy as np -import pandas as pd -from sklearn.preprocessing import Normalizer - - -def preprocess2(df, nr_samples=None, snr=None, movement_noise_sigma=None, - magnification=None, bands_to_sortout=None): - - # first set 0 reflectances to nan - df["reflectances"] = df["reflectances"].replace(to_replace=0., - value=np.nan) - # remove nan - df.dropna(inplace=True) - - # extract nr_samples samples from data - if nr_samples is not None: - df = df.sample(nr_samples) - - # get reflectance and oxygenation - X = df.reflectances - if bands_to_sortout is not None and bands_to_sortout.size > 0: - X.drop(X.columns[bands_to_sortout], axis=1, inplace=True) - snr = np.delete(snr, bands_to_sortout) - X = X.values - y = df.layer0[["sao2", "vhb"]] - - # do data magnification - if magnification is not None: - X_temp = X - y_temp = y - for i in range(magnification - 1): - X = np.vstack((X, X_temp)) - y = pd.concat([y, y_temp]) - - # add noise to reflectances - camera_noise = 0. - if snr is not None: - sigmas = X / snr - noises = np.random.normal(loc=0., scale=1, size=X.shape) - camera_noise = sigmas*noises - - movement_noise = 0. - if movement_noise_sigma is not None: - nr_bands = X.shape[1] - nr_samples = X.shape[0] - # we assume no correlation between neighboring bands - CORRELATION_COEFFICIENT = 0.0 - movement_variance = movement_noise_sigma ** 2 - movement_variances = np.ones(nr_bands) * movement_variance - movement_covariances = np.ones(nr_bands-1) * CORRELATION_COEFFICIENT * \ - movement_variance - movement_covariance_matrix = np.diag(movement_variances) + \ - np.diag(movement_covariances, -1) + \ - np.diag(movement_covariances, 1) - # percentual sample errors - sample_errors_p = np.random.multivariate_normal(mean=np.zeros(nr_bands), - cov=movement_covariance_matrix, - size=nr_samples) - # errors w.r.t. the curve height. - movement_noise = X * sample_errors_p - - X += camera_noise + movement_noise - - X = np.clip(X, 0.00001, 1.) - # do normalizations - X = normalize(X) - return X, y - - -def preprocess(batch, nr_samples=None, snr=None, movement_noise_sigma=None, - magnification=None, bands_to_sortout=None): - X, y = preprocess2(batch, nr_samples, snr, movement_noise_sigma, - magnification, bands_to_sortout) - - return X, y["sao2"] - - -def normalize(X): - # normalize reflectances - normalizer = Normalizer(norm='l1') - X = normalizer.transform(X) - # reflectances to absorption - absorptions = -np.log(X) - X = absorptions - # get rid of sorted out bands - normalizer = Normalizer(norm='l2') - X = normalizer.transform(X) - return X diff --git a/Modules/Biophotonics/python/iMC/regression/tensorflow_dataset.py b/Modules/Biophotonics/python/iMC/regression/tensorflow_dataset.py deleted file mode 100644 index 4bc2065aac..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/tensorflow_dataset.py +++ /dev/null @@ -1,83 +0,0 @@ -"""Functions for downloading and reading ipcai data.""" -from __future__ import print_function - -import os - -import numpy -import pandas as pd - -from regression.preprocessing import preprocess - - -class DataSet(object): - def __init__(self, images, labels, fake_data=False): - if fake_data: - self._num_examples = 10000 - else: - assert images.shape[0] == labels.shape[0], ( - "images.shape: %s labels.shape: %s" % (images.shape, - labels.shape)) - self._num_examples = images.shape[0] - images = images.astype(numpy.float32) - self._images = images - self._labels = labels - if self._labels.ndim == 1: - self._labels = self._labels[:, numpy.newaxis] - self._epochs_completed = 0 - self._index_in_epoch = 0 - - @property - def images(self): - return self._images - - @property - def labels(self): - return self._labels - - @property - def num_examples(self): - return self._num_examples - - @property - def epochs_completed(self): - return self._epochs_completed - - def next_batch(self, batch_size, fake_data=False): - """Return the next `batch_size` examples from this data set.""" - if fake_data: - fake_image = [1.0 for _ in xrange(784)] - fake_label = 0 - return [fake_image for _ in xrange(batch_size)], [ - fake_label for _ in xrange(batch_size)] - start = self._index_in_epoch - self._index_in_epoch += batch_size - if self._index_in_epoch > self._num_examples: - # Finished epoch - self._epochs_completed += 1 - # Shuffle the data - perm = numpy.arange(self._num_examples) - numpy.random.shuffle(perm) - self._images = self._images[perm] - self._labels = self._labels[perm] - - # Start next epoch - start = 0 - self._index_in_epoch = batch_size - assert batch_size <= self._num_examples - end = self._index_in_epoch - return self._images[start:end], self._labels[start:end] - - -def read_data_set(dataframe_filename, fake_data=False): - - if fake_data: - data_set = DataSet([], [], fake_data=True) - return data_set - - df_data_set = pd.read_csv(os.path.join(dir, dataframe_filename), - header=[0, 1]) - - data_set_images, data_set_labels = preprocess(df_data_set, snr=10.) - data_set_labels = data_set_labels.values - data_set = DataSet(data_set_images, data_set_labels) - return data_set diff --git a/Modules/Biophotonics/python/iMC/regression/tensorflow_estimator.py b/Modules/Biophotonics/python/iMC/regression/tensorflow_estimator.py deleted file mode 100644 index b5025563ec..0000000000 --- a/Modules/Biophotonics/python/iMC/regression/tensorflow_estimator.py +++ /dev/null @@ -1,88 +0,0 @@ - - -import tensorflow as tf - - -def weight_variable(shape): - initial = tf.truncated_normal(shape, stddev=0.1) - return tf.Variable(initial) - - -def bias_variable(shape): - initial = tf.constant(0.1, shape=shape) - return tf.Variable(initial) - - -def conv2d(x, W, padding='SAME'): - return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding=padding) - - -def max_pool1d(x, poolsize=2): - return tf.nn.max_pool(x, ksize=[1, poolsize, 1, 1], - strides=[1, poolsize, 1, 1], padding='SAME') - - -def add_cnn_layer(input, n_inputs, n_outputs, kernel_size, padding='SAME'): - #w = weight_variable([n_inputs, n_outputs]) - #b = bias_variable([n_outputs]) - W = weight_variable([kernel_size, 1, n_inputs, n_outputs]) - b = bias_variable([n_outputs]) - # Hidden layer with RELU activation - #new_layer = tf.nn.relu(tf.add(tf.matmul(input, w), b)) - h_conv = tf.nn.relu(conv2d(input, W, padding=padding) + b) - # Add dropout regularization - #new_layer_with_dropout = tf.nn.dropout(new_layer, keep_prob) - h_pool = max_pool1d(h_conv) - return h_pool, W - - -def add_fully_connected_layer(_X, n_inputs, n_outputs, keep_prob): - W = weight_variable([n_inputs, n_outputs]) - b = bias_variable([n_outputs]) - # Hidden layer with RELU activation - new_layer = tf.nn.relu(tf.add(tf.matmul(_X, W), b)) - # Add dropout regularization - new_layer_with_dropout = tf.nn.dropout(new_layer, keep_prob) - - return new_layer_with_dropout, W - - -# this is my exemplary convolutional network -def cnn(_X, n_classes, keep_prob): - # two convolutional layers - layer_1, _ = add_cnn_layer(_X, 1, 32, 3, padding='VALID') - layer_2, _ = add_cnn_layer(layer_1, 32, 32, 2, padding='VALID') - # flatten last one to be able to apply it to fully connected layer - final_number_of_dimensions = 1*32 - layer_2_flat = tf.reshape(layer_2, [-1, final_number_of_dimensions]) - - # fully connected layer to bring information together - fc_dim = 5 - h_fc1_drop, _ = add_fully_connected_layer(layer_2_flat, - final_number_of_dimensions, - fc_dim, keep_prob) - - # return linear output layer - W_fc2 = weight_variable([fc_dim, n_classes]) - b_fc2 = bias_variable([n_classes]) - return tf.matmul(h_fc1_drop, W_fc2) + b_fc2 - - -# and this is the simpler multilayer perceptron -def multilayer_perceptron(x, n_bands, n_hidden, n_classes, keep_prob): - flattend_input = tf.reshape(x, [-1, n_bands]) - layer_1, W_1 = add_fully_connected_layer(flattend_input, n_bands, n_hidden, - keep_prob) - layer_2, W_2 = add_fully_connected_layer(layer_1, n_hidden, n_hidden, - keep_prob) - last_hidden_layer, W_3 = add_fully_connected_layer(layer_2, n_hidden, n_hidden, - keep_prob) - - W_out = weight_variable([n_hidden, n_classes]) - b_out = bias_variable([n_classes]) - - regularizers = (tf.nn.l2_loss(W_1) + tf.nn.l2_loss(W_2) + - tf.nn.l2_loss(W_3) + tf.nn.l2_loss(W_out)) - - return tf.matmul(last_hidden_layer, W_out) + b_out, regularizers - diff --git a/Modules/Biophotonics/python/iMC/scripts/basic_checks/__init__.py b/Modules/Biophotonics/python/iMC/scripts/basic_checks/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/basic_checks/script_evaluate_color_checkerboard.py b/Modules/Biophotonics/python/iMC/scripts/basic_checks/script_evaluate_color_checkerboard.py deleted file mode 100644 index fcf5bea72e..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/basic_checks/script_evaluate_color_checkerboard.py +++ /dev/null @@ -1,266 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 11:09:18 2015 - -@author: wirkert -""" - - -import Image -import ImageEnhance -import logging -import datetime -import copy - -from scipy.interpolate import interp1d -from sklearn.preprocessing import normalize -from sklearn.metrics import r2_score - -from msi.io.nrrdreader import NrrdReader -import msi.normalize as norm -from ipcai2016.tasks_common import * -import commons -from ipcai2016 import tasks_mc -import msi.plot as msiplot -from msi.io.spectrometerreader import SpectrometerReader -from msi.normalize import standard_normalizer -from msi.io.tiffringreader import TiffRingReader - -TiffRingReader.RESIZE_FACTOR = 0.5 - -sc = commons.ScriptCommons() - -sc.add_dir("COLORCHECKER_DATA", - os.path.join(sc.get_dir("DATA_FOLDER"), "colorchecker_laparoscope")) - -sc.add_dir("COLORCHECKER_RESULTS", - os.path.join(sc.get_dir("RESULTS_FOLDER"), - "colorchecker_laparoscope")) - -sc.add_dir("FLAT_FOLDER", - os.path.join(sc.get_dir("DATA_FOLDER"), - "colorchecker_laparoscope_flatfield")) - -sc.add_dir("SPECTROMETER_REFERENCE_DATA", - os.path.join(sc.get_dir("DATA_FOLDER"), - "spectrometer_reflectance_new")) - -sc.add_dir("FILTER_TRANSMISSIONS", - os.path.join(sc.get_dir("DATA_FOLDER"), - "filter_transmissions")) - - -class CheckColorCheckerBoards(luigi.Task): - image_name = luigi.Parameter() - - def requires(self): - return Flatfield(flatfield_folder=sc.get_full_dir("FLAT_FOLDER")), \ - SingleMultispectralImage(image=self.image_name), \ - Dark(dark_folder=sc.get_full_dir("DARK_FOLDER")), \ - SpectrometerToSpectrocam(spectrometer_measurement= - os.path.join(sc.get_full_dir("SPECTROMETER_REFERENCE_DATA"), - os.path.split(self.image_name)[1][0:8] + ".txt")) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("COLORCHECKER_RESULTS"), - os.path.split(self.image_name)[1] + - "_" + "_color_check" + ".png")) - - def run(self): - - print "... read data" - - segmentation_file = os.path.join( - sc.get_full_dir("COLORCHECKER_DATA"), "seg.tiff") - segmentation_file2 = os.path.join( - sc.get_full_dir("COLORCHECKER_DATA"), "seg2.tiff") - - nrrd_reader = NrrdReader() - tiff_ring_reader = TiffRingReader() - # read the flatfield - flat = nrrd_reader.read(self.input()[0].path) - dark = nrrd_reader.read(self.input()[2].path) - # read the msi - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - msi, segmentation = tiff_ring_reader.read(self.input()[1].path, - nr_filters, - segmentation=segmentation_file) - msi_copy = copy.deepcopy(msi) # copy to be able to apply both - # segmentations - msimani.apply_segmentation(msi, segmentation) - msi2, segmentation2 = tiff_ring_reader.read(self.input()[1].path, - nr_filters, - segmentation=segmentation_file2) - msimani.apply_segmentation(msi2, segmentation2) - - msimani.apply_segmentation(msi_copy, segmentation + segmentation2) - - # read the spectrometer measurement - msi_spectrometer = nrrd_reader.read(self.input()[3].path) - - # correct by flatfield and dark image - #msimani.image_correction(msi, flat, dark) - #msimani.image_correction(msi2, flat, dark) - #msimani.image_correction(msi_copy, flat, dark) - msimani.dark_correction(msi, dark) - msimani.dark_correction(msi2, dark) - msimani.dark_correction(msi_copy, dark) - - # create artificial rgb - rgb_image = msi_copy.get_image()[:, :, [2, 3, 1]] - rgb_image /= np.max(rgb_image) - rgb_image *= 255. - - # preprocess the image - # sortout unwanted bands - print "... apply normalizations" - # normalize to get rid of lighting intensity - norm.standard_normalizer.normalize(msi) - norm.standard_normalizer.normalize(msi2) - - print "... plot" - - # plot of the rgb image - rgb_image = rgb_image.astype(np.uint8) - im = Image.fromarray(rgb_image, 'RGB') - enh_brightness = ImageEnhance.Brightness(im) - im = enh_brightness.enhance(2.) - plotted_image = np.array(im) - - plt.figure() - f, (ax_rgb, ax_spectra) = plt.subplots(1, 2) - plot_image(plotted_image, ax_rgb, title="false rgb") - - msiplot.plotMeanError(msi, ax_spectra) - msiplot.plotMeanError(msi2, ax_spectra) - - standard_normalizer.normalize(msi_spectrometer) - msiplot.plot(msi_spectrometer, ax_spectra) - - mean_spectrometer = msi_spectrometer.get_image() - mean_msi = msimani.calculate_mean_spectrum(msi).get_image() - mean_msi2 = msimani.calculate_mean_spectrum(msi2).get_image() - r2_msi = r2_score(mean_spectrometer, mean_msi) - r2_msi2 = r2_score(mean_spectrometer, mean_msi2) - - ax_spectra.legend(["spectrocam 1 r2: " + str(r2_msi), - "spectrocam 2 r2: " + str(r2_msi2), "spectrometer"], - bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0., - fontsize=5) - - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight') - - -class CameraQEFile(luigi.Task): - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("DATA_FOLDER"), - "camera_quantum_efficiency.csv")) - - -class SpectrometerToSpectrocam(luigi.Task): - - spectrometer_measurement = luigi.Parameter() - - def requires(self): - # all wavelengths must have been measured for transmission and stored in - # wavelength.txt files (e.g. 470.txt) - filenames = ((sc.other["RECORDED_WAVELENGTHS"] * 10**9).astype(int)).astype(str) - filenames = map(lambda name: tasks_mc.FilterTransmission(os.path.join(sc.get_full_dir("FILTER_TRANSMISSIONS"), - name) + ".txt"), - filenames) - - return tasks_mc.SpectrometerFile(self.spectrometer_measurement), \ - filenames, CameraQEFile() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - os.path.split(self.spectrometer_measurement)[1] + - "_spectrocam.nrrd")) - - def run(self): - # load spectrometer measurement - spectrometer_reader = SpectrometerReader() - spectrometer_msi = spectrometer_reader.read(self.input()[0].path) - - # the wavelengths recorded by the spectrometer - spectrometer_wavelengths = spectrometer_msi.get_wavelengths() - - spectrometer_white = spectrometer_reader.read(os.path.join( - sc.get_full_dir("DATA_FOLDER"), "spectrometer_whitebalance", - "white_IL_1_OO_20ms.txt")) - spectrometer_dark = spectrometer_reader.read(os.path.join( - sc.get_full_dir("DATA_FOLDER"), "spectrometer_whitebalance", - "dark_1_OO_20ms.txt")) - msimani.dark_correction(spectrometer_white, spectrometer_dark) - white_interpolator = interp1d(spectrometer_white.get_wavelengths(), - spectrometer_white.get_image(), - bounds_error=False, fill_value=0.) - white_interpolated = white_interpolator(spectrometer_wavelengths) - - camera_qe = pd.read_csv(self.input()[2].path) - camera_qe_interpolator = interp1d(camera_qe["wavelengths"] * 10**-9, - camera_qe["quantum efficiency"], - bounds_error=False, - fill_value=0.) - camera_qe_interpolated = \ - camera_qe_interpolator(spectrometer_wavelengths) - - # camera batch creation: - new_reflectances = [] - for band in self.input()[1]: - df_filter = pd.read_csv(band.path) - interpolator = interp1d(df_filter["wavelengths"], - df_filter["reflectances"], - assume_sorted=False, bounds_error=False) - # use this to create new reflectances - interpolated_filter = interpolator(spectrometer_wavelengths) - # if a wavelength cannot be interpolated, set it to 0 - interpolated_filter = np.nan_to_num(interpolated_filter) - # account for cameras quantum efficiency - interpolated_filter *= camera_qe_interpolated * white_interpolated - # normalize band response - #normalize(interpolated_filter.reshape(1, -1), norm='l1', copy=False) - folded_reflectance = np.dot(spectrometer_msi.get_image(), - interpolated_filter) - new_reflectances.append(folded_reflectance) - plt.plot(interpolated_filter) - new_reflectances = np.array(new_reflectances).T - spectrometer_msi.set_image(new_reflectances, - wavelengths=sc.other["RECORDED_WAVELENGTHS"]) - - # write it - nrrd_writer = NrrdWriter(spectrometer_msi) - nrrd_writer.write(self.output().path) - -if __name__ == '__main__': - - # create a folder for the results if necessary - sc.set_root("/media/wirkert/data/Data/2020_Current_Works/") - sc.create_folders() - - # root folder there the data lies - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "color_checker" + - str(datetime.datetime.now()) + - '.log'), level=logging.INFO) - luigi.interface.setup_interface_logging() - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - - files = get_image_files_from_folder(sc.get_full_dir("COLORCHECKER_DATA"), - suffix="F0.tiff", fullpath=True) - - for f in files: - main_task = CheckColorCheckerBoards(image_name=f) - w.add(main_task) - - w.run() - diff --git a/Modules/Biophotonics/python/iMC/scripts/commons.py b/Modules/Biophotonics/python/iMC/scripts/commons.py deleted file mode 100644 index 48e060132c..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/commons.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -This file contains a singleton class which manages the paths set for evaluating -the scripts. - -Also it contains some utility methods. -""" - -import os - -import numpy as np - - -class ScriptCommons(object): - """ - The commonly shared paths to the data/log/results... folders. - + additional commonly available data as recorded wavelengths - this is a singleton pattern copied from - http://python-3-patterns-idioms-test.readthedocs.org/en/latest/Singleton.html - """ - - class __ScriptCommons_Singleton: - - def __init__(self): - - self.root = os.path.join("..", "..") - - self.dirs = {"LOG_FOLDER": "log", - "DATA_FOLDER": "data", - "RESULTS_FOLDER": "results"} - - self.dirs["FLAT_FOLDER"] = os.path.join(self.dirs["DATA_FOLDER"], - "flatfields") - self.dirs["DARK_FOLDER"] = os.path.join(self.dirs["DATA_FOLDER"], - "dark") - - self.dirs["INTERMEDIATES_FOLDER"] = os.path.join( - self.dirs["RESULTS_FOLDER"], "intermediate") - - self.dirs["MC_DATA_FOLDER"] = os.path.join( - self.dirs["INTERMEDIATES_FOLDER"], "mc_data") - - self.other = {"RECORDED_WAVELENGTHS": np.array([580, 470, - 660, 560, - 480, 511, - 600, 700]) - * 10 ** -9} - - def create_folders(self): - """ - Create all folders listed in self.folders if not existing - """ - for f in self.dirs: - create_folder_if_necessary(self.get_full_dir(f)) - - def set_root(self, root): - self.root = root - - def get_root(self): - return self.root - - def add_dir(self, key, new_dir): - """ - Add/replace a directory to the singletons list. - Directories can be returned with get_dir and with their full path by - calling get_full_dir - - :param key: the key under which it shall be retrievable - :param new_dir: the directory to add to the list - """ - self.dirs[key] = new_dir - - def get_dir(self, key): - return self.dirs[key] - - def get_full_dir(self, key): - return os.path.join(self.get_root(), self.get_dir(key)) - - instance = None - - def __new__(cls): # __new__ always a classmethod - if not ScriptCommons.instance: - ScriptCommons.instance = ScriptCommons.__ScriptCommons_Singleton() - return ScriptCommons.instance - - def __getattr__(self, name): - return getattr(self.instance, name) - - def __setattr__(self, name): - return setattr(self.instance, name) - - -def create_folder_if_necessary(folder): - """ - :param folder: create the folder folder if necessary (not already existing) - """ - if not os.path.exists(folder): - os.makedirs(folder) diff --git a/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/__init__.py b/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/domain_adaptation_paths.py b/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/domain_adaptation_paths.py deleted file mode 100644 index 23660eb1f1..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/domain_adaptation_paths.py +++ /dev/null @@ -1,18 +0,0 @@ - - -import os - -ROOT_FOLDER = "/media/wirkert/data/Data/2016_03_Domain_Adaptation" -LOG_FOLDER = os.path.join(ROOT_FOLDER, "log") -DATA_FOLDER = os.path.join(ROOT_FOLDER, "data") -RESULTS_FOLDER = os.path.join(ROOT_FOLDER, "results") -INTERMEDIATES_FOLDER = os.path.join(RESULTS_FOLDER, "intermediate") -MC_DATA_FOLDER = os.path.join(INTERMEDIATES_FOLDER, "mc_data") - - -def create_folder_if_necessary(folder): - if not os.path.exists(folder): - os.makedirs(folder) - -create_folder_if_necessary(INTERMEDIATES_FOLDER) -create_folder_if_necessary(LOG_FOLDER) diff --git a/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/script_analyze_da_in_silico.py b/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/script_analyze_da_in_silico.py deleted file mode 100644 index f8d486e90a..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/domain_adaptation/script_analyze_da_in_silico.py +++ /dev/null @@ -1,364 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 11:09:18 2015 - -@author: wirkert -""" - -import os -import logging -import datetime - -import numpy as np -import pandas as pd -import luigi -import matplotlib.pyplot as plt -import seaborn as sns - -from regression.preprocessing import preprocess -import domain_adaptation_paths as sp -from ipcai2016 import tasks_mc -from ipcai2016.script_analyze_ipcai_in_silico import w_standard, noise_levels, \ - evaluate_data, standard_plotting, NoisePlot -# additionally we need the weights estimation functionality -from regression.domain_adaptation import estimate_weights_random_forests - - -class WeightedBatch(luigi.Task): - which_source = luigi.Parameter() - which_target = luigi.Parameter() - noise = luigi.FloatParameter() - - def requires(self): - return tasks_mc.CameraBatch(self.which_source), \ - tasks_mc.CameraBatch(self.which_target) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - "adapted_" + - self.which_source + - "_with_" + self.which_target + - "_noise_" + str(self.noise) + - ".txt")) - - def run(self): - # get data - df_source = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_target = pd.read_csv(self.input()[1].path, header=[0, 1]) - - # first extract X_source and X_target, preprocessed at standard noise - # level - X_source, y_source = preprocess(df_source, w_percent=w_standard) - X_target, y_target = preprocess(df_target, w_percent=w_standard) - - # train a classifier to determine probability for specific class - weights = estimate_weights_random_forests(X_source, X_target, X_source) - # add weight to dataframe - df_source["weights"] = weights - - # finally save the dataframe with the added weights - df_source.to_csv(self.output().path, index=False) - - -class DaNoisePlot(luigi.Task): - """ - Very similar to NoisePlot in IPCAI in silico evaluation but with - weighted data coming in. - """ - which_train = luigi.Parameter() - which_test = luigi.Parameter() - - def requires(self): - # for each noise level we need to create the weights - NecessaryBatches = map(lambda noise: WeightedBatch(self.which_train, - self.which_test, - noise), - noise_levels) - return NecessaryBatches(self.which_train, self.which_test), \ - tasks_mc.CameraBatch(self.which_test) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - sp.FINALS_FOLDER, - "noise_da_plot_train_" + - self.which_train + - "_test_" + self.which_test + - ".png")) - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - - df = evaluate_data(df_train, noise_levels, df_test, noise_levels) - standard_plotting(df) - - # finally save the figure - plt.savefig(self.output().path, dpi=500, - bbox_inches='tight') - - -class GeneratingDistributionPlot(luigi.Task): - which_source = luigi.Parameter() - which_target = luigi.Parameter() - - def requires(self): - return WeightedBatch(self.which_source, self.which_target), \ - tasks_mc.CameraBatch(self.which_target) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - sp.FINALS_FOLDER, - "generating_distribution_" + - self.which_source + - "_adapted_to_" + - self.which_target + - ".png")) - - def run(self): - # get data - df_source = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_target = pd.read_csv(self.input()[1].path, header=[0, 1]) - - # create dataframe suited for plotting - # we do a weighted sampling with replacement to be able to create some - # plots there the data distribution is visible. - nr_samples = 100 - # first data weighted by domain adaptation - df_source_adapted = df_source["layer0"].copy() - df_source_adapted["weights"] = df_source["weights"] - df_source_adapted["data"] = "adapted" - df_source_adapted = df_source_adapted.sample(n=nr_samples, replace=True, - weights="weights") - # now original source data - df_source = df_source["layer0"].copy() - df_source["weights"] = 1 # we set the weights here to 1 - df_source["data"] = "source" - df_source = df_source.sample(n=nr_samples, replace=True, - weights="weights") - # now the target data - df_target = df_target["layer0"] - df_target["weights"] = 1 - df_target["data"] = "target" - df_target = df_target.sample(n=nr_samples, replace=True, - weights="weights") - # now merge all three dataframes to the dataframe used for the plotting - df = pd.concat([df_source, df_source_adapted, df_target]) - # since we already sampled we can get rid of weights - df.drop("weights", axis=1, inplace=True) - # d to um - df["d"] *= 10**6 - # vhb and sao2 to % - df["vhb"] *= 100 - df["sao2"] *= 100 - - # do some serious plotting - g = sns.pairplot(df, vars=["vhb", "sao2", "d"], - hue="data", markers=["o", "s", "D"]) - - # tidy up plot - g.add_legend() - - # finally save the figure - plt.savefig(self.output().path, dpi=500, - bbox_inches='tight') - - -class WeightDistributionPlot(luigi.Task): - which_source = luigi.Parameter() - which_target = luigi.Parameter() - - def requires(self): - return WeightedBatch(self.which_source, self.which_target) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - sp.FINALS_FOLDER, - "weight_distribution_" + - self.which_source + - "_adapted_to_" + - self.which_target + - ".png")) - - def run(self): - # get data - df_source = pd.read_csv(self.input().path, header=[0, 1]) - - df_source["weights"].plot.hist(bins=100) - plt.axvline(x=1, ymin=0, ymax=df_source.shape[0]) - # TODO: add cumsum on top - - # finally save the figure - plt.savefig(self.output().path, dpi=500, - bbox_inches='tight') - - -class FeatureDistributionPlot(luigi.Task): - which_source = luigi.Parameter() - which_target = luigi.Parameter() - - def requires(self): - return WeightedBatch(self.which_source, self.which_target), \ - tasks_mc.CameraBatch(self.which_target) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - sp.FINALS_FOLDER, - "feature_distribution_" + - self.which_source + - "_adapted_to_" + - self.which_target + - ".png")) - - def run(self): - # get data - df_source = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_target = pd.read_csv(self.input()[1].path, header=[0, 1]) - - df_f_source = format_dataframe_for_distribution_plotting(df_source) - df_f_target = format_dataframe_for_distribution_plotting(df_target) - df_f_adapted = format_dataframe_for_distribution_plotting(df_source, - weights=df_source["weights"].values.squeeze()) - - # build a combined df - df_f_source["data"] = "source" - df_f_target["data"] = "target" - df_f_adapted["data"] = "adapted" - df = pd.concat([df_f_source, df_f_target, df_f_adapted]) - - # do the plotting - grid = sns.FacetGrid(df, col="w", hue="data", col_wrap=3, size=1.5) - grid.map(plt.plot, "bins", "frequency") - - # tidy up plot - grid.fig.tight_layout(w_pad=1) - grid.add_legend() - grid.set(xticks=(0, 1)) - - # finally save the figure - plt.savefig(self.output().path, dpi=500) - - -class DAvNormalPlot(luigi.Task): - which_train = luigi.Parameter() - which_test = luigi.Parameter() - which_train_no_covariance_shift = luigi.Parameter() - - def requires(self): - return WeightedBatch(self.which_train, self.which_test), \ - tasks_mc.CameraBatch(self.which_test), \ - tasks_mc.CameraBatch(self.which_train_no_covariance_shift) - - def output(self): - return luigi.LocalTarget(os.path.join(sp.ROOT_FOLDER, - sp.RESULTS_FOLDER, - sp.FINALS_FOLDER, - "da_v_normal_train_" + - self.which_train + - "_test_" + self.which_test + - ".png")) - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - df_train_no_covariance_shift = pd.read_csv(self.input()[2].path, - header=[0, 1]) - - evaluation_setups = [EvaluationStruct("Proposed", rf)] - # evaluate the different methods - df_adapted = evaluate_data(df_train, noise_levels, - df_test, noise_levels, - evaluation_setups=evaluation_setups) - df_adapted["data"] = "adapted" - df_no_adaptation = evaluate_data( - df_train.drop("weights", axis=1), noise_levels, - df_test, noise_levels, - evaluation_setups=evaluation_setups) - df_no_adaptation["data"] = "source" - df_no_covariance_shift = evaluate_data( - df_train_no_covariance_shift, noise_levels, - df_test, noise_levels, - evaluation_setups=evaluation_setups) - df_no_covariance_shift["data"] = "target" - df = pd.concat([df_adapted, df_no_adaptation, df_no_covariance_shift]) - - # plot it - sns.boxplot(data=df, x="noise added [sigma %]", y="Errors", hue="data", - hue_order=["source", "adapted", "target"], fliersize=0) - # tidy up plot - plt.ylim((0, 40)) - plt.legend(loc='upper left') - - # finally save the figure - plt.savefig(self.output().path, dpi=500) - - -def format_dataframe_for_distribution_plotting(df, weights=None): - if weights is None: - weights = np.ones(df.shape[0]) - - bins = np.arange(0, 1, 0.01) - - # we're only interested in reflectance information - df_formatted = df.loc[:, "reflectances"] - # to [nm] for plotting - df_formatted.rename(columns=lambda x: float(x)*10**9, inplace=True) - - # transform data to a histogram - df_formatted = df_formatted.apply(lambda x: - pd.Series(np.histogram(x, bins=bins, - weights=weights, - normed=True)[0]), - axis=0) - # convert to long form using bins as identifier - df_formatted["bins"] = bins[1:] - df_formatted = pd.melt(df_formatted, id_vars=["bins"], - var_name="w", value_name="frequency") - - return df_formatted - - -if __name__ == '__main__': - logging.basicConfig(filename=os.path.join(sp.LOG_FOLDER, - "da_in_silico_plots" + - str(datetime.datetime.now()) + - '.log'), - level=logging.INFO) - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - luigi.interface.setup_interface_logging() - - source_domain = "ipcai_revision_generic" - target_domain = "ipcai_revision_colon_test" - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - # check how the graph looks with same domains for training and testing - w.add(DaNoisePlot(which_train="ipcai_revision_colon_train", - which_test="ipcai_revision_colon_test")) - # check how the graph looks without domain adaptation - w.add(NoisePlot(which_train=source_domain, which_test=target_domain)) - # Set a different testing domain to evaluate domain sensitivity - w.add(DaNoisePlot(which_train=source_domain, which_test=target_domain)) - - w.add(WeightDistributionPlot(which_source=source_domain, - which_target=target_domain)) - w.add(FeatureDistributionPlot(which_source=source_domain, - which_target=target_domain)) - # also plot distributions for equal domains to check for errors in data - w.add(FeatureDistributionPlot(which_source="ipcai_revision_colon_mean_scattering_train", - which_target="ipcai_revision_colon_mean_scattering_test")) - # plot how the generating model data (e.g. sao2 and vhb) is distributed - w.add(GeneratingDistributionPlot(which_source=source_domain, - which_target=target_domain)) - w.add(DAvNormalPlot(which_train=source_domain, which_test=target_domain, - which_train_no_covariance_shift="ipcai_revision_colon_train")) - w.run() diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/__init__.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_silico.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_silico.py deleted file mode 100644 index 0db37b69f9..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_silico.py +++ /dev/null @@ -1,335 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 11:09:18 2015 - -@author: wirkert -""" - -import os -import logging -import datetime -from collections import namedtuple - -import matplotlib -import numpy as np -import pandas as pd -from pandas import DataFrame -import luigi -import matplotlib.pyplot as plt -from sklearn.ensemble.forest import RandomForestRegressor - -import tasks_mc -from regression.preprocessing import preprocess, preprocess2 -from regression.linear import LinearSaO2Unmixing - -import commons - -sc = commons.ScriptCommons() - -sc.add_dir("IN_SILICO_RESULTS_PATH", os.path.join(sc.get_dir("RESULTS_FOLDER"), - "in_silico")) - -sc.other["RECORDED_WAVELENGTHS"] = np.arange(470, 680, 10) * 10 ** -9 - -w_standard = 10. # for this evaluation we add 10% noise - -font = {'family' : 'normal', - 'size' : 20} - -matplotlib.rc('font', **font) - - -# setup standard random forest -rf = RandomForestRegressor(10, min_samples_leaf=10, max_depth=9, n_jobs=-1) -EvaluationStruct = namedtuple("EvaluationStruct", - "name regressor") -# standard evaluation setup -standard_evaluation_setups = [EvaluationStruct("Linear Beer-Lambert", - LinearSaO2Unmixing()) - , EvaluationStruct("Proposed", rf)] - -# color palette -my_colors = ["red", "green"] - -# standard noise levels -noise_levels = np.array([1,2,3,4,5,6,7,8,9,10, - 15,20,30,40,50,100,150,200]).astype("float") - - -class TrainingSamplePlot(luigi.Task): - which_train = luigi.Parameter() - which_test = luigi.Parameter() - - def requires(self): - return tasks_mc.CameraBatch(self.which_train), \ - tasks_mc.CameraBatch(self.which_test) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("IN_SILICO_RESULTS_PATH"), - "sample_plot_train_" + - self.which_train + - "_test_" + self.which_test + - ".pdf")) - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - - # for this plot we write a custom evaluation function as it is built - # a little different - - # create a new dataframe which will hold all the generated errors - df = pd.DataFrame() - - nr_training_samples = np.arange(10, 15010, 50).astype(int) - # not very pythonic, don't care - for n in nr_training_samples: - X_test, y_test = preprocess(df_test, snr=w_standard) - # only take n samples for training - X_train, y_train = preprocess(df_train, nr_samples=n, - snr=w_standard) - - regressor = rf - regressor.fit(X_train, y_train) - y_pred = regressor.predict(X_test) - # save results to a dataframe - errors = np.abs(y_pred - y_test) - errors = errors.reshape(len(errors), 1) - current_df = DataFrame(errors * 100, - columns=["Errors"]) - current_df["Method"] = "Proposed" - current_df["Number Samples"] = n / 10**3. - df = pd.concat([df, current_df], ignore_index=True) - logging.info( - "Finished training classifier with {0} samples".format( - str(n))) - - df = df.groupby("Number Samples").describe() - # get the error description in the rows: - df = df.unstack(-1) - # get rid of multiindex by dropping "Error" level - df.columns = df.columns.droplevel(0) - - plt.figure() - plt.plot(df.index, df["50%"], color="green") - - # tidy up the plot - plt.xlabel("number of training samples / 1000") - plt.ylabel("absolute error [%]") - plt.ylim((0, 20)) - plt.xlim((0, 15)) - plt.grid() - - # finally save the figure - plt.savefig(self.output().path, mode="pdf", dpi=500, - bbox_inches='tight') - - -class VhbPlot(luigi.Task): - which_train = luigi.Parameter() - which_test = luigi.Parameter() - - def requires(self): - return tasks_mc.CameraBatch(self.which_train), \ - tasks_mc.CameraBatch(self.which_test) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("IN_SILICO_RESULTS_PATH"), - "vhb_noise_plot_train_" + - self.which_train + - "_test_" + self.which_test + - ".pdf")) - - @staticmethod - def preprocess_vhb(batch, nr_samples=None, snr=None, - magnification=None, bands_to_sortout=None): - """ For evaluating vhb we extract labels for vhb instead of sao2""" - X, y = preprocess2(batch, nr_samples, snr, - magnification, bands_to_sortout) - - return X, y["vhb"].values - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - - # for vhb we only evaluate the proposed method since the linear - # beer-lambert is not applicable - evaluation_setups = [EvaluationStruct("Proposed", rf)] - df = evaluate_data(df_train, noise_levels, df_test, noise_levels, - evaluation_setups=evaluation_setups, - preprocessing=self.preprocess_vhb) - standard_plotting(df, color_palette=["green"], - xytext_position=(2, 3)) - plt.ylim((0, 4)) - - # finally save the figure - plt.savefig(self.output().path, dpi=500, - bbox_inches='tight') - - -class NoisePlot(luigi.Task): - which_train = luigi.Parameter() - which_test = luigi.Parameter() - - def requires(self): - return tasks_mc.CameraBatch(self.which_train), \ - tasks_mc.CameraBatch(self.which_test) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("IN_SILICO_RESULTS_PATH"), - "noise_plot_train_" + - self.which_train + - "_test_" + self.which_test + - ".pdf")) - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - - df = evaluate_data(df_train, noise_levels, df_test, noise_levels) - standard_plotting(df) - - # finally save the figure - plt.savefig(self.output().path, mode="pdf", dpi=500, - bbox_inches='tight') - - -class WrongNoisePlot(luigi.Task): - which_train = luigi.Parameter() - which_test = luigi.Parameter() - train_snr = luigi.FloatParameter() - - def requires(self): - return tasks_mc.CameraBatch(self.which_train), \ - tasks_mc.CameraBatch(self.which_test) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("IN_SILICO_RESULTS_PATH"), - str(self.train_snr) + - "_wrong_noise_plot_train_" + - self.which_train + - "_test_" + self.which_test + - ".pdf")) - - def run(self): - # get data - df_train = pd.read_csv(self.input()[0].path, header=[0, 1]) - df_test = pd.read_csv(self.input()[1].path, header=[0, 1]) - - # do same as in NoisePlot but with standard noise input - df = evaluate_data(df_train, - np.ones_like(noise_levels) * self.train_snr, - df_test, noise_levels) - standard_plotting(df) - - # finally save the figure - plt.savefig(self.output().path, mode="pdf", dpi=500, - bbox_inches='tight') - - -def evaluate_data(df_train, w_train, df_test, w_test, - evaluation_setups=None, preprocessing=None): - """ Our standard method to evaluate the data. It will fill a DataFrame df - which saves the errors for each evaluated setup""" - if evaluation_setups is None: - evaluation_setups = standard_evaluation_setups - if preprocessing is None: - preprocessing = preprocess - if ("weights" in df_train) and df_train["weights"].size > 0: - weights = df_train["weights"].as_matrix().squeeze() - else: - weights = np.ones(df_train.shape[0]) - - # create a new dataframe which will hold all the generated errors - df = pd.DataFrame() - for one_w_train, one_w_test in zip(w_train, w_test): - # setup testing function - X_test, y_test = preprocessing(df_test, snr=one_w_test) - # extract noisy data - X_train, y_train = preprocessing(df_train, snr=one_w_train) - for e in evaluation_setups: - regressor = e.regressor - regressor.fit(X_train, y_train, weights) - y_pred = regressor.predict(X_test) - # save results to a dataframe - errors = np.abs(y_pred - y_test) - errors = errors.reshape(len(errors), 1) - current_df = DataFrame(errors * 100, - columns=["Errors"]) - current_df["Method"] = e.name - current_df["SNR"] = int(one_w_test) - df = pd.concat([df, current_df], ignore_index=True) - - return df - - -def standard_plotting(df, color_palette=None, xytext_position=None): - if color_palette is None: - color_palette = my_colors - if xytext_position is None: - xytext_position = (2, 15) - - plt.figure() - - # group it by method and noise level and get description on the errors - df_statistics = df.groupby(['Method', 'SNR']).describe() - # get the error description in the rows: - df_statistics = df_statistics.unstack(-1) - # get rid of multiindex by dropping "Error" level - df_statistics.columns = df_statistics.columns.droplevel(0) - - # iterate over methods to plot linegraphs with error tube - # probably this can be done nicer, but no idea how exactly - - for color, method in zip( - color_palette, df_statistics.index.get_level_values("Method").unique()): - df_method = df_statistics.loc[method] - plt.plot(df_method.index, df_method["50%"], - color=color, label=method) - plt.fill_between(df_method.index, df_method["25%"], df_method["75%"], - facecolor=color, edgecolor=color, - alpha=0.5) - # tidy up the plot - plt.ylim((0, 40)) - plt.gca().set_xticks(np.arange(0, 200, 10), minor=True) - plt.xlabel("SNR") - plt.ylabel("absolute error [%]") - plt.grid() - plt.legend() - - -if __name__ == '__main__': - - sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") - sc.create_folders() - - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "in_silico_plots_" + - str(datetime.datetime.now()) + - '.log'), - level=logging.INFO) - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - luigi.interface.setup_interface_logging() - - train = "ipcai_revision_colon_mean_scattering_train" - test = "ipcai_revision_colon_mean_scattering_test" - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - w.add(TrainingSamplePlot(which_train=train, which_test=test)) - w.add(NoisePlot(which_train=train, which_test=test)) - w.add(WrongNoisePlot(which_train=train, which_test=test, train_snr=10.)) - w.add(WrongNoisePlot(which_train=train, which_test=test, train_snr=50.)) - w.add(WrongNoisePlot(which_train=train, which_test=test, train_snr=200.)) - # Set a different testing domain to evaluate domain sensitivity - w.add(NoisePlot(which_train=train, - which_test="ipcai_revision_generic_mean_scattering_test")) - w.add(VhbPlot(which_train=train, which_test=test)) - w.run() diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_liver.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_liver.py deleted file mode 100644 index 2f547afe3f..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_liver.py +++ /dev/null @@ -1,294 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 11:09:18 2015 - -@author: wirkert -""" - - -import Image -import ImageEnhance -import logging -import datetime - -import SimpleITK as sitk -import matplotlib - -from msi.io.nrrdreader import NrrdReader -import msi.normalize as norm -from regression.estimation import estimate_image -from tasks_common import * -import commons -from msi.io.tiffringreader import TiffRingReader - -TiffRingReader.RESIZE_FACTOR = 0.5 - -sc = commons.ScriptCommons() - -sc.add_dir("LIVER_DATA", - os.path.join(sc.get_dir("DATA_FOLDER"), "liver_images")) -sc.add_dir("LIVER_RESULTS", os.path.join(sc.get_dir("RESULTS_FOLDER"), "liver")) - -sc.add_dir("FILTER_TRANSMISSIONS", - os.path.join(sc.get_dir("DATA_FOLDER"), - "filter_transmissions")) - -font = {'family' : 'normal', - 'size' : 30} -matplotlib.rc('font', **font) - - -class ResultsFile(luigi.Task): - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("LIVER_RESULTS"), - "results.csv")) - - -class OxyAndVhbOverTimeTask(luigi.Task): - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("LIVER_RESULTS"), - "liver_oxy_over_time.pdf")) - - def requires(self): - return ResultsFile() - - def run(self): - df = pd.read_csv(self.input().path, index_col=0) - # determine times from start: - image_name_strings = df["image name"].values - time_strings = map(lambda s: s[ - s.find("2014-08-03_")+11:s.find("2014-08-03_")+19], - image_name_strings) - time_in_s = map(lambda s: int(s[0:2]) * 3600 + - int(s[3:5]) * 60 + - int(s[6:]), time_strings) - df["time since drug delivery [s]"] = np.array(time_in_s) - time_in_s[0] - - # print oxy over time as scatterplot. - ax = df.plot.scatter(x="time since drug delivery [s]", - y="oxygenation mean [%]", - s=100, alpha=0.5, - fontsize=30) - ax.set_xlim((-1, 70)) - - plt.axvline(x=0, ymin=0, ymax=1, linewidth=2) - plt.axvline(x=56, ymin=0, ymax=1, linewidth=2) - ax.annotate('drug delivery', xy=(0, ax.get_ylim()[1]), - xycoords='data', xytext=(0, 0), - fontsize=30, - textcoords='offset points') - ax.annotate('porcine death', xy=(56, ax.get_ylim()[1]), - xycoords='data', xytext=(-100, 0), - fontsize=30, - textcoords='offset points') - ax.yaxis.label.set_size(30) - ax.xaxis.label.set_size(30) - plt.grid() - - df.to_csv(self.input().path) - - # create and save vhb plot - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight', mode="pdf") - - # print vhb over time as scatterplot. - ax = df.plot.scatter(x="time since drug delivery [s]", - y="blood volume fraction mean [%]", - s=100, alpha=0.5, - fontsize=30) - ax.set_xlim((-1, 70)) - - plt.axvline(x=0, ymin=0, ymax=1, linewidth=2) - plt.axvline(x=56, ymin=0, ymax=1, linewidth=2) - ax.annotate('drug delivery', xy=(0, ax.get_ylim()[1]), - xycoords='data', xytext=(0, 0), - fontsize=30, - textcoords='offset points') - ax.annotate('porcine death', xy=(56, ax.get_ylim()[1]), - xycoords='data', xytext=(-100, 0), - fontsize=30, - textcoords='offset points') - ax.yaxis.label.set_size(30) - ax.xaxis.label.set_size(30) - plt.grid() - - plt.savefig(self.output().path + "_vhb_mean.pdf", - dpi=250, bbox_inches='tight', mode="pdf") - - -class IPCAICreateOxyImageTask(luigi.Task): - image_name = luigi.Parameter() - df_prefix = luigi.Parameter() - - def requires(self): - return IPCAITrainRegressor(df_prefix=self.df_prefix), \ - Flatfield(flatfield_folder=sc.get_full_dir("FLAT_FOLDER")), \ - SingleMultispectralImage(image=os.path.join( - sc.get_full_dir("LIVER_DATA"), self.image_name)), \ - Dark(dark_folder=sc.get_full_dir("DARK_FOLDER")) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("LIVER_RESULTS"), - self.image_name + "_" + - self.df_prefix + - "_oxy_summary" + ".png")) - - def run(self): - nrrd_reader = NrrdReader() - tiff_ring_reader = TiffRingReader() - # read the flatfield - flat = nrrd_reader.read(self.input()[1].path) - dark = nrrd_reader.read(self.input()[3].path) - # read the msi - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - msi, segmentation = tiff_ring_reader.read(self.input()[2].path, - nr_filters) - - # only take into account not saturated pixels. - segmentation = np.max(msi.get_image(), axis=-1) < 2000. - - # read the regressor - e_file = open(self.input()[0].path, 'r') - e = pickle.load(e_file) - - # correct image setup - position_filter_nr_in_string = self.image_name.find(" 2014") - 1 - filter_nr = int(self.image_name[ - position_filter_nr_in_string:position_filter_nr_in_string+1]) - original_order = np.arange(nr_filters) - new_image_order = np.concatenate(( - original_order[nr_filters - filter_nr:], - original_order[:nr_filters - filter_nr])) - # resort msi to restore original order - msimani.get_bands(msi, new_image_order) - # correct by flatfield - msimani.image_correction(msi, flat, dark) - - # create artificial rgb - rgb_image = msi.get_image()[:, :, [2, 3, 1]] - rgb_image /= np.max(rgb_image) - rgb_image *= 255. - - # preprocess the image - # sortout unwanted bands - print "1" - # zero values would lead to infinity logarithm, thus clip. - msi.set_image(np.clip(msi.get_image(), 0.00001, 2. ** 64)) - # normalize to get rid of lighting intensity - norm.standard_normalizer.normalize(msi) - # transform to absorption - msi.set_image(-np.log(msi.get_image())) - # normalize by l2 for stability - norm.standard_normalizer.normalize(msi, "l2") - print "2" - # estimate - sitk_image, time = estimate_image(msi, e) - image = sitk.GetArrayFromImage(sitk_image) - - plt.figure() - print "3" - rgb_image = rgb_image.astype(np.uint8) - im = Image.fromarray(rgb_image, 'RGB') - enh_brightness = ImageEnhance.Brightness(im) - im = enh_brightness.enhance(5.) - plotted_image = np.array(im) - top_left_axis = plt.gca() - top_left_axis.imshow(plotted_image, interpolation='nearest') - top_left_axis.xaxis.set_visible(False) - top_left_axis.yaxis.set_visible(False) - - plt.set_cmap("jet") - print "4" - # plot parametric maps - # first oxygenation - plt.figure() - oxy_image = image[:, :, 0] - segmentation[0, 0] = 1 - segmentation[0, 1] = 1 - oxy_image = np.ma.masked_array(oxy_image, ~segmentation) - oxy_image[np.isnan(oxy_image)] = 0. - oxy_image[np.isinf(oxy_image)] = 0. - oxy_mean = np.mean(oxy_image) - oxy_image[0, 0] = 0.0 - oxy_image[0, 1] = 1. - plot_image(oxy_image[:, :], plt.gca()) - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight') - # second blood volume fraction - plt.figure() - vhb_image = image[:, :, 1] - vhb_image = np.ma.masked_array(vhb_image, ~segmentation) - vhb_image[np.isnan(vhb_image)] = 0. - vhb_image[np.isinf(vhb_image)] = 0. - vhb_image[0, 0] = 0.0 - vhb_image[0, 1] = 0.1 - vhb_image = np.clip(vhb_image, 0.0, 0.1) - vhb_mean = np.mean(vhb_image) - plot_image(vhb_image, plt.gca()) - plt.savefig(self.output().path + "vhb.png", - dpi=250, bbox_inches='tight') - - # store results summary in dataframe - df_image_results = pd.DataFrame(data=np.expand_dims([self.image_name, - oxy_mean * 100., - vhb_mean * 100., - time], 0), - columns=["image name", - "oxygenation mean [%]", - "blood volume fraction mean [%]", - "time to estimate"]) - - results_file = os.path.join(sc.get_full_dir("LIVER_RESULTS"), - "results.csv") - if os.path.isfile(results_file): - df_results = pd.read_csv(results_file, index_col=0) - df_results = pd.concat((df_results, df_image_results)).reset_index( - drop=True - ) - else: - df_results = df_image_results - - df_results.to_csv(results_file) - - print "5" - plt.close("all") - - -if __name__ == '__main__': - - # create a folder for the results if necessary - sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") - sc.create_folders() - - # root folder there the data lies - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "liver" + - str(datetime.datetime.now()) + - '.log'), level=logging.INFO) - luigi.interface.setup_interface_logging() - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - - onlyfiles = get_image_files_from_folder(sc.get_full_dir("LIVER_DATA")) - - first_invivo_image_files = filter(lambda image_name: "0 2014" in image_name, - onlyfiles) - - for f in first_invivo_image_files: - main_task = IPCAICreateOxyImageTask(image_name=f, - df_prefix="ipcai_revision_colon_mean_scattering_train") - w.add(main_task) - - w.run() - - oxygenation_over_time_task = OxyAndVhbOverTimeTask() - w.add(oxygenation_over_time_task) - w.run() - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_small_bowel.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_small_bowel.py deleted file mode 100644 index 6ce3da2895..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_analyze_ipcai_in_vivo_small_bowel.py +++ /dev/null @@ -1,276 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 14 11:09:18 2015 - -@author: wirkert -""" - -import Image -import ImageEnhance -import logging -import datetime - -import SimpleITK as sitk -import matplotlib - -from msi.io.nrrdreader import NrrdReader -import msi.normalize as norm -from regression.estimation import estimate_image -from tasks_common import * -import commons -from msi.io.tiffringreader import TiffRingReader - -TiffRingReader.RESIZE_FACTOR = 0.5 - -sc = commons.ScriptCommons() - - -sc.add_dir("SMALL_BOWEL_DATA", - os.path.join(sc.get_dir("DATA_FOLDER"), "small_bowel_images")) - -sc.add_dir("SMALL_BOWEL_RESULT", os.path.join(sc.get_dir("RESULTS_FOLDER"), - "small_bowel")) - -sc.add_dir("FILTER_TRANSMISSIONS", - os.path.join(sc.get_dir("DATA_FOLDER"), - "filter_transmissions")) - -font = {'family' : 'normal', - 'size' : 25} -matplotlib.rc('font', **font) - - -class ResultsFile(luigi.Task): - - def output(self): - return luigi.LocalTarget(os.path.join( - sc.get_full_dir("SMALL_BOWEL_RESULT"), "results.csv")) - - -class OxyOverTimeTask(luigi.Task): - - def output(self): - return luigi.LocalTarget(os.path.join( - sc.get_full_dir("SMALL_BOWEL_RESULT"), - "colon_oxy_over_time.pdf")) - - def requires(self): - return ResultsFile() - - def run(self): - df = pd.read_csv(self.input().path, index_col=0) - - # determine times from start: - image_name_strings = df["image name"].values - time_strings = map(lambda s: s[ - s.find("2015-10-08_")+11:s.find("2015-10-08_")+19], - image_name_strings) - time_in_s = map(lambda s: int(s[0:2]) * 3600 + - int(s[3:5]) * 60 + - int(s[6:]), time_strings) - df["time since first frame [s]"] = np.array(time_in_s) - time_in_s[0] - df["time since applying first clip [s]"] = df["time since first frame [s]"] - 4 - # print oxy over time as scatterplot. - plt.figure() - ax = df.plot.scatter(x="time since applying first clip [s]", - y="oxygenation mean [%]", fontsize=30, - s=50, alpha=0.5) - ax.set_xlim((-5, 600)) - - plt.axvline(x=0, ymin=0, ymax=1, linewidth=2) - plt.axvline(x=39, ymin=0, ymax=1, linewidth=2) - plt.axvline(x=100, ymin=0, ymax=1, linewidth=2) - plt.axvline(x=124, ymin=0, ymax=1, linewidth=2) - ax.annotate('1', xy=(0, ax.get_ylim()[1]), - fontsize=18, - color="blue", - xycoords='data', xytext=(-5, 0), - textcoords='offset points') - ax.annotate('2', xy=(39, ax.get_ylim()[1]), - fontsize=18, - color="blue", - xycoords='data', xytext=(-5, 0), - textcoords='offset points') - ax.annotate('3', xy=(100, ax.get_ylim()[1]), - fontsize=18, - color="blue", - xycoords='data', xytext=(-5, 0), - textcoords='offset points') - ax.annotate('4', xy=(124, ax.get_ylim()[1]), - fontsize=18, - color="blue", - xycoords='data', xytext=(-5, 0), - textcoords='offset points') - - plt.grid() - - df.to_csv(self.input().path) - - # save - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight', mode="pdf") - - -def plot_image(image, axis): - im2 = axis.imshow(image, interpolation='nearest', alpha=1.0) - # axis.set_title(title, fontsize=5) - # divider = make_axes_locatable(axis) - # cax = divider.append_axes("right", size="10%", pad=0.05) - # cbar = plt.colorbar(im2, cax=cax) - # cbar.ax.tick_params(labelsize=5) - axis.xaxis.set_visible(False) - - -class IPCAICreateOxyImageTask(luigi.Task): - image_name = luigi.Parameter() - df_prefix = luigi.Parameter() - - def requires(self): - return IPCAITrainRegressor(df_prefix=self.df_prefix), \ - Flatfield(flatfield_folder=sc.get_full_dir("FLAT_FOLDER")), \ - SingleMultispectralImage(image=self.image_name), \ - Dark(dark_folder=sc.get_full_dir("DARK_FOLDER")) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("SMALL_BOWEL_RESULT"), - os.path.split(self.image_name)[1] + - "_" + self.df_prefix + - "_summary" + ".png")) - - def run(self): - nrrd_reader = NrrdReader() - tiff_ring_reader = TiffRingReader() - # read the flatfield - flat = nrrd_reader.read(self.input()[1].path) - dark = nrrd_reader.read(self.input()[3].path) - # read the msi - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - msi, segmentation = tiff_ring_reader.read(self.input()[2].path, - nr_filters) - # only take into account not saturated pixels. - segmentation = np.logical_and(segmentation, - (np.max(msi.get_image(), - axis=-1) < 1000.)) - - # read the regressor - e_file = open(self.input()[0].path, 'r') - e = pickle.load(e_file) - - # correct image setup - filter_nr = int(self.image_name[-6:-5]) - original_order = np.arange(nr_filters) - new_image_order = np.concatenate(( - original_order[nr_filters - filter_nr:], - original_order[:nr_filters - filter_nr])) - # resort msi to restore original order - msimani.get_bands(msi, new_image_order) - # correct by flatfield - msimani.image_correction(msi, flat, dark) - - # create artificial rgb - rgb_image = msi.get_image()[:, :, [2, 3, 1]] - rgb_image /= np.max(rgb_image) - rgb_image *= 255. - - # preprocess the image - # sortout unwanted bands - print "1" - # zero values would lead to infinity logarithm, thus clip. - msi.set_image(np.clip(msi.get_image(), 0.00001, 2. ** 64)) - # normalize to get rid of lighting intensity - norm.standard_normalizer.normalize(msi) - # transform to absorption - msi.set_image(-np.log(msi.get_image())) - # normalize by l2 for stability - norm.standard_normalizer.normalize(msi, "l2") - print "2" - # estimate - sitk_image, time = estimate_image(msi, e) - image = sitk.GetArrayFromImage(sitk_image) - - plt.figure() - print "3" - rgb_image = rgb_image.astype(np.uint8) - im = Image.fromarray(rgb_image, 'RGB') - enh_brightness = ImageEnhance.Brightness(im) - im = enh_brightness.enhance(10.) - plotted_image = np.array(im) - top_left_axis = plt.gca() - top_left_axis.imshow(plotted_image, interpolation='nearest') - top_left_axis.xaxis.set_visible(False) - top_left_axis.yaxis.set_visible(False) - - plt.set_cmap("jet") - print "4" - # plot parametric maps - segmentation[0, 0] = 1 - segmentation[0, 1] = 1 - oxy_image = np.ma.masked_array(image[:, :, 0], ~segmentation) - oxy_image[np.isnan(oxy_image)] = 0. - oxy_image[np.isinf(oxy_image)] = 0. - oxy_mean = np.mean(oxy_image) - oxy_image[0, 0] = 0.0 - oxy_image[0, 1] = 1. - - plot_image(oxy_image[:, :], plt.gca()) - - df_image_results = pd.DataFrame(data=np.expand_dims([self.image_name, - oxy_mean * 100., - time], 0), - columns=["image name", - "oxygenation mean [%]", - "time to estimate"]) - - results_file = os.path.join(sc.get_full_dir("SMALL_BOWEL_RESULT"), - "results.csv") - if os.path.isfile(results_file): - df_results = pd.read_csv(results_file, index_col=0) - df_results = pd.concat((df_results, df_image_results)).reset_index( - drop=True - ) - else: - df_results = df_image_results - - df_results.to_csv(results_file) - - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight') - plt.close("all") - - -if __name__ == '__main__': - - # create a folder for the results if necessary - sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") - sc.create_folders() - - # root folder there the data lies - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "small_bowel_images" + - str(datetime.datetime.now()) + - '.log'), - level=logging.INFO) - luigi.interface.setup_interface_logging() - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - - - # determine files to process - files = get_image_files_from_folder(sc.get_full_dir("SMALL_BOWEL_DATA"), - suffix="F0.tiff", fullpath=True) - - for f in files: - main_task = IPCAICreateOxyImageTask(image_name=f, - df_prefix="ipcai_revision_colon_mean_scattering_te") - w.add(main_task) - w.run() - - oxygenation_over_time_task = OxyOverTimeTask() - w.add(oxygenation_over_time_task) - w.run() - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_calculate_spectra.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_calculate_spectra.py deleted file mode 100644 index 5ceb764c33..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/script_calculate_spectra.py +++ /dev/null @@ -1,123 +0,0 @@ -''' -Created on Sep 9, 2015 - -@author: wirkert -''' - - -import logging -import datetime -import os -import time - -import numpy as np -import luigi - -import commons -import mc.factories as mcfac -from mc.sim import SimWrapper -from mc.create_spectrum import create_spectrum - -# parameter setting -NR_BATCHES = 100 -NR_ELEMENTS_IN_BATCH = 1000 -# the wavelengths to be simulated -WAVELENGHTS = np.arange(450, 720, 2) * 10 ** -9 -NR_PHOTONS = 10 ** 6 - -# experiment configuration -MCI_FILENAME = "./temp.mci" -MCO_FILENAME = "temp.mco" -# this path definitly needs to be adapted by you -PATH_TO_MCML = "/home/wirkert/workspace/monteCarlo/gpumcml/fast-gpumcml/" -EXEC_MCML = "gpumcml.sm_20" - - -sc = commons.ScriptCommons() - - -class CreateSpectraTask(luigi.Task): - df_prefix = luigi.Parameter() - batch_nr = luigi.IntParameter() - nr_samples = luigi.IntParameter() - factory = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("MC_DATA_FOLDER"), - self.df_prefix + "_" + - str(self.batch_nr) + ".txt")) - - def run(self): - start = time.time() - # setup simulation wrapper - sim_wrapper = SimWrapper() - sim_wrapper.set_mci_filename(MCI_FILENAME) - sim_wrapper.set_mcml_executable(os.path.join(PATH_TO_MCML, EXEC_MCML)) - # setup model - tissue_model = self.factory.create_tissue_model() - tissue_model.set_mci_filename(sim_wrapper.mci_filename) - tissue_model.set_mco_filename(MCO_FILENAME) - tissue_model.set_nr_photons(NR_PHOTONS) - # setup array in which data shall be stored - batch = self.factory.create_batch_to_simulate() - batch.create_parameters(self.nr_samples) - # dataframe created by batch: - df = batch.df - # add reflectance column to dataframe - for w in WAVELENGHTS: - df["reflectances", w] = np.NAN - - # for each instance of our tissue model - for i in range(df.shape[0]): - # set the desired element in the dataframe to be simulated - tissue_model.set_dataframe_row(df.loc[i, :]) - logging.info("running simulation " + str(i) + " for\n" + - str(tissue_model)) - reflectances = create_spectrum(tissue_model, sim_wrapper, - WAVELENGHTS) - # store in dataframe - for r, w in zip(reflectances, WAVELENGHTS): - df["reflectances", w][i] = r - - # clean up temporarily created files - os.remove(MCI_FILENAME) - created_mco_file = os.path.join(PATH_TO_MCML, MCO_FILENAME) - if os.path.isfile(created_mco_file): - os.remove(created_mco_file) - # save the created output - f = open(self.output().path, 'w') - df.to_csv(f) - - end = time.time() - logging.info("time for creating batch of mc data: %.f s" % - (end - start)) - - -if __name__ == '__main__': - - # create a folder for the results if necessary - sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") - sc.create_folders() - - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "calculate_spectra" + - str(datetime.datetime.now()) + - '.log'), - level=logging.INFO) - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - luigi.interface.setup_interface_logging() - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - BATCH_NUMBERS = np.arange(0, NR_BATCHES, 1) - for i in BATCH_NUMBERS: - colon_task = CreateSpectraTask("ipcai_revision_generic_mean_scattering", - i, - NR_ELEMENTS_IN_BATCH, - mcfac.GenericMeanScatteringFactory()) - w.add(colon_task) - w.run() - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_common.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_common.py deleted file mode 100644 index 7df698175c..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_common.py +++ /dev/null @@ -1,166 +0,0 @@ - -import os -import pickle - -import numpy as np -import pandas as pd -import luigi -from sklearn.ensemble.forest import RandomForestRegressor -import matplotlib.pylab as plt -from mpl_toolkits.axes_grid1 import make_axes_locatable - -import tasks_mc -import commons -from msi.msi import Msi -from msi.io.nrrdwriter import NrrdWriter -import msi.msimanipulations as msimani -from regression.preprocessing import preprocess2 -from msi.io.tiffringreader import TiffRingReader - -sc = commons.ScriptCommons() - -""" -Collection of functions and luigi.Task s which are used by more than one script -""" - - -def get_image_files_from_folder(folder, - prefix="", suffix=".tiff", fullpath=False): - # small helper function to get all the image files in a folder - # it will only return files which end with suffix. - # if fullpath==True it will return the full path of the file, otherwise - # only the filename - # get all filenames - image_files = [f for f in os.listdir(folder) if - os.path.isfile(os.path.join(folder, f))] - image_files.sort() - image_files = [f for f in image_files if f.endswith(suffix)] - image_files = [f for f in image_files if f.startswith(prefix)] - if fullpath: # expand to full path if wished - image_files = [os.path.join(folder, f) for f in image_files] - return image_files - - -def plot_image(image, axis=None, title=None, cmap=None): - if axis is None: - axis = plt.gca() - if cmap is None: - im = axis.imshow(image, interpolation='nearest', alpha=1.0) - else: - im = axis.imshow(image, interpolation='nearest', alpha=1.0, - cmap=cmap) - divider = make_axes_locatable(axis) - cax = divider.append_axes("right", size="20%", pad=0.05) - cbar = plt.colorbar(im, cax=cax) - - axis.xaxis.set_visible(False) - axis.yaxis.set_visible(False) - if title is not None: - axis.set_title(title) - - -class IPCAITrainRegressor(luigi.Task): - df_prefix = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - "reg_small_bowel_" + - self.df_prefix)) - - def requires(self): - return tasks_mc.SpectroCamBatch(self.df_prefix) - - def run(self): - # extract data from the batch - df_train = pd.read_csv(self.input().path, header=[0, 1]) - - X, y = preprocess2(df_train, snr=10.) - # train regressor - reg = RandomForestRegressor(10, min_samples_leaf=10, max_depth=9, - n_jobs=-1) - # reg = KNeighborsRegressor(algorithm="auto") - # reg = LinearRegression() - # reg = sklearn.svm.SVR(kernel="rbf", degree=3, C=100., gamma=10.) - # reg = LinearSaO2Unmixing() - reg.fit(X, y.values) - # reg = LinearSaO2Unmixing() - # save regressor - regressor_file = self.output().open('w') - pickle.dump(reg, regressor_file) - regressor_file.close() - - -class SingleMultispectralImage(luigi.Task): - - image = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(self.image) - - -class Flatfield(luigi.Task): - - flatfield_folder = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - "flatfield.nrrd")) - - def run(self): - tiff_ring_reader = TiffRingReader() - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - - # analyze all the first image files - image_files = get_image_files_from_folder(self.flatfield_folder) - image_files = filter(lambda image_name: "F0" in image_name, image_files) - - # helper function to take maximum of two images - def maximum_of_two_images(image_1, image_name_2): - image_2 = tiff_ring_reader.read(os.path.join(self.flatfield_folder, - image_name_2), - nr_filters)[0].get_image() - return np.maximum(image_1, image_2) - - # now reduce to maximum of all the single images - flat_maximum = reduce(lambda x, y: maximum_of_two_images(x, y), - image_files, 0) - msi = Msi(image=flat_maximum) - msi.set_wavelengths(sc.other["RECORDED_WAVELENGTHS"]) - - # write flatfield as nrrd - writer = NrrdWriter(msi) - writer.write(self.output().path) - - -class Dark(luigi.Task): - dark_folder = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - "dark" + - ".nrrd")) - - def run(self): - tiff_ring_reader = TiffRingReader() - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - - # analyze all the first image files - image_files = get_image_files_from_folder(self.dark_folder, - suffix="F0.tiff") - - # returns the mean dark image vector of all inputted dark image - # overly complicated TODO SW: make this simple code readable. - dark_means = map(lambda image_name: - msimani.calculate_mean_spectrum( - tiff_ring_reader.read(os.path.join(self.dark_folder, image_name), - nr_filters)[0]), - image_files) - dark_means_sum = reduce(lambda x, y: x+y.get_image(), dark_means, 0) - final_dark_mean = dark_means_sum / len(dark_means) - - msi = Msi(image=final_dark_mean) - msi.set_wavelengths(sc.other["RECORDED_WAVELENGTHS"]) - - # write flatfield as nrrd - writer = NrrdWriter(msi) - writer.write(self.output().path) diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_mc.py b/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_mc.py deleted file mode 100644 index c3771dfd9d..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai2016/tasks_mc.py +++ /dev/null @@ -1,155 +0,0 @@ -''' -Created on Sep 10, 2015 - -@author: wirkert -''' - - - -import os - -import pandas as pd -import numpy as np -import luigi -from scipy.interpolate import interp1d -from sklearn.preprocessing import normalize - -import commons -import mc.dfmanipulations as dfmani -from msi.io.spectrometerreader import SpectrometerReader - -sc = commons.ScriptCommons() - - -class SpectrometerFile(luigi.Task): - input_file = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(self.input_file) - - -class FilterTransmission(luigi.Task): - input_file = luigi.Parameter() - - def requires(self): - return SpectrometerFile(self.input_file) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - "processed_transmission" + os.path.split(self.input_file)[1])) - - def run(self): - reader = SpectrometerReader() - filter_transmission = reader.read(self.input().path) - # filter high and low _wavelengths - wavelengths = filter_transmission.get_wavelengths() - fi_image = filter_transmission.get_image() - fi_image[wavelengths < 450 * 10 ** -9] = 0.0 - fi_image[wavelengths > 720 * 10 ** -9] = 0.0 - # filter elements farther away than +- 30nm - file_name = os.path.split(self.input_file)[1] - name_to_float = float(os.path.splitext(file_name)[0]) - fi_image[wavelengths < (name_to_float - 30) * 10 ** -9] = 0.0 - fi_image[wavelengths > (name_to_float + 30) * 10 ** -9] = 0.0 - # elements < 0 are set to 0. - fi_image[fi_image < 0.0] = 0.0 - - # write it to a dataframe - df = pd.DataFrame() - df["wavelengths"] = wavelengths - df["reflectances"] = fi_image - df.to_csv(self.output().path, index=False) - - -class JoinBatches(luigi.Task): - df_prefix = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - self.df_prefix + "_" + - "all" + ".txt")) - - def run(self): - # get all files in the search path - files = [f for f in os.listdir(sc.get_full_dir("MC_DATA_FOLDER")) - if os.path.isfile(os.path.join(sc.get_full_dir("MC_DATA_FOLDER"), f))] - # from these get only those who start with correct batch prefix - df_file_names = [os.path.join(sc.get_full_dir("MC_DATA_FOLDER"), f) - for f in files if f.startswith(self.df_prefix)] - # load these files - dfs = [pd.read_csv(f, header=[0, 1]) for f in df_file_names] - # now join them to one batch - joined_df = pd.concat(dfs, ignore_index=True) - # write it - joined_df.to_csv(self.output().path, index=False) - - -class CameraBatch(luigi.Task): - """takes a batch of reference data and converts it to the spectra - processed by a camera with the specified wavelengths assuming a 10nm FWHM""" - df_prefix = luigi.Parameter() - - def requires(self): - return JoinBatches(self.df_prefix) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - self.df_prefix + - "_all_virtual_camera.txt")) - - def run(self): - # load dataframe - df = pd.read_csv(self.input().path, header=[0, 1]) - # camera batch creation: - dfmani.fold_by_sliding_average(df, 6) - dfmani.interpolate_wavelengths(df, sc.other["RECORDED_WAVELENGTHS"]) - # write it - df.to_csv(self.output().path, index=False) - - -class SpectroCamBatch(luigi.Task): - """ - Same as CameraBatch in purpose but adapts the batch to our very specific - SpectroCam set-up. - """ - df_prefix = luigi.Parameter() - - def requires(self): - # all wavelengths must have been measured for transmission and stored in - # wavelength.txt files (e.g. 470.txt) - filenames = ((sc.other["RECORDED_WAVELENGTHS"] * 10**9).astype(int)).astype(str) - filenames = map(lambda name: FilterTransmission(os.path.join(sc.get_full_dir("FILTER_TRANSMISSIONS"), - name + - ".txt")), - filenames) - - return JoinBatches(self.df_prefix), filenames - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("INTERMEDIATES_FOLDER"), - self.df_prefix + - "_all_spectrocam.txt")) - - def run(self): - # load dataframe - df = pd.read_csv(self.input()[0].path, header=[0, 1]) - # camera batch creation: - new_reflectances = [] - for band in self.input()[1]: - df_filter = pd.read_csv(band.path) - interpolator = interp1d(df_filter["wavelengths"], - df_filter["reflectances"], - assume_sorted=False, bounds_error=False) - # use this to create new reflectances - interpolated_filter = interpolator(df["reflectances"]. - columns.astype(float)) - # normalize band response - normalize(interpolated_filter.reshape(1, -1), norm='l1', copy=False) - folded_reflectance = np.dot(df["reflectances"].values, - interpolated_filter) - new_reflectances.append(folded_reflectance) - new_reflectances = np.array(new_reflectances).T - dfmani.switch_reflectances(df, sc.other["RECORDED_WAVELENGTHS"], - new_reflectances) - # write it - df.to_csv(self.output().path, index=False) diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/__init__.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_image_hdf5.h5_list.txt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_image_hdf5.h5_list.txt deleted file mode 100644 index 1a0f78a1b1..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_image_hdf5.h5_list.txt +++ /dev/null @@ -1 +0,0 @@ -ipcai_image_hdf5.h5 \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_solver.prototxt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_solver.prototxt deleted file mode 100644 index d76ba8c7f1..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_solver.prototxt +++ /dev/null @@ -1,24 +0,0 @@ -# The train/test net protocol buffer definition -train_net: "ipcai_train.prototxt" -test_net: "ipcai_test.prototxt" -# test_iter specifies how many forward passes the test should carry out. -# In the case of MNIST, we have test batch size 100 and 100 test iterations, -# covering the full 10,000 testing images. -test_iter: 100 -# Carry out testing every 500 training iterations. -test_interval: 500 -# The base learning rate, momentum and the weight decay of the network. -base_lr: 0.01 -momentum: 0.0 -weight_decay: 0.0005 -# The learning rate policy -lr_policy: "inv" -gamma: 0.0001 -power: 0.75 -# Display every 100 iterations -display: 1000 -# The maximum number of iterations -max_iter: 10000 -# snapshot intermediate results -snapshot: 5000 -snapshot_prefix: "snapshot" diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test.prototxt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test.prototxt deleted file mode 100644 index 72534d20a0..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test.prototxt +++ /dev/null @@ -1,77 +0,0 @@ -layer { - name: "data" - type: "HDF5Data" - top: "data" - top: "label" - hdf5_data_param { - source: "ipcai_test_hdf5.h5_list.txt" - batch_size: 50 - } -} -layer { - name: "fc1" - type: "InnerProduct" - bottom: "data" - top: "fc1" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu1" - type: "ReLU" - bottom: "fc1" - top: "fc1" -} -layer { - name: "fc2" - type: "InnerProduct" - bottom: "fc1" - top: "fc2" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu2" - type: "ReLU" - bottom: "fc2" - top: "fc2" -} -layer { - name: "score" - type: "InnerProduct" - bottom: "fc2" - top: "score" - inner_product_param { - num_output: 1 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "loss" - type: "EuclideanLoss" - bottom: "score" - bottom: "label" - top: "loss" -} diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_hdf5.h5_list.txt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_hdf5.h5_list.txt deleted file mode 100644 index 691abad4da..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_hdf5.h5_list.txt +++ /dev/null @@ -1 +0,0 @@ -ipcai_test_hdf5.h5 \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_image.prototxt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_image.prototxt deleted file mode 100644 index 6bc1620c4f..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_test_image.prototxt +++ /dev/null @@ -1,70 +0,0 @@ - -layer { - name: "data" - type: "HDF5Data" - top: "data" - hdf5_data_param { - source: "ipcai_image_hdf5.h5_list.txt" - batch_size: 1263612 - } -} -layer { - name: "fc1" - type: "InnerProduct" - bottom: "data" - top: "fc1" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu1" - type: "ReLU" - bottom: "fc1" - top: "fc1" -} -layer { - name: "fc2" - type: "InnerProduct" - bottom: "fc1" - top: "fc2" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu2" - type: "ReLU" - bottom: "fc2" - top: "fc2" -} -layer { - name: "score" - type: "InnerProduct" - bottom: "fc2" - top: "score" - inner_product_param { - num_output: 1 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train.prototxt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train.prototxt deleted file mode 100644 index d79b65aa90..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train.prototxt +++ /dev/null @@ -1,77 +0,0 @@ -layer { - name: "data" - type: "HDF5Data" - top: "data" - top: "label" - hdf5_data_param { - source: "ipcai_train_hdf5.h5_list.txt" - batch_size: 100 - } -} -layer { - name: "fc1" - type: "InnerProduct" - bottom: "data" - top: "fc1" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu1" - type: "ReLU" - bottom: "fc1" - top: "fc1" -} -layer { - name: "fc2" - type: "InnerProduct" - bottom: "fc1" - top: "fc2" - inner_product_param { - num_output: 25 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "relu2" - type: "ReLU" - bottom: "fc2" - top: "fc2" -} -layer { - name: "score" - type: "InnerProduct" - bottom: "fc2" - top: "score" - inner_product_param { - num_output: 1 - weight_filler { - type: "xavier" - } - bias_filler { - type: "constant" - value: 0.1 - } - } -} -layer { - name: "loss" - type: "EuclideanLoss" - bottom: "score" - bottom: "label" - top: "loss" -} diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train_hdf5.h5_list.txt b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train_hdf5.h5_list.txt deleted file mode 100644 index d4b8316827..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/ipcai_train_hdf5.h5_list.txt +++ /dev/null @@ -1 +0,0 @@ -ipcai_train_hdf5.h5 \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_hdf5_database.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_hdf5_database.py deleted file mode 100644 index 3c416e3446..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_hdf5_database.py +++ /dev/null @@ -1,29 +0,0 @@ -import h5py, os -import pandas as pd - -from regression.preprocessing import preprocess - - -def create_hdf5(path_to_simulation_results, hdf5_name): - - df = pd.read_csv(path_to_simulation_results, header=[0, 1]) - - X, y = preprocess(df, snr=10.) - y = y.values - - with h5py.File(hdf5_name,'w') as H: - H.create_dataset('data', data=X ) # note the name X given to the dataset! - H.create_dataset('label', data=y ) # note the name y given to the dataset! - with open(hdf5_name + '_list.txt','w') as L: - L.write(hdf5_name) # list all h5 files you are going to use - - -data_root = "/media/wirkert/data/Data/2016_02_02_IPCAI/results/intermediate" - -TRAIN_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_train_all_spectrocam.txt") -TEST_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_test_all_spectrocam.txt") - -create_hdf5(TRAIN_IMAGES, "ipcai_train_hdf5.h5") -create_hdf5(TEST_IMAGES, "ipcai_test_hdf5.h5") diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_lmdb_database.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_lmdb_database.py deleted file mode 100644 index ad0160c8ce..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_create_lmdb_database.py +++ /dev/null @@ -1,52 +0,0 @@ - -import os - -import pandas as pd -import lmdb -import caffe - -from regression.preprocessing import preprocess - - -def create_lmdb(path_to_simulation_results, lmdb_name): - - df = pd.read_csv(path_to_simulation_results, header=[0, 1]) - - X, y = preprocess(df, snr=10.) - y = y.values * 1000 - - # We need to prepare the database for the size. We'll set it 10 times - # greater than what we theoretically need. There is little drawback to - # setting this too big. If you still run into problem after raising - # this, you might want to try saving fewer entries in a single - # transaction. - map_size = X.nbytes * 10 - - env = lmdb.open(lmdb_name, map_size=map_size) - - with env.begin(write=True) as txn: - # txn is a Transaction object - for i in range(X.shape[0]): - datum = caffe.proto.caffe_pb2.Datum() - datum.channels = X.shape[1] - datum.height = 1 - datum.width = 1 - datum.data = X[i].tobytes() # or .tostring() if numpy < 1.9 - datum.label = int(y[i]) - str_id = '{:08}'.format(i) - - # The encode is only essential in Python 3 - txn.put(str_id.encode('ascii'), datum.SerializeToString()) - - -data_root = "/media/wirkert/data/Data/2016_02_02_IPCAI/results/intermediate" - -TRAIN_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_train_all_spectrocam.txt") -TEST_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_test_all_spectrocam.txt") - -create_lmdb(TRAIN_IMAGES, "ipcai_train_lmdb") -create_lmdb(TEST_IMAGES, "ipcai_test_lmdb") - - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_test_pretrained_model.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_test_pretrained_model.py deleted file mode 100644 index 688ad933ec..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_test_pretrained_model.py +++ /dev/null @@ -1,26 +0,0 @@ - -import time - -import caffe - -from ipcai2016.tasks_common import plot_image - -model_def = 'ipcai_test_image.prototxt' -model_weights = 'snapshot_iter_100000.caffemodel' - -net = caffe.Net(model_def, # defines the structure of the model - model_weights, # contains the trained weights - caffe.TEST) # use test mode (e.g., don't perform dropout) - -### perform classification - -start = time.time() -output = net.forward() -end = time.time() -estimation_time = end - start - -print "time necessary for estimating image parameters: " + str(estimation_time) + "s" - -image = output['score'].reshape(1029,1228) - -plot_image(image) \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_train_caffe.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_train_caffe.py deleted file mode 100644 index c269272502..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_caffe/script_train_caffe.py +++ /dev/null @@ -1,83 +0,0 @@ -from pylab import * - -import caffe -from caffe import layers as L, params as P - - -def ipcai(database, batch_size): - # our version of LeNet: a series of linear and simple nonlinear transformations - n = caffe.NetSpec() - - n.data, n.label = L.HDF5Data(batch_size=batch_size, source=database, ntop=2) - - n.fc1 = L.InnerProduct(n.data, num_output=25, weight_filler=dict(type='xavier'), - bias_filler=dict(type='constant', value=0.1)) - n.relu1 = L.ReLU(n.fc1, in_place=True) - n.fc2 = L.InnerProduct(n.relu1, num_output=25, weight_filler=dict(type='xavier'), - bias_filler=dict(type='constant', value=0.1)) - n.relu2 = L.ReLU(n.fc2, in_place=True) - n.score = L.InnerProduct(n.relu2, num_output=1, weight_filler=dict(type='xavier'), - bias_filler=dict(type='constant', value=0.1)) - n.loss = L.EuclideanLoss(n.score, n.label) - - return n.to_proto() - -with open('ipcai_train.prototxt', 'w') as f: - f.write(str(ipcai('ipcai_train_hdf5.h5_list.txt', 100))) - -with open('ipcai_test.prototxt', 'w') as f: - f.write(str(ipcai('ipcai_test_hdf5.h5_list.txt', 50))) - -caffe.set_device(0) -caffe.set_mode_gpu() - -### load the solver and create train and test nets -solver = None # ignore this workaround for lmdb data (can't instantiate two solvers on the same data) -solver = caffe.SGDSolver('ipcai_solver.prototxt') - -# each output is (batch size, feature dim, spatial dim) -print [(k, v.data.shape) for k, v in solver.net.blobs.items()] - -# just print the weight sizes (we'll omit the biases) -print [(k, v[0].data.shape) for k, v in solver.net.params.items()] - -solver.net.forward() # train net -print solver.test_nets[0].forward() # test net (there can be more than one) - -niter = 100000 -test_interval = 1000 -# losses will also be stored in the log -train_loss = zeros(niter) -test_acc = zeros(int(np.ceil(niter / test_interval))) -output = zeros((niter, 8, 10)) - -# the main solver loop -for it in range(niter): - solver.step(1) # SGD by Caffe - - # store the train loss - train_loss[it] = solver.net.blobs['loss'].data - - # store the output on the first test batch - # (start the forward pass at fc1 to avoid loading new data) - solver.test_nets[0].forward(start='fc1') - output[it] = solver.test_nets[0].blobs['score'].data[:8] - - # run a full test every so often - # (Caffe can also do this for us and write to a log, but we show here - # how to do it directly in Python, where more complicated things are easier.) - if it % test_interval == 0: - print 'Iteration', it, 'testing...' - mean = 0. - for i in range(100): - solver.test_nets[0].forward() - mean += np.sum(np.abs(np.squeeze(solver.test_nets[0].blobs['score'].data) - - solver.test_nets[0].blobs['label'].data)) - mean = mean / 5000 - test_acc[it // test_interval] = mean * 100. # % - -print "final testing accuracy: ", test_acc[-1] - - -print solver.test_nets[0].blobs['score'].data -print solver.test_nets[0].blobs['label'].data \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/__init__.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_data.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_data.py deleted file mode 100644 index d1d0d28e2b..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_data.py +++ /dev/null @@ -1,144 +0,0 @@ -"""Functions for downloading and reading MNIST data.""" -from __future__ import print_function -import gzip -import os -import urllib -import numpy -SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/' -def maybe_download(filename, work_directory): - """Download the data from Yann's website, unless it's already here.""" - if not os.path.exists(work_directory): - os.mkdir(work_directory) - filepath = os.path.join(work_directory, filename) - if not os.path.exists(filepath): - filepath, _ = urllib.urlretrieve(SOURCE_URL + filename, filepath) - statinfo = os.stat(filepath) - print('Succesfully downloaded', filename, statinfo.st_size, 'bytes.') - return filepath -def _read32(bytestream): - dt = numpy.dtype(numpy.uint32).newbyteorder('>') - return numpy.frombuffer(bytestream.read(4), dtype=dt) -def extract_images(filename): - """Extract the images into a 4D uint8 numpy array [index, y, x, depth].""" - print('Extracting', filename) - with gzip.open(filename) as bytestream: - magic = _read32(bytestream) - if magic != 2051: - raise ValueError( - 'Invalid magic number %d in MNIST image file: %s' % - (magic, filename)) - num_images = _read32(bytestream) - rows = _read32(bytestream) - cols = _read32(bytestream) - buf = bytestream.read(rows * cols * num_images) - data = numpy.frombuffer(buf, dtype=numpy.uint8) - data = data.reshape(num_images, rows, cols, 1) - return data -def dense_to_one_hot(labels_dense, num_classes=10): - """Convert class labels from scalars to one-hot vectors.""" - num_labels = labels_dense.shape[0] - index_offset = numpy.arange(num_labels) * num_classes - labels_one_hot = numpy.zeros((num_labels, num_classes)) - labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1 - return labels_one_hot -def extract_labels(filename, one_hot=False): - """Extract the labels into a 1D uint8 numpy array [index].""" - print('Extracting', filename) - with gzip.open(filename) as bytestream: - magic = _read32(bytestream) - if magic != 2049: - raise ValueError( - 'Invalid magic number %d in MNIST label file: %s' % - (magic, filename)) - num_items = _read32(bytestream) - buf = bytestream.read(num_items) - labels = numpy.frombuffer(buf, dtype=numpy.uint8) - if one_hot: - return dense_to_one_hot(labels) - return labels -class DataSet(object): - def __init__(self, images, labels, fake_data=False): - if fake_data: - self._num_examples = 10000 - else: - assert images.shape[0] == labels.shape[0], ( - "images.shape: %s labels.shape: %s" % (images.shape, - labels.shape)) - self._num_examples = images.shape[0] - # Convert shape from [num examples, rows, columns, depth] - # to [num examples, rows*columns] (assuming depth == 1) - assert images.shape[3] == 1 - images = images.reshape(images.shape[0], - images.shape[1] * images.shape[2]) - # Convert from [0, 255] -> [0.0, 1.0]. - images = images.astype(numpy.float32) - images = numpy.multiply(images, 1.0 / 255.0) - self._images = images - self._labels = labels - self._epochs_completed = 0 - self._index_in_epoch = 0 - @property - def images(self): - return self._images - @property - def labels(self): - return self._labels - @property - def num_examples(self): - return self._num_examples - @property - def epochs_completed(self): - return self._epochs_completed - def next_batch(self, batch_size, fake_data=False): - """Return the next `batch_size` examples from this data set.""" - if fake_data: - fake_image = [1.0 for _ in xrange(784)] - fake_label = 0 - return [fake_image for _ in xrange(batch_size)], [ - fake_label for _ in xrange(batch_size)] - start = self._index_in_epoch - self._index_in_epoch += batch_size - if self._index_in_epoch > self._num_examples: - # Finished epoch - self._epochs_completed += 1 - # Shuffle the data - perm = numpy.arange(self._num_examples) - numpy.random.shuffle(perm) - self._images = self._images[perm] - self._labels = self._labels[perm] - # Start next epoch - start = 0 - self._index_in_epoch = batch_size - assert batch_size <= self._num_examples - end = self._index_in_epoch - return self._images[start:end], self._labels[start:end] -def read_data_sets(train_dir, fake_data=False, one_hot=False): - class DataSets(object): - pass - data_sets = DataSets() - if fake_data: - data_sets.train = DataSet([], [], fake_data=True) - data_sets.validation = DataSet([], [], fake_data=True) - data_sets.test = DataSet([], [], fake_data=True) - return data_sets - TRAIN_IMAGES = 'train-images-idx3-ubyte.gz' - TRAIN_LABELS = 'train-labels-idx1-ubyte.gz' - TEST_IMAGES = 't10k-images-idx3-ubyte.gz' - TEST_LABELS = 't10k-labels-idx1-ubyte.gz' - VALIDATION_SIZE = 5000 - local_file = maybe_download(TRAIN_IMAGES, train_dir) - train_images = extract_images(local_file) - local_file = maybe_download(TRAIN_LABELS, train_dir) - train_labels = extract_labels(local_file, one_hot=one_hot) - local_file = maybe_download(TEST_IMAGES, train_dir) - test_images = extract_images(local_file) - local_file = maybe_download(TEST_LABELS, train_dir) - test_labels = extract_labels(local_file, one_hot=one_hot) - validation_images = train_images[:VALIDATION_SIZE] - validation_labels = train_labels[:VALIDATION_SIZE] - train_images = train_images[VALIDATION_SIZE:] - train_labels = train_labels[VALIDATION_SIZE:] - data_sets.train = DataSet(train_images, train_labels) - data_sets.validation = DataSet(validation_images, validation_labels) - data_sets.test = DataSet(test_images, test_labels) - return data_sets \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_ipcai_data.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_ipcai_data.py deleted file mode 100644 index 65429d72ad..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/input_ipcai_data.py +++ /dev/null @@ -1,103 +0,0 @@ -"""Functions for downloading and reading ipcai data.""" -from __future__ import print_function - -import os - -import numpy -import pandas as pd - -from regression.preprocessing import preprocess - - -class DataSet(object): - def __init__(self, images, labels, fake_data=False): - if fake_data: - self._num_examples = 10000 - else: - assert images.shape[0] == labels.shape[0], ( - "images.shape: %s labels.shape: %s" % (images.shape, - labels.shape)) - self._num_examples = images.shape[0] - images = images.astype(numpy.float32) - self._images = images - self._labels = labels - if self._labels.ndim == 1: - self._labels = self._labels[:, numpy.newaxis] - self._epochs_completed = 0 - self._index_in_epoch = 0 - - @property - def images(self): - return self._images - - @property - def labels(self): - return self._labels - - @property - def num_examples(self): - return self._num_examples - - @property - def epochs_completed(self): - return self._epochs_completed - - def next_batch(self, batch_size, fake_data=False): - """Return the next `batch_size` examples from this data set.""" - if fake_data: - fake_image = [1.0 for _ in xrange(784)] - fake_label = 0 - return [fake_image for _ in xrange(batch_size)], [ - fake_label for _ in xrange(batch_size)] - start = self._index_in_epoch - self._index_in_epoch += batch_size - if self._index_in_epoch > self._num_examples: - # Finished epoch - self._epochs_completed += 1 - # Shuffle the data - perm = numpy.arange(self._num_examples) - numpy.random.shuffle(perm) - self._images = self._images[perm] - self._labels = self._labels[perm] - - # Start next epoch - start = 0 - self._index_in_epoch = batch_size - assert batch_size <= self._num_examples - end = self._index_in_epoch - return self._images[start:end], self._labels[start:end] - - -def read_data_sets(dir, fake_data=False): - - class DataSets(object): - pass - data_sets = DataSets() - if fake_data: - data_sets.train = DataSet([], [], fake_data=True) - data_sets.validation = DataSet([], [], fake_data=True) - data_sets.test = DataSet([], [], fake_data=True) - return data_sets - - TRAIN_IMAGES = "ipcai_revision_colon_mean_scattering_train_all_spectrocam.txt" - TEST_IMAGES = "ipcai_revision_colon_mean_scattering_test_all_spectrocam.txt" - - df_train = pd.read_csv(os.path.join(dir, TRAIN_IMAGES), header=[0, 1]) - df_test = pd.read_csv(os.path.join(dir, TEST_IMAGES), header=[0, 1]) - - train_images, train_labels = preprocess(df_train, snr=10.) - test_images, test_labels = preprocess(df_test, snr=10.) - - train_labels = train_labels.values - test_labels = test_labels.values - - VALIDATION_SIZE = 1 - - validation_images = train_images[:VALIDATION_SIZE] - validation_labels = train_labels[:VALIDATION_SIZE] - train_images = train_images[VALIDATION_SIZE:] - train_labels = train_labels[VALIDATION_SIZE:] - data_sets.train = DataSet(train_images, train_labels) - data_sets.validation = DataSet(validation_images, validation_labels) - data_sets.test = DataSet(test_images, test_labels) - return data_sets \ No newline at end of file diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/script_train_tensorflow_model.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/script_train_tensorflow_model.py deleted file mode 100644 index ee85401f73..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_tensorflow/script_train_tensorflow_model.py +++ /dev/null @@ -1,270 +0,0 @@ - -import Image -import ImageEnhance -import logging -import datetime - -import SimpleITK as sitk -import tensorflow as tf - -from regression.tensorflow_estimator import multilayer_perceptron, cnn -from regression.tensorflow_dataset import read_data_set -from ipcai2016.tasks_common import * -import commons -from msi.io.nrrdreader import NrrdReader -import msi.normalize as norm -from regression.estimation import estimate_image_tensorflow - -sc = commons.ScriptCommons() -sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") -sc.create_folders() - -ipcai_dir = sc.get_full_dir("INTERMEDIATES_FOLDER") - -sc.add_dir("SMALL_BOWEL_DATA", - os.path.join(sc.get_dir("DATA_FOLDER"), "small_bowel_images")) - -sc.add_dir("TENSORFLOW_DATA", - os.path.join(sc.get_dir("INTERMEDIATES_FOLDER"), "TensorflowModels")) - -sc.add_dir("SMALL_BOWEL_RESULT", os.path.join(sc.get_dir("RESULTS_FOLDER"), - "small_bowel_tensorflow")) - -sc.add_dir("FILTER_TRANSMISSIONS", - os.path.join(sc.get_dir("DATA_FOLDER"), - "filter_transmissions")) - - - -def plot_image(image, axis): - im2 = axis.imshow(image, interpolation='nearest', alpha=1.0) - axis.xaxis.set_visible(False) - - -class TensorFlowCreateOxyImageTask(luigi.Task): - image_name = luigi.Parameter() - df_prefix = luigi.Parameter() - df_test_prefix = luigi.Parameter() - - def requires(self): - return TensorflowTrainRegressor(df_prefix=self.df_prefix, - df_test_prefix=self.df_test_prefix), \ - Flatfield(flatfield_folder=sc.get_full_dir("FLAT_FOLDER")), \ - SingleMultispectralImage(image=self.image_name), \ - Dark(dark_folder=sc.get_full_dir("DARK_FOLDER")) - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("SMALL_BOWEL_RESULT"), - os.path.split(self.image_name)[1] + - "_" + self.df_prefix + - "_summary" + ".png")) - - - def run(self): - nrrd_reader = NrrdReader() - tiff_ring_reader = TiffRingReader() - # read the flatfield - flat = nrrd_reader.read(self.input()[1].path) - dark = nrrd_reader.read(self.input()[3].path) - # read the msi - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - msi, segmentation = tiff_ring_reader.read(self.input()[2].path, - nr_filters, resize_factor=0.5) - # only take into account not saturated pixels. - segmentation = np.logical_and(segmentation, - (np.max(msi.get_image(), - axis=-1) < 1000.)) - - # correct image setup - filter_nr = int(self.image_name[-6:-5]) - original_order = np.arange(nr_filters) - new_image_order = np.concatenate(( - original_order[nr_filters - filter_nr:], - original_order[:nr_filters - filter_nr])) - # resort msi to restore original order - msimani.get_bands(msi, new_image_order) - # correct by flatfield - msimani.image_correction(msi, flat, dark) - - # create artificial rgb - rgb_image = msi.get_image()[:, :, [2, 3, 1]] - rgb_image /= np.max(rgb_image) - rgb_image *= 255. - - # preprocess the image - # sortout unwanted bands - print "1" - # zero values would lead to infinity logarithm, thus clip. - msi.set_image(np.clip(msi.get_image(), 0.00001, 2. ** 64)) - # normalize to get rid of lighting intensity - norm.standard_normalizer.normalize(msi) - # transform to absorption - msi.set_image(-np.log(msi.get_image())) - # normalize by l2 for stability - norm.standard_normalizer.normalize(msi, "l2") - print "2" - # estimate - path = sc.get_full_dir("TENSORFLOW_DATA") - sitk_image, time = estimate_image_tensorflow(msi, path) - image = sitk.GetArrayFromImage(sitk_image) - - plt.figure() - print "3" - rgb_image = rgb_image.astype(np.uint8) - im = Image.fromarray(rgb_image, 'RGB') - enh_brightness = ImageEnhance.Brightness(im) - im = enh_brightness.enhance(10.) - plotted_image = np.array(im) - top_left_axis = plt.gca() - top_left_axis.imshow(plotted_image, interpolation='nearest') - top_left_axis.xaxis.set_visible(False) - top_left_axis.yaxis.set_visible(False) - - plt.set_cmap("jet") - print "4" - # plot parametric maps - segmentation[0, 0] = 1 - segmentation[0, 1] = 1 - oxy_image = np.ma.masked_array(image[:, :], ~segmentation) - oxy_image[np.isnan(oxy_image)] = 0. - oxy_image[np.isinf(oxy_image)] = 0. - oxy_mean = np.mean(oxy_image) - oxy_image[0, 0] = 0.0 - oxy_image[0, 1] = 1. - - plot_image(oxy_image[:, :], plt.gca()) - - df_image_results = pd.DataFrame(data=np.expand_dims([self.image_name, - oxy_mean * 100., - time], 0), - columns=["image name", - "oxygenation mean [%]", - "time to estimate"]) - - results_file = os.path.join(sc.get_full_dir("SMALL_BOWEL_RESULT"), - "results.csv") - if os.path.isfile(results_file): - df_results = pd.read_csv(results_file, index_col=0) - df_results = pd.concat((df_results, df_image_results)).reset_index( - drop=True - ) - else: - df_results = df_image_results - - df_results.to_csv(results_file) - - plt.savefig(self.output().path, - dpi=250, bbox_inches='tight') - plt.close("all") - - -class TensorflowTrainRegressor(luigi.Task): - df_prefix = luigi.Parameter() - df_test_prefix = luigi.Parameter() - - def output(self): - return luigi.LocalTarget(os.path.join(sc.get_full_dir("TENSORFLOW_DATA"), - "model.ckpt")) - - def requires(self): - return tasks_mc.SpectroCamBatch(self.df_prefix), \ - tasks_mc.SpectroCamBatch(self.df_test_prefix) - - def run(self): - # extract data from the batch - tensorflow_dataset = read_data_set(self.input()[0].path) - test_dataset = read_data_set(self.input()[1].path) - - # train regressor - # Construct the desired model - - # Network Parameters - nr_filters = len(sc.other["RECORDED_WAVELENGTHS"]) - x = tf.placeholder("float", [None, nr_filters, 1, 1]) - # Construct the desired model - keep_prob = tf.placeholder("float") - # pred, regularizers = multilayer_perceptron(x, nr_filters, 100, 1, - # keep_prob) - pred = cnn(x, 1, keep_prob) - # define parameters - learning_rate = 0.0001 - training_epochs = 300 - batch_size = 100 - display_step = 1 - - # Define loss and optimizer - - y = tf.placeholder("float", [None, 1]) - cost = tf.reduce_mean(tf.square(pred - y)) - optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost) - - # Initializing the variables - init = tf.initialize_all_variables() - - saver = tf.train.Saver() # defaults to saving all variables - - # Launch the graph - with tf.Session() as sess: - sess.run(init) - - # Training cycle - for epoch in range(training_epochs): - avg_cost = 0. - total_batch = int(tensorflow_dataset.num_examples/batch_size) - # Loop over all batches - for i in range(total_batch): - batch_xs, batch_ys = tensorflow_dataset.next_batch(batch_size) - # Fit training using batch data - x_image = np.reshape(batch_xs, [-1, nr_filters, 1, 1]) - sess.run(optimizer, feed_dict={x: x_image, y: batch_ys, - keep_prob: 0.75}) - # Compute average loss - avg_cost += sess.run(cost, feed_dict={x: x_image, y: batch_ys, - keep_prob: 1.0})/total_batch - # Display logs per epoch step - if epoch % display_step == 0: - print "Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(avg_cost) - - # Test model - accuracy = tf.reduce_mean(tf.cast(tf.abs(pred-y), "float")) - x_test_image = np.reshape(test_dataset.images, [-1, nr_filters, 1, 1]) - print "Mean testing error:", accuracy.eval({x: x_test_image, - y: test_dataset.labels, - keep_prob:1.0}) - - print "Optimization Finished!" - saver.save(sess, self.output().path) - - -if __name__ == '__main__': - - # create a folder for the results if necessary - sc.set_root("/media/wirkert/data/Data/2016_02_02_IPCAI/") - sc.create_folders() - - # root folder there the data lies - logging.basicConfig(filename=os.path.join(sc.get_full_dir("LOG_FOLDER"), - "small_bowel_images" + - str(datetime.datetime.now()) + - '.log'), - level=logging.INFO) - luigi.interface.setup_interface_logging() - ch = logging.StreamHandler() - ch.setLevel(logging.INFO) - logger = logging.getLogger() - logger.addHandler(ch) - - sch = luigi.scheduler.CentralPlannerScheduler() - w = luigi.worker.Worker(scheduler=sch) - - # determine files to process - files = get_image_files_from_folder(sc.get_full_dir("SMALL_BOWEL_DATA"), - suffix="F0.tiff", fullpath=True) - - for f in files: - main_task = TensorFlowCreateOxyImageTask(image_name=f, - df_prefix="ipcai_revision_colon_mean_scattering_train", - df_test_prefix="ipcai_revision_colon_mean_scattering_test") - w.add(main_task) - w.run() - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/__init__.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/input_icai_data.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/input_icai_data.py deleted file mode 100644 index 4aaf742da7..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/input_icai_data.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -This tutorial introduces logistic regression using Theano and stochastic -gradient descent. - -Logistic regression is a probabilistic, linear classifier. It is parametrized -by a weight matrix :math:`W` and a bias vector :math:`b`. Classification is -done by projecting data points onto a set of hyperplanes, the distance to -which is used to determine a class membership probability. - -Mathematically, this can be written as: - -.. math:: - P(Y=i|x, W,b) &= softmax_i(W x + b) \\ - &= \frac {e^{W_i x + b_i}} {\sum_j e^{W_j x + b_j}} - - -The output of the model or prediction is then done by taking the argmax of -the vector whose i'th element is P(Y=i|x). - -.. math:: - - y_{pred} = argmax_i P(Y=i|x,W,b) - - -This tutorial presents a stochastic gradient descent optimization method -suitable for large datasets. - - -References: - - - textbooks: "Pattern Recognition and Machine Learning" - - Christopher M. Bishop, section 4.3.2 - -""" - -from __future__ import print_function - -import os - -import numpy -import pandas as pd -import numpy as np - -import theano -import theano.tensor as T - -from regression.preprocessing import preprocess - -__docformat__ = 'restructedtext en' - - -def create_dataset(path_to_simulation_results): - - df = pd.read_csv(path_to_simulation_results, header=[0, 1]) - - X, y = preprocess(df, snr=10.) - y = y.values - return X, y - - - -def load_data(data_root): - ''' Loads the dataset - - :type dataset: string - :param dataset: the path to the dataset (here MNIST) - ''' - - TRAIN_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_train_all_spectrocam.txt") - TEST_IMAGES = os.path.join(data_root, - "ipcai_revision_colon_mean_scattering_test_all_spectrocam.txt") - - train_set = create_dataset(TRAIN_IMAGES) - valid_set = create_dataset(TEST_IMAGES) - test_set = (np.load("sample_image.npy"), np.array([0])) - - def shared_dataset(data_xy, borrow=True): - """ Function that loads the dataset into shared variables - - The reason we store our dataset in shared variables is to allow - Theano to copy it into the GPU memory (when code is run on GPU). - Since copying data into the GPU is slow, copying a minibatch everytime - is needed (the default behaviour if the data is not in a shared - variable) would lead to a large decrease in performance. - """ - data_x, data_y = data_xy - shared_x = theano.shared(numpy.asarray(data_x, - dtype=theano.config.floatX), - borrow=borrow) - shared_y = theano.shared(numpy.asarray(data_y, - dtype=theano.config.floatX), - borrow=borrow) - # When storing data on the GPU it has to be stored as floats - # therefore we will store the labels as ``floatX`` as well - # (``shared_y`` does exactly that). But during our computations - # we need them as ints (we use labels as index, and if they are - # floats it doesn't make sense) therefore instead of returning - # ``shared_y`` we will have to cast it to int. This little hack - # lets ous get around this issue - return shared_x, shared_y - - test_set_x, test_set_y = shared_dataset(test_set, 0) - valid_set_x, valid_set_y = shared_dataset(valid_set) - train_set_x, train_set_y = shared_dataset(train_set) - - rval = [(train_set_x, train_set_y), (valid_set_x, valid_set_y), - (test_set_x, test_set_y)] - return rval - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/logistic_sgd.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/logistic_sgd.py deleted file mode 100644 index 6ef9f732b3..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/logistic_sgd.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -This tutorial introduces logistic regression using Theano and stochastic -gradient descent. - -Logistic regression is a probabilistic, linear classifier. It is parametrized -by a weight matrix :math:`W` and a bias vector :math:`b`. Classification is -done by projecting data points onto a set of hyperplanes, the distance to -which is used to determine a class membership probability. - -Mathematically, this can be written as: - -.. math:: - P(Y=i|x, W,b) &= softmax_i(W x + b) \\ - &= \frac {e^{W_i x + b_i}} {\sum_j e^{W_j x + b_j}} - - -The output of the model or prediction is then done by taking the argmax of -the vector whose i'th element is P(Y=i|x). - -.. math:: - - y_{pred} = argmax_i P(Y=i|x,W,b) - - -This tutorial presents a stochastic gradient descent optimization method -suitable for large datasets. - - -References: - - - textbooks: "Pattern Recognition and Machine Learning" - - Christopher M. Bishop, section 4.3.2 - -""" - -from __future__ import print_function - -import numpy - -import theano -import theano.tensor as T - - -__docformat__ = 'restructedtext en' - - -class LogisticRegression(object): - """Multi-class Logistic Regression Class - - The logistic regression is fully described by a weight matrix :math:`W` - and bias vector :math:`b`. Classification is done by projecting data - points onto a set of hyperplanes, the distance to which is used to - determine a class membership probability. - """ - - def __init__(self, input, n_in, n_out): - """ Initialize the parameters of the logistic regression - - :type input: theano.tensor.TensorType - :param input: symbolic variable that describes the input of the - architecture (one minibatch) - - :type n_in: int - :param n_in: number of input units, the dimension of the space in - which the datapoints lie - - :type n_out: int - :param n_out: number of output units, the dimension of the space in - which the labels lie - - """ - # start-snippet-1 - # initialize with 0 the weights W as a matrix of shape (n_in, n_out) - self.W = theano.shared( - value=numpy.zeros( - (n_in, n_out), - dtype=theano.config.floatX - ), - name='W', - borrow=True - ) - # initialize the biases b as a vector of n_out 0s - self.b = theano.shared( - value=numpy.zeros( - (n_out,), - dtype=theano.config.floatX - ), - name='b', - borrow=True - ) - - # symbolic expression for computing the matrix of class-membership - # probabilities - # Where: - # W is a matrix where column-k represent the separation hyperplane for - # class-k - # x is a matrix where row-j represents input training sample-j - # b is a vector where element-k represent the free parameter of - # hyperplane-k - #self.p_y_given_x = T.nnet.softmax(T.dot(input, self.W) + self.b) - self.p_y_given_x = T.max(T.dot(input, self.W) + self.b, axis = 1) - - - # symbolic description of how to compute prediction as class whose - # probability is maximal - self.y_pred = self.p_y_given_x - #self.y_pred = self.p_y_given_x - # end-snippet-1 - - # parameters of the model - self.params = [self.W, self.b] - - # keep track of model input - self.input = input - - def negative_log_likelihood(self, y): - """Return the mean of the negative log-likelihood of the prediction - of this model under a given target distribution. - - .. math:: - - \frac{1}{|\mathcal{D}|} \mathcal{L} (\theta=\{W,b\}, \mathcal{D}) = - \frac{1}{|\mathcal{D}|} \sum_{i=0}^{|\mathcal{D}|} - \log(P(Y=y^{(i)}|x^{(i)}, W,b)) \\ - \ell (\theta=\{W,b\}, \mathcal{D}) - - :type y: theano.tensor.TensorType - :param y: corresponds to a vector that gives for each example the - correct label - - Note: we use the mean instead of the sum so that - the learning rate is less dependent on the batch size - """ - # start-snippet-2 - # y.shape[0] is (symbolically) the number of rows in y, i.e., - # number of examples (call it n) in the minibatch - # T.arange(y.shape[0]) is a symbolic vector which will contain - # [0,1,2,... n-1] T.log(self.p_y_given_x) is a matrix of - # Log-Probabilities (call it LP) with one row per example and - # one column per class LP[T.arange(y.shape[0]),y] is a vector - # v containing [LP[0,y[0]], LP[1,y[1]], LP[2,y[2]], ..., - # LP[n-1,y[n-1]]] and T.mean(LP[T.arange(y.shape[0]),y]) is - # the mean (across minibatch examples) of the elements in v, - # i.e., the mean log-likelihood across the minibatch. - theano.printing.Print('p_y_given_x')(self.p_y_given_x) - theano.printing.Print('y')(y) - return T.mean(T.square(self.p_y_given_x - y)) - #return -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y]) - # end-snippet-2 - - def errors(self, y): - """Return a float representing the number of errors in the minibatch - over the total number of examples of the minibatch ; zero one - loss over the size of the minibatch - - :type y: theano.tensor.TensorType - :param y: corresponds to a vector that gives for each example the - correct label - """ - - # check if y has same dimension of y_pred - if y.ndim != self.y_pred.ndim: - raise TypeError( - 'y should have the same shape as self.y_pred', - ('y', y.type, 'y_pred', self.y_pred.type) - ) - # check if y is of the correct datatype - if y.dtype.startswith('float'): - # the T.neq operator returns a vector of 0s and 1s, where 1 - # represents a mistake in prediction - return T.mean(T.abs_(self.y_pred - y)) - else: - raise NotImplementedError() - - - diff --git a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/script_train_theano_model.py b/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/script_train_theano_model.py deleted file mode 100644 index 32c2a7045e..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/ipcai_to_theano/script_train_theano_model.py +++ /dev/null @@ -1,445 +0,0 @@ - - -""" -This tutorial introduces the multilayer perceptron using Theano. - - A multilayer perceptron is a logistic regressor where -instead of feeding the input to the logistic regression you insert a -intermediate layer, called the hidden layer, that has a nonlinear -activation function (usually tanh or sigmoid) . One can use many such -hidden layers making the architecture deep. The tutorial will also tackle -the problem of MNIST digit classification. - -.. math:: - - f(x) = G( b^{(2)} + W^{(2)}( s( b^{(1)} + W^{(1)} x))), - -References: - - - textbooks: "Pattern Recognition and Machine Learning" - - Christopher M. Bishop, section 5 - -""" - -from __future__ import print_function - -import os -import sys -import timeit -import time - -import numpy -import numpy as np -import matplotlib.pylab as plt -import theano -import theano.tensor as T - - -from logistic_sgd import LogisticRegression -from input_icai_data import load_data -from ipcai2016.tasks_common import plot_image - -#theano.config.compute_test_value = 'warn' -#theano.config.mode = "FAST_COMPILE" -#theano.config.exception_verbosity='high' - -__docformat__ = 'restructedtext en' - - -# start-snippet-1 -class HiddenLayer(object): - def __init__(self, rng, input, n_in, n_out, W=None, b=None, - activation=T.tanh): - """ - Typical hidden layer of a MLP: units are fully-connected and have - sigmoidal activation function. Weight matrix W is of shape (n_in,n_out) - and the bias vector b is of shape (n_out,). - - NOTE : The nonlinearity used here is tanh - - Hidden unit activation is given by: tanh(dot(input,W) + b) - - :type rng: numpy.random.RandomState - :param rng: a random number generator used to initialize weights - - :type input: theano.tensor.dmatrix - :param input: a symbolic tensor of shape (n_examples, n_in) - - :type n_in: int - :param n_in: dimensionality of input - - :type n_out: int - :param n_out: number of hidden units - - :type activation: theano.Op or function - :param activation: Non linearity to be applied in the hidden - layer - """ - self.input = input - # end-snippet-1 - - # `W` is initialized with `W_values` which is uniformely sampled - # from sqrt(-6./(n_in+n_hidden)) and sqrt(6./(n_in+n_hidden)) - # for tanh activation function - # the output of uniform if converted using asarray to dtype - # theano.config.floatX so that the code is runable on GPU - # Note : optimal initialization of weights is dependent on the - # activation function used (among other things). - # For example, results presented in [Xavier10] suggest that you - # should use 4 times larger initial weights for sigmoid - # compared to tanh - # We have no info for other function, so we use the same as - # tanh. - if W is None: - W_values = numpy.asarray( - rng.uniform( - low=-numpy.sqrt(6. / (n_in + n_out)), - high=numpy.sqrt(6. / (n_in + n_out)), - size=(n_in, n_out) - ), - dtype=theano.config.floatX - ) - if activation == theano.tensor.nnet.sigmoid: - W_values *= 4 - - W = theano.shared(value=W_values, name='W', borrow=True) - - if b is None: - b_values = 0.1+numpy.zeros((n_out,), dtype=theano.config.floatX) - b = theano.shared(value=b_values, name='b', borrow=True) - - self.W = W - self.b = b - - lin_output = T.dot(input, self.W) + self.b - self.output = ( - lin_output if activation is None - else activation(lin_output) - ) - # parameters of the model - self.params = [self.W, self.b] - - -# start-snippet-2 -class MLP(object): - """Multi-Layer Perceptron Class - - A multilayer perceptron is a feedforward artificial neural network model - that has one layer or more of hidden units and nonlinear activations. - Intermediate layers usually have as activation function tanh or the - sigmoid function (defined here by a ``HiddenLayer`` class) while the - top layer is a softmax layer (defined here by a ``LogisticRegression`` - class). - """ - - def __init__(self, rng, input, n_in, n_hidden, n_out): - """Initialize the parameters for the multilayer perceptron - - :type rng: numpy.random.RandomState - :param rng: a random number generator used to initialize weights - - :type input: theano.tensor.TensorType - :param input: symbolic variable that describes the input of the - architecture (one minibatch) - - :type n_in: int - :param n_in: number of input units, the dimension of the space in - which the datapoints lie - - :type n_hidden: int - :param n_hidden: number of hidden units - - :type n_out: int - :param n_out: number of output units, the dimension of the space in - which the labels lie - - """ - - # Since we are dealing with a one hidden layer MLP, this will translate - # into a HiddenLayer with a tanh activation function connected to the - # LogisticRegression layer; the activation function can be replaced by - # sigmoid or any other nonlinear function - self.hiddenLayer1 = HiddenLayer( - rng=rng, - input=input, - n_in=n_in, - n_out=n_hidden, - activation=T.nnet.relu - ) - - self.hiddenLayer2 = HiddenLayer( - rng=rng, - input=self.hiddenLayer1.output, - n_in=n_hidden, - n_out=n_hidden, - activation=T.nnet.relu - ) - - # The logistic regression layer gets as input the hidden units - # of the hidden layer - self.logRegressionLayer = LogisticRegression( - input=self.hiddenLayer2.output, - n_in=n_hidden, - n_out=n_out - ) - # end-snippet-2 start-snippet-3 - # L1 norm ; one regularization option is to enforce L1 norm to - # be small - self.L1 = ( - abs(self.hiddenLayer1.W).sum() - + abs(self.hiddenLayer2.W).sum() - + abs(self.logRegressionLayer.W).sum() - ) - - # square of L2 norm ; one regularization option is to enforce - # square of L2 norm to be small - self.L2_sqr = ( - (self.hiddenLayer1.W ** 2).sum() - + (self.hiddenLayer2.W ** 2).sum() - + (self.logRegressionLayer.W ** 2).sum() - ) - - # negative log likelihood of the MLP is given by the negative - # log likelihood of the output of the model, computed in the - # logistic regression layer - self.negative_log_likelihood = ( - self.logRegressionLayer.negative_log_likelihood - ) - # same holds for the function computing the number of errors - self.errors = self.logRegressionLayer.errors - - self.y_pred = self.logRegressionLayer.y_pred - - # the parameters of the model are the parameters of the two layer it is - # made out of - self.params = self.hiddenLayer1.params +\ - self.hiddenLayer2.params +\ - self.logRegressionLayer.params - # end-snippet-3 - - # keep track of model input - self.input = input - - -def test_mlp(learning_rate=0.001, L1_reg=0.0001, L2_reg=0.0001, n_epochs=1000, - dataset="/media/wirkert/data/Data/2016_02_02_IPCAI/results/intermediate", - batch_size=20, n_hidden=25, - do_timing_test=False): - """ - Demonstrate stochastic gradient descent optimization for a multilayer - perceptron - - This is demonstrated on MNIST. - - :type learning_rate: float - :param learning_rate: learning rate used (factor for the stochastic - gradient - - :type L1_reg: float - :param L1_reg: L1-norm's weight when added to the cost (see - regularization) - - :type L2_reg: float - :param L2_reg: L2-norm's weight when added to the cost (see - regularization) - - :type n_epochs: int - :param n_epochs: maximal number of epochs to run the optimizer - - :type dataset: string - :param dataset: the path of the MNIST dataset file from - http://www.iro.umontreal.ca/~lisa/deep/data/mnist/mnist.pkl.gz - - - """ - - datasets = load_data(dataset) - - train_set_x, train_set_y = datasets[0] - valid_set_x, valid_set_y = datasets[1] - test_set_x, test_set_y = datasets[2] - - # compute number of minibatches for training and validation - n_train_batches = train_set_x.get_value(borrow=True).shape[0] // batch_size - n_valid_batches = valid_set_x.get_value(borrow=True).shape[0] // batch_size - - ###################### - # BUILD ACTUAL MODEL # - ###################### - print('... building the model') - - # allocate symbolic variables for the data - index = T.lscalar() # index to a [mini]batch - x = T.matrix('x') # the data is presented as rasterized images - x.tag.test_value = np.zeros((5000, 8)).astype('float32') - y = T.vector('y') # the labels are presented as 1D vector of - # [int] labels - y.tag.test_value = np.ones(5000).astype('float32') - - rng = numpy.random.RandomState(1234) - - # construct the MLP class - classifier = MLP( - rng=rng, - input=x, - n_in=8, - n_hidden=n_hidden, - n_out=1 - ) - - # start-snippet-4 - # the cost we minimize during training is the negative log likelihood of - # the model plus the regularization terms (L1 and L2); cost is expressed - # here symbolically - cost = ( - classifier.negative_log_likelihood(y) - + L1_reg * classifier.L1 - + L2_reg * classifier.L2_sqr - ) - # end-snippet-4 - - # compiling a Theano function that computes the mistakes that are made - # by the model on a minibatch - test_model = theano.function( - inputs=[], - outputs=classifier.y_pred, - givens={ - x: test_set_x - } - ) - - validate_model = theano.function( - inputs=[index], - outputs=classifier.errors(y), - givens={ - x: valid_set_x[index * batch_size:(index + 1) * batch_size], - y: valid_set_y[index * batch_size:(index + 1) * batch_size] - } - ) - - # start-snippet-5 - # compute the gradient of cost with respect to theta (sorted in params) - # the resulting gradients will be stored in a list gparams - gparams = [T.grad(cost, param) for param in classifier.params] - - # specify how to update the parameters of the model as a list of - # (variable, update expression) pairs - - # given two lists of the same length, A = [a1, a2, a3, a4] and - # B = [b1, b2, b3, b4], zip generates a list C of same size, where each - # element is a pair formed from the two lists : - # C = [(a1, b1), (a2, b2), (a3, b3), (a4, b4)] - updates = [ - (param, param - learning_rate * gparam) - for param, gparam in zip(classifier.params, gparams) - ] - - # compiling a Theano function `train_model` that returns the cost, but - # in the same time updates the parameter of the model based on the rules - # defined in `updates` - train_model = theano.function( - inputs=[index], - outputs=cost, - updates=updates, - givens={ - x: train_set_x[index * batch_size: (index + 1) * batch_size], - y: train_set_y[index * batch_size: (index + 1) * batch_size] - } - ) - # end-snippet-5 - - ############### - # TRAIN MODEL # - ############### - print('... training') - - # early-stopping parameters - patience = 10000 # look as this many examples regardless - patience_increase = 2 # wait this much longer when a new best is - # found - improvement_threshold = 0.995 # a relative improvement of this much is - # considered significant - validation_frequency = min(n_train_batches, patience // 2) - # go through this many - # minibatche before checking the network - # on the validation set; in this case we - # check every epoch - - best_validation_loss = numpy.inf - best_iter = 0 - test_score = 0. - start_time = timeit.default_timer() - - epoch = 0 - done_looping = False - - while (epoch < n_epochs):# and (not done_looping): - epoch = epoch + 1 - for minibatch_index in range(n_train_batches): - - minibatch_avg_cost = train_model(minibatch_index) - # iteration number - iter = (epoch - 1) * n_train_batches + minibatch_index - - if (iter + 1) % validation_frequency == 0: - # compute zero-one loss on validation set - validation_losses = [validate_model(i) for i - in range(n_valid_batches)] - this_validation_loss = numpy.mean(validation_losses) - - print( - 'epoch %i, minibatch %i/%i, validation error %f %%' % - ( - epoch, - minibatch_index + 1, - n_train_batches, - this_validation_loss * 100. - ) - ) - - # if we got the best validation score until now - if this_validation_loss < best_validation_loss: - #improve patience if loss improvement is good enough - if ( - this_validation_loss < best_validation_loss * - improvement_threshold - ): - patience = max(patience, iter * patience_increase) - - best_validation_loss = this_validation_loss - best_iter = iter - - if do_timing_test: - # test it on the test set - start = time.time() - test_predictions = test_model() - end = time.time() - estimation_time = end - start - print("time necessary for estimating image parameters: " + - str(estimation_time) + "s") - print(test_predictions.shape) - - if patience <= iter: - done_looping = True - #break - - end_time = timeit.default_timer() - print(('Optimization complete. Best validation score of %f %% ' - 'obtained at iteration %i, with test performance %f %%') % - (best_validation_loss * 100., best_iter + 1, test_score * 100.)) - print(('The code for file ' + - os.path.split(__file__)[1] + - ' ran for %.2fm' % ((end_time - start_time) / 60.)), file=sys.stderr) - - test_predictions = test_model() - image = test_predictions.reshape(1029,1228) - image[0, 0] = 0.0 - image[0, 1] = 1. - image = np.clip(image, 0., 1.) - plot_image(image) - plt.savefig("sample_image.png", - dpi=250, bbox_inches='tight') - -if __name__ == '__main__': - test_mlp() - diff --git a/Modules/Biophotonics/python/iMC/scripts/spielewiese/__init__.py b/Modules/Biophotonics/python/iMC/scripts/spielewiese/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Modules/Biophotonics/python/iMC/scripts/spielewiese/monte_carlo_single_photon.py b/Modules/Biophotonics/python/iMC/scripts/spielewiese/monte_carlo_single_photon.py deleted file mode 100644 index 05f0afc7dd..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/spielewiese/monte_carlo_single_photon.py +++ /dev/null @@ -1,203 +0,0 @@ -from collections import OrderedDict -import numpy as np - -import theano -from theano.ifelse import ifelse -import theano.tensor as T -import theano.tensor.inplace as inplace -#from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams -from theano.tensor.shared_randomstreams import RandomStreams -import time - - -#theano.config.compute_test_value = 'warn' -#theano.config.exception_verbosity='high' -#theano.config.profile=True -#theano.config.mode = "FAST_RUN" -#theano.config.mode = "FAST_COMPILE" -#theano.config.scan.allow_gc =True -#theano.config.scan.allow_output_prealloc =False -#theano.optimizer_excluding="more_mem" - -# initializing -rng = RandomStreams(seed=234) -photons = 10**6 -SHELL_MAX = 101 - - -mu_a = T.scalar('mu_a') -# provide Theano with a default test-value -mu_a.tag.test_value = 2. -mu_s = T.scalar('mu_s') -mu_s.tag.test_value = 20. -microns_per_shell = T.scalar('microns_per_shell') -microns_per_shell.tag.test_value = 50. - -albedo = mu_s / (mu_s + mu_a) -shells_per_mfp = 1e4/microns_per_shell/(mu_a+mu_s) - -heat = theano.shared(np.zeros(SHELL_MAX, dtype=theano.config.floatX)) - -x = T.scalar('x') -x.tag.test_value = 0 - -y = T.scalar('y') -y.tag.test_value = 0 - -z = T.scalar('z') -z.tag.test_value = 0 - -u = T.scalar('u') -u.tag.test_value = 0 - -v = T.scalar('v') -v.tag.test_value = 0 - -w = T.scalar('w') -w.tag.test_value = 1 - -weight = T.scalar('weight') -weight.tag.test_value = 1 - - -def one_run(my_x, my_y, my_z, - my_u, my_v, my_w, - my_weight, - my_heat, my_albedo, my_microns_per_shell): - - # move - random = rng.uniform(low=0.00003, high=1.) - t = -T.log(random) - - x_moved = my_x + my_u*t - y_moved = my_y + my_v*t - z_moved = my_z + my_w*t - - # absorb - shell = T.cast(T.sqrt(T.sqr(x_moved) + T.sqr(y_moved) + T.sqr(z_moved)) - * my_microns_per_shell, 'int32') - shell = T.clip(shell, 0, SHELL_MAX-1) - - new_weight = my_weight * my_albedo - - # new direction - xi1 = rng.uniform(low=-1., high=1.) - xi2 = rng.uniform(low=-1., high=1.) - xi_norm = T.sqrt(T.sqr(xi1) + T.sqr(xi2)) - - t_xi = rng.uniform(low=0.000000001, high=1.) - - # rescale xi12 to fit t_xi as norm - xi1 = xi1/xi_norm * T.sqr(t_xi) - xi2 = xi2/xi_norm * T.sqr(t_xi) - - u_new_direction = 2. * t_xi - 1. - v_new_direction = xi1 * T.sqrt((1. - T.sqr(u_new_direction)) / t_xi) - w_new_direction = xi2 * T.sqrt((1. - T.sqr(u_new_direction)) / t_xi) - - # roulette - weight_for_starting_roulette = 0.001 - CHANCE = 0.1 - partakes_roulette = T.switch(T.lt(new_weight, weight_for_starting_roulette), - 1, - 0) - roulette = rng.uniform(low=0., high=1.) - loses_roulette = T.gt(roulette, CHANCE) - # if roulette decides to terminate the photon: set weight to 0 - weight_after_roulette = ifelse(T.and_(partakes_roulette, loses_roulette), - 0., - new_weight) - # if partakes in roulette but does not get terminated - weight_after_roulette = ifelse(T.and_(partakes_roulette, T.invert(loses_roulette)), - weight_after_roulette / CHANCE, - weight_after_roulette) - - new_heat = (1.0 - my_albedo) * my_weight - heat_i = my_heat[shell] - - return (x_moved, y_moved, z_moved,\ - u_new_direction, v_new_direction, w_new_direction,\ - weight_after_roulette),\ - OrderedDict({my_heat: T.inc_subtensor(heat_i, new_heat)}) - - -# one_photon_results, one_photon_updates = theano.scan(fn=one_run, -# outputs_info=[T.zeros_like(x), -# T.zeros_like(y), -# T.zeros_like(z), -# T.zeros_like(u), -# T.zeros_like(v), -# T.ones_like(w), -# T.ones_like(weight)], -# non_sequences=[heat, -# albedo, -# microns_per_shell], -# n_steps=100, -# strict=True) -# -# final_one_photon_heat_result = one_photon_updates[heat] - -# heat_for_one_photon = theano.function(inputs=[x, y, z, -# u, v, w, -# weight, -# mu_a, mu_s, microns_per_shell], -# outputs=final_one_photon_heat_result, -# updates=one_photon_updates) - - -def all_runs(my_x, my_y, my_z, - my_u, my_v, my_w, - my_weight, - my_heat, - my_albedo, my_microns_per_shell): - my_one_photon_results, my_one_photon_updates = theano.scan(fn=one_run, - outputs_info=[T.zeros_like(my_x), - T.zeros_like(my_y), - T.zeros_like(my_z), - T.zeros_like(my_u), - T.zeros_like(my_v), - T.ones_like(my_w), - T.ones_like(my_weight)], - non_sequences=[my_heat, - my_albedo, - my_microns_per_shell], - n_steps=10, - strict=True) - return {my_heat: my_one_photon_updates[my_heat]} - - -all_photon_results, all_photon_updates = theano.scan(fn=all_runs, - outputs_info=None, - non_sequences=[x, y, z, - u, v, w, - weight, - heat, - albedo, microns_per_shell], - n_steps=10, - strict=True) - - -heat_for_all_photons = theano.function(inputs=[x, y, z, - u, v, w, - weight, - mu_a, mu_s, microns_per_shell], - outputs=all_photon_updates[heat], - updates=all_photon_updates) - - - - - -start = time.time() - -print("start simulation") - -print(heat_for_all_photons(0., 0., 0., - 0., 0., 1., - 1., - 2., 20., 50.)) - -end = time.time() -print("end simulation after: " + str(end - start) + " seconds") - - diff --git a/Modules/Biophotonics/python/iMC/scripts/spielewiese/spielewiese.py b/Modules/Biophotonics/python/iMC/scripts/spielewiese/spielewiese.py deleted file mode 100644 index 871864547f..0000000000 --- a/Modules/Biophotonics/python/iMC/scripts/spielewiese/spielewiese.py +++ /dev/null @@ -1,130 +0,0 @@ -from collections import OrderedDict -import numpy as np - -import theano -import theano.tensor as T -from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams -#from theano.tensor.shared_randomstreams import RandomStreams -import time - -#theano.config.compute_test_value = 'warn' -#theano.config.exception_verbosity='high' -# initializing -rng = RandomStreams(seed=234) -photons = 10**6 -SHELL_MAX = 101 - -mu_a = T.scalar('mu_a') -# provide Theano with a default test-value -mu_a.tag.test_value = 2. -mu_s = T.scalar('mu_s') -mu_s.tag.test_value = 20. -microns_per_shell = T.scalar('microns_per_shell') -microns_per_shell.tag.test_value = 50. - -albedo = mu_s / (mu_s + mu_a) -shells_per_mfp = 1e4/microns_per_shell/(mu_a+mu_s) - - - - -finished = theano.shared(np.array(0, dtype='int8')) - -xyz = theano.shared(np.zeros((photons,3), dtype=theano.config.floatX)) - -uvw_np = np.zeros((photons,3), dtype=theano.config.floatX) -uvw_np[:,2] = 1. # w = 1 -uvw = theano.shared(uvw_np) - -#weights_np = np.ones((photons,1), dtype=theano.config.floatX) -weight = theano.shared(np.ones((photons,1), dtype=theano.config.floatX)) - -heat_np = np.zeros((SHELL_MAX,1), dtype=theano.config.floatX) -heat = theano.shared(heat_np) - - - - - - - - -# while sum alive > 0 - -def l2_norm_along_columns(A): - A_normed = T.sqrt(T.sum(T.sqr(A), axis=1)) - A_normed = A_normed.reshape((photons, 1)) - return A_normed - -# move -random = rng.uniform((photons,1), low=0.00003, high=1.) -t = -T.log(random) -t = T.addbroadcast(t, 1) - -xyz_moved = xyz + uvw*t -#theano.printing.Print('xyz_moved')(xyz_moved) - -# absorb -shells = T.cast(l2_norm_along_columns(xyz_moved) * shells_per_mfp, - 'int32') -shells = T.clip(shells, 0, SHELL_MAX-1) -new_heats = (1.0 - albedo) * weight -new_weight = weight * albedo -theano.printing.Print('shells')(shells) - -# new direction -xi12 = rng.uniform((photons,2), low=-1., high=1.) -xi_norm = l2_norm_along_columns(xi12) - -t_xi = rng.uniform((photons,1), low=0.000000001, high=1.) -t_xi = T.addbroadcast(t_xi, 1) - -# rescale xi12 to fit t_xi as norm -xi12 = xi12/xi_norm * T.sqr(t_xi) - -u_new_direction = 2. * t_xi - 1. -vw_new_direction = xi12 * T.sqrt((1. - T.sqr(u_new_direction)) / t_xi) -uvw_new_direction = T.concatenate([u_new_direction, vw_new_direction], axis=1) - -#theano.printing.Print('t_xi')(t_xi) -#theano.printing.Print('vw')(vw_new_direction) -#theano.printing.Print('uvw')(uvw_new_direction) -# roulette -weight_for_starting_roulette = 0.001 -CHANCE = 0.1 -partakes_roulette = T.switch(T.lt(new_weight, weight_for_starting_roulette), - 1, - 0) -roulette = rng.uniform((photons,1), low=0., high=1.) -loses_roulette = T.gt(roulette, CHANCE) -# if roulette decides to ter+minate the photon: set weight to 0 -weight_after_roulette = T.switch(T.and_(partakes_roulette, loses_roulette), - 0., - new_weight) -# if partakes in roulette but does not get terminated -weight_after_roulette = T.switch(T.and_(partakes_roulette, T.invert(loses_roulette)), - weight_after_roulette / CHANCE, - weight_after_roulette) -#theano.printing.Print('new weight')(new_weight) -#theano.printing.Print('partakes_roulette')(partakes_roulette) -#theano.printing.Print('loses_roulette')(loses_roulette) -#theano.printing.Print('weight_after_roulette')(weight_after_roulette) - - -one_cycle = theano.function(inputs=[mu_a, mu_s, microns_per_shell], - outputs=[shells, new_heats], - updates=OrderedDict({xyz: xyz_moved, uvw: uvw_new_direction, - weight: weight_after_roulette, - finished: T.allclose(weight, 0.)})) - - -start = time.time() -print("start simulation") - -while not finished.get_value(): - new_shells, new_heats = one_cycle(2, 20, 50) - -end = time.time() -print("end simulation after: " + str(end - start) + " seconds") - - diff --git a/Modules/Biophotonics/python/iMC/setup.py b/Modules/Biophotonics/python/iMC/setup.py deleted file mode 100644 index 9e04fc9ca8..0000000000 --- a/Modules/Biophotonics/python/iMC/setup.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Created on Fri Aug 7 18:41:50 2015 - -@author: wirkert -""" - -from setuptools import setup, find_packages - -setup(name='MITK-MSI', - version='0.1', - description='Multi spectral imaging (MSI) utilities', - author='Sebastian Wirkert', - author_email='s.wirkert@dkfz-heidelberg.de', - license='BSD', - packages=find_packages(exclude=['test*']), - package_dir={}, - package_data={'data': ['*.txt', '*.mci', '*.nrrd']}, - install_requires=['numpy>=1.10.2', 'scipy', 'scikit-learn>=0.17', - 'SimpleITK>=0.9.0', 'subprocess32', - 'pypng', 'pandas>0.17', 'libtiff'], - entry_points={} # for scripts, add later - ) diff --git a/Modules/Biophotonics/python/iMC/tox.ini b/Modules/Biophotonics/python/iMC/tox.ini deleted file mode 100644 index 51e0c9f594..0000000000 --- a/Modules/Biophotonics/python/iMC/tox.ini +++ /dev/null @@ -1,9 +0,0 @@ -# content of: tox.ini , put in same dir as setup.py -[tox] -envlist = py27 -[testenv] -deps=discover # install pytest in the venvs -install_command=pip install -f http://www.simpleitk.org/SimpleITK/resources/software.html --trusted-host www.simpleitk.org {opts} {packages} -#changedir=tests -commands=discover - diff --git a/Modules/Biophotonics/python/iMC/tutorials/Monte Carlo Spectra Generation - Basic tutorial.ipynb b/Modules/Biophotonics/python/iMC/tutorials/Monte Carlo Spectra Generation - Basic tutorial.ipynb deleted file mode 100644 index e5ea2b6e52..0000000000 --- a/Modules/Biophotonics/python/iMC/tutorials/Monte Carlo Spectra Generation - Basic tutorial.ipynb +++ /dev/null @@ -1,1018 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Creating and manipulating monte carlo spectra using MITK-MSI\n", - "\n", - "In this tutorial we will learn how to\n", - "1. create reflectance spectra from examplary tissues\n", - "2. how to analyse and visualize the created spectra\n", - "3. how to manipulate them\n", - "\n", - "The MITK-MSI software provides a wrapper to the popular MCML approach to simulate how light travels through tissue. This wrapper can be found in mc/sim.py.\n", - "In this tutorial we will utilize our tissue model which uses this wrapper to create the reflectance spectra.\n", - "\n", - "As a prerequisit, you need a MCML monte carlo simulation which uses the format specified [here](http://omlc.org/software/mc/).\n", - "I tested this software with the GPU accelerated version which can be found [here](https://code.google.com/archive/p/gpumcml/)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "# 1.1 create spectra - setup simulation environment\n", - "\n", - "# some necessary imports\n", - "import logging\n", - "import numpy as np\n", - "import os\n", - "# everything related to the simulation wrapper\n", - "from mc import sim\n", - "# the factories create batches (tissue samples) and suited tissue models\n", - "from mc import factories\n", - "# function which runs simulations for each wavelength\n", - "from mc.create_spectrum import create_spectrum\n", - "\n", - "# Where does your monte carlo simulation executable resides in?\n", - "MCML_EXECUTABLE = \"/home/wirkert/workspace/monteCarlo/gpumcml/fast-gpumcml/gpumcml.sm_20\"\n", - "# The MCML needs a simulation input file, where shall it be created?\n", - "MCI_FILENAME = \"./temp.mci\"\n", - "# filename of the file with the simulation results. Due to a bug in GPUMCML will always\n", - "# be created in the same folder as the MCML executable\n", - "MCO_FILENAME = \"temp.mco\"\n", - "# The wavelengths for which we want to run our simulation\n", - "WAVELENGTHS = np.arange(450, 720, 2) * 10 ** -9\n", - "\n", - "# we want to create standard colonic tissue as specified in the IPCAI 2016 publication\n", - "# \"Robust Near Real-Time Estimation of Physiological Parameters from Megapixel\n", - "# Multispectral Images with Inverse Monte Carlo and Random Forest Regression\"\n", - "factory = factories.ColonMuscleMeanScatteringFactory()\n", - "# if you want to create data from the generic tissue mentioned in the paper, choose:\n", - "#factory = factories.GenericMeanScatteringFactory()\n", - "\n", - "# create a simulation wrapper\n", - "# the simulation wrapper wraps the mcml executable in python code\n", - "sim_wrapper = sim.SimWrapper()\n", - "# our simulation needs to know where the input file for the simulation\n", - "# shall resign (will be automatically created)\n", - "sim_wrapper.set_mci_filename(MCI_FILENAME)\n", - "# also it needs to know where the simulation executable shall lie in\n", - "sim_wrapper.set_mcml_executable(MCML_EXECUTABLE)\n", - "\n", - "# create the tissue model\n", - "# it is responsible for writing the simulation input file\n", - "tissue_model = factory.create_tissue_model()\n", - "# tell it where the input file shall lie in\n", - "tissue_model.set_mci_filename(sim_wrapper.mci_filename)\n", - "# also set the output filename\n", - "tissue_model.set_mco_filename(MCO_FILENAME)\n", - "# tell it how much photons shall be simulated. Will be set to 10**6 by standard,\n", - "# this is just an example\n", - "tissue_model.set_nr_photons(10**6)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
layer0layer1layer2
vhbsao2a_mieb_miedngvhbsao2a_mie...dngvhbsao2a_mieb_miedng
00.0037800.4475832425.9008821.2860.0009071.360.8726260.0689850.447583912.591151...0.0005031.360.9487000.0344270.4475833150.4940321.2860.0004541.380.804610
10.0211980.1844103022.1165321.2860.0007821.360.9302680.0638040.18441010.000000...0.0007351.360.8306010.0282470.1844103101.2614991.2860.0004301.380.813056
20.0520960.3074451171.3227581.2860.0008971.360.9249330.0210530.3074451433.788625...0.0007381.360.8073480.0066140.3074451002.5369011.2860.0004851.380.943837
30.0767990.4713041599.0386711.2860.0008781.360.9006370.0845040.4713043228.771326...0.0006051.360.9052220.0436740.4713041810.1143031.2860.0005041.380.868953
40.0531230.1081373524.4808851.2860.0010011.360.8334340.0953820.1081371988.134950...0.0006431.360.9209400.0312010.1081371731.7512831.2860.0005421.380.906191
50.0091470.866703372.7547991.2860.0009431.360.8412740.0949150.8667031660.695761...0.0005051.360.8569690.0092740.8667031991.3905631.2860.0004391.380.813544
60.0829030.2060322314.4154111.2860.0006631.360.8844920.0386080.206032459.458466...0.0005731.360.8505740.0637460.2060322728.8206781.2860.0004941.380.801766
70.0407190.2009561858.9101211.2860.0007721.360.8845160.0039300.2009563564.807750...0.0007661.360.9037640.0472570.2009561429.5744071.2860.0004681.380.849055
80.0288100.7296361751.8182481.2860.0008861.360.8133910.0074770.7296361388.286116...0.0008131.360.9141250.0929930.7296364001.4466131.2860.0005041.380.844552
90.0897580.6653973768.7091881.2860.0008001.360.8367110.0156480.6653971298.629577...0.0006201.360.9279040.0480230.6653973015.2893861.2860.0004271.380.893833
\n", - "

10 rows × 21 columns

\n", - "
" - ], - "text/plain": [ - " layer0 layer1 \\\n", - " vhb sao2 a_mie b_mie d n g vhb \n", - "0 0.003780 0.447583 2425.900882 1.286 0.000907 1.36 0.872626 0.068985 \n", - "1 0.021198 0.184410 3022.116532 1.286 0.000782 1.36 0.930268 0.063804 \n", - "2 0.052096 0.307445 1171.322758 1.286 0.000897 1.36 0.924933 0.021053 \n", - "3 0.076799 0.471304 1599.038671 1.286 0.000878 1.36 0.900637 0.084504 \n", - "4 0.053123 0.108137 3524.480885 1.286 0.001001 1.36 0.833434 0.095382 \n", - "5 0.009147 0.866703 372.754799 1.286 0.000943 1.36 0.841274 0.094915 \n", - "6 0.082903 0.206032 2314.415411 1.286 0.000663 1.36 0.884492 0.038608 \n", - "7 0.040719 0.200956 1858.910121 1.286 0.000772 1.36 0.884516 0.003930 \n", - "8 0.028810 0.729636 1751.818248 1.286 0.000886 1.36 0.813391 0.007477 \n", - "9 0.089758 0.665397 3768.709188 1.286 0.000800 1.36 0.836711 0.015648 \n", - "\n", - " ... layer2 \\\n", - " sao2 a_mie ... d n g vhb \n", - "0 0.447583 912.591151 ... 0.000503 1.36 0.948700 0.034427 \n", - "1 0.184410 10.000000 ... 0.000735 1.36 0.830601 0.028247 \n", - "2 0.307445 1433.788625 ... 0.000738 1.36 0.807348 0.006614 \n", - "3 0.471304 3228.771326 ... 0.000605 1.36 0.905222 0.043674 \n", - "4 0.108137 1988.134950 ... 0.000643 1.36 0.920940 0.031201 \n", - "5 0.866703 1660.695761 ... 0.000505 1.36 0.856969 0.009274 \n", - "6 0.206032 459.458466 ... 0.000573 1.36 0.850574 0.063746 \n", - "7 0.200956 3564.807750 ... 0.000766 1.36 0.903764 0.047257 \n", - "8 0.729636 1388.286116 ... 0.000813 1.36 0.914125 0.092993 \n", - "9 0.665397 1298.629577 ... 0.000620 1.36 0.927904 0.048023 \n", - "\n", - " \n", - " sao2 a_mie b_mie d n g \n", - "0 0.447583 3150.494032 1.286 0.000454 1.38 0.804610 \n", - "1 0.184410 3101.261499 1.286 0.000430 1.38 0.813056 \n", - "2 0.307445 1002.536901 1.286 0.000485 1.38 0.943837 \n", - "3 0.471304 1810.114303 1.286 0.000504 1.38 0.868953 \n", - "4 0.108137 1731.751283 1.286 0.000542 1.38 0.906191 \n", - "5 0.866703 1991.390563 1.286 0.000439 1.38 0.813544 \n", - "6 0.206032 2728.820678 1.286 0.000494 1.38 0.801766 \n", - "7 0.200956 1429.574407 1.286 0.000468 1.38 0.849055 \n", - "8 0.729636 4001.446613 1.286 0.000504 1.38 0.844552 \n", - "9 0.665397 3015.289386 1.286 0.000427 1.38 0.893833 \n", - "\n", - "[10 rows x 21 columns]" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 1.2 create spectra - create tissue samples for simulation\n", - "\n", - "# setup batch with tissue instances which should be simulated\n", - "batch = factory.create_batch_to_simulate()\n", - "# we want to simulate ten tissue instances in this example\n", - "nr_samples = 10\n", - "df = batch.create_parameters(10)\n", - "\n", - "# lets have a look at the dataframe. Each row corresponds to one tissue instance,\n", - "# each tissue instance is defined by various layers, which all have certain parameters\n", - "# like e.g. oxygenation (here sao2)\n", - "df" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
4.5e-074.52e-074.54e-074.56e-074.58e-074.6e-074.62e-074.64e-074.66e-074.68e-07...7e-077.02e-077.04e-077.06e-077.08e-077.1e-077.12e-077.14e-077.16e-077.18e-07
00.3186160.3469430.3712540.3798780.3855570.3890870.3948770.3977620.4010030.404130...0.4947310.4951620.4950680.4954260.4954470.4950080.4950810.4950930.4946230.494477
10.1402660.1896400.2435540.2597920.2755930.2848330.2963580.3023110.3088770.314986...0.4464260.4471380.4486750.4494690.4502970.4514850.4518860.4517670.4520540.452514
20.0217470.0351540.0562930.0651130.0736100.0807250.0889400.0945650.1008130.107133...0.3781550.3791120.3799530.3810480.3822710.3826990.3841090.3847810.3858160.386681
30.0219310.0319950.0459550.0517710.0569900.0616940.0676900.0713280.0760240.080335...0.4224780.4247930.4259650.4280110.4294140.4303710.4321060.4335270.4337730.435063
40.0692870.1071740.1597940.1774210.1961230.2080050.2219370.2313520.2392310.247642...0.4771400.4783930.4811330.4831720.4851440.4867610.4882540.4902850.4917000.492445
50.0456060.0513120.0585810.0627280.0653590.0689120.0734840.0759510.0801960.084404...0.3826210.3819220.3814710.3814510.3804810.3805680.3798410.3793170.3787140.378075
60.0273930.0446680.0708600.0810270.0912480.0985350.1074260.1125430.1184450.123929...0.3713010.3731900.3750970.3773240.3791270.3805240.3824810.3836580.3854440.386918
70.0489080.0788570.1249280.1422370.1596210.1722800.1868360.1968700.2060290.216111...0.4945830.4963940.4973510.4982170.4990100.4994520.5014810.5016000.5023150.503171
80.0867910.1051410.1258770.1359230.1430730.1511150.1602390.1656310.1738780.180887...0.5160760.5163510.5173030.5170440.5167270.5166640.5154350.5152280.5153230.514933
90.0563380.0714790.0890410.0970410.1033080.1094470.1168740.1209010.1278040.133711...0.5066700.5068890.5078580.5081430.5083510.5082180.5090400.5095760.5085060.508549
\n", - "

10 rows × 135 columns

\n", - "
" - ], - "text/plain": [ - " 4.500000e-07 4.520000e-07 4.540000e-07 4.560000e-07 4.580000e-07 \\\n", - "0 0.318616 0.346943 0.371254 0.379878 0.385557 \n", - "1 0.140266 0.189640 0.243554 0.259792 0.275593 \n", - "2 0.021747 0.035154 0.056293 0.065113 0.073610 \n", - "3 0.021931 0.031995 0.045955 0.051771 0.056990 \n", - "4 0.069287 0.107174 0.159794 0.177421 0.196123 \n", - "5 0.045606 0.051312 0.058581 0.062728 0.065359 \n", - "6 0.027393 0.044668 0.070860 0.081027 0.091248 \n", - "7 0.048908 0.078857 0.124928 0.142237 0.159621 \n", - "8 0.086791 0.105141 0.125877 0.135923 0.143073 \n", - "9 0.056338 0.071479 0.089041 0.097041 0.103308 \n", - "\n", - " 4.600000e-07 4.620000e-07 4.640000e-07 4.660000e-07 4.680000e-07 \\\n", - "0 0.389087 0.394877 0.397762 0.401003 0.404130 \n", - "1 0.284833 0.296358 0.302311 0.308877 0.314986 \n", - "2 0.080725 0.088940 0.094565 0.100813 0.107133 \n", - "3 0.061694 0.067690 0.071328 0.076024 0.080335 \n", - "4 0.208005 0.221937 0.231352 0.239231 0.247642 \n", - "5 0.068912 0.073484 0.075951 0.080196 0.084404 \n", - "6 0.098535 0.107426 0.112543 0.118445 0.123929 \n", - "7 0.172280 0.186836 0.196870 0.206029 0.216111 \n", - "8 0.151115 0.160239 0.165631 0.173878 0.180887 \n", - "9 0.109447 0.116874 0.120901 0.127804 0.133711 \n", - "\n", - " ... 7.000000e-07 7.020000e-07 7.040000e-07 7.060000e-07 \\\n", - "0 ... 0.494731 0.495162 0.495068 0.495426 \n", - "1 ... 0.446426 0.447138 0.448675 0.449469 \n", - "2 ... 0.378155 0.379112 0.379953 0.381048 \n", - "3 ... 0.422478 0.424793 0.425965 0.428011 \n", - "4 ... 0.477140 0.478393 0.481133 0.483172 \n", - "5 ... 0.382621 0.381922 0.381471 0.381451 \n", - "6 ... 0.371301 0.373190 0.375097 0.377324 \n", - "7 ... 0.494583 0.496394 0.497351 0.498217 \n", - "8 ... 0.516076 0.516351 0.517303 0.517044 \n", - "9 ... 0.506670 0.506889 0.507858 0.508143 \n", - "\n", - " 7.080000e-07 7.100000e-07 7.120000e-07 7.140000e-07 7.160000e-07 \\\n", - "0 0.495447 0.495008 0.495081 0.495093 0.494623 \n", - "1 0.450297 0.451485 0.451886 0.451767 0.452054 \n", - "2 0.382271 0.382699 0.384109 0.384781 0.385816 \n", - "3 0.429414 0.430371 0.432106 0.433527 0.433773 \n", - "4 0.485144 0.486761 0.488254 0.490285 0.491700 \n", - "5 0.380481 0.380568 0.379841 0.379317 0.378714 \n", - "6 0.379127 0.380524 0.382481 0.383658 0.385444 \n", - "7 0.499010 0.499452 0.501481 0.501600 0.502315 \n", - "8 0.516727 0.516664 0.515435 0.515228 0.515323 \n", - "9 0.508351 0.508218 0.509040 0.509576 0.508506 \n", - "\n", - " 7.180000e-07 \n", - "0 0.494477 \n", - "1 0.452514 \n", - "2 0.386681 \n", - "3 0.435063 \n", - "4 0.492445 \n", - "5 0.378075 \n", - "6 0.386918 \n", - "7 0.503171 \n", - "8 0.514933 \n", - "9 0.508549 \n", - "\n", - "[10 rows x 135 columns]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# 1.3 create spectra - run simulation\n", - "\n", - "# add reflectance column to dataframe\n", - "for w in WAVELENGTHS:\n", - " df[\"reflectances\", w] = np.NAN # the reflectances have not been calculated yet, thus set no nan\n", - "\n", - "# for each instance in our batch\n", - "for i in range(df.shape[0]):\n", - " # set the desired element in the dataframe to be simulated\n", - " tissue_model.set_dataframe_row(df.loc[i, :])\n", - " logging.info(\"running simulation \" + str(i) + \" for\\n\" +\n", - " str(tissue_model))\n", - " reflectances = create_spectrum(tissue_model, sim_wrapper, WAVELENGTHS)\n", - " # store in dataframe\n", - " for r, w in zip(reflectances, WAVELENGTHS):\n", - " df[\"reflectances\", w][i] = r\n", - " \n", - "# clean up temporarily created files\n", - "os.remove(MCI_FILENAME)\n", - "created_mco_file = os.path.join(os.path.split(MCML_EXECUTABLE)[0], MCO_FILENAME)\n", - "if os.path.isfile(created_mco_file):\n", - " os.remove(created_mco_file)\n", - "\n", - "# Hooray, finished,\n", - "# now our dataframe also contains reflectances for each tissue instance:\n", - "df[\"reflectances\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nwooZFMEAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# 2.1 analyse spectra - plot reflectances\n", - "\n", - "# the usual settings for plotting in ipython notebooks\n", - "import matplotlib.pylab as plt\n", - "%matplotlib inline\n", - "\n", - "# let's have a look at our reflectances\n", - "df[\"reflectances\"].T.plot(kind=\"line\")\n", - "plt.ylabel(\"reflectance\")\n", - "plt.xlabel(\"wavelengths [m]\")\n", - "# put legend outside of plot\n", - "plt.gca().legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", - "plt.grid()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# 2.1 analyse spectra - show distribution of blood volume fraction (vhb) and sao2\n", - "\n", - "# now we need some special pandas functions\n", - "import pandas as pd\n", - "\n", - "# we're interested in the distribution of vhb and sao2 in the first layer (layer0)\n", - "df_vhb_sao2 = df[\"layer0\"][[\"vhb\", \"sao2\"]]\n", - "# plot a scatter matrix showing the distribution of vhb and sao2.\n", - "# of course, with this little data this does not really make sense,\n", - "# however it is a useful tool for analysis if much data is available\n", - "pd.tools.plotting.scatter_matrix(df_vhb_sao2, alpha=0.75, figsize=(6, 6))\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# 3.1 manipulate spectra - apply sliding average\n", - "# in 3.1 and 3.2 we will adapt the generated spectra to an imaginary imaging system\n", - "# This system has filters with 20nm bandwith (taken care of in 3.1)\n", - "# and takes multispectral images in 10nm steps (taken care of in 3.2)\n", - "\n", - "# the module mc.dfmanipulations was written to provide some basic,\n", - "# often needed manipulations of the calculated spectra\n", - "# all dmfmanipulations are performed inplace, however, the df is also returned.\n", - "import mc.dfmanipulations as dfmani\n", - "\n", - "# first copy to not lose our original data\n", - "df2 = df.copy()\n", - "# We apply a sliding average to our data. This is usefull if \n", - "# we want to see e.g. how the reflectance was recorded by bands with a certain width\n", - "# a sliding average of 11 will take the five left and five right of the current reflectance\n", - "# and average. Because we take 2nm steps of reflectance in our simulation this means\n", - "# a 20nm window.\n", - "dfmani.fold_by_sliding_average(df2, 11)\n", - "\n", - "# lets again plot the reflectances\n", - "df2[\"reflectances\"].T.plot(kind=\"line\")\n", - "plt.ylabel(\"reflectance\")\n", - "plt.xlabel(\"wavelengths [m]\")\n", - "# put legend outside of plot\n", - "plt.gca().legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", - "plt.grid()\n", - "# we can see that the bump at 560nm is \"smoother\"" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# 3.2 manipulate spectra - select certain wavelenghts\n", - "\n", - "# our imaginary imaging system takes images in 10nm steps from 470 to 660nm\n", - "imaging_system_wavelengths = np.arange(470, 670, 10) * 10**-9\n", - "\n", - "df3 = df2.copy()\n", - "dfmani.interpolate_wavelengths(df3, imaging_system_wavelengths)\n", - "\n", - "# let's look at the newly created reflectances\n", - "df3[\"reflectances\"].T.plot(kind=\"line\", marker='o')\n", - "plt.ylabel(\"reflectance\")\n", - "plt.xlabel(\"wavelengths [m]\")\n", - "# put legend outside of plot\n", - "plt.gca().legend(loc='center left', bbox_to_anchor=(1, 0.5))\n", - "plt.grid()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# that's it, folks. If you want, you can save the created dataframe easily to csv:\n", - "df.to_csv(\"results.csv\", index=False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/Modules/Biophotonics/python/iMC/tutorials/README.txt b/Modules/Biophotonics/python/iMC/tutorials/README.txt deleted file mode 100644 index f6fb2aa8d9..0000000000 --- a/Modules/Biophotonics/python/iMC/tutorials/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -The tutorials are not fletched out, since I want to discuss the general direction first. -I propose IPhython notebooks, as e.g. Google does for the Caffe framework: -http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb - -I added a tutorial for the monte carlo spectra generation to show how this could look like. - diff --git a/Modules/Biophotonics/python/iMC_ipcai_jcars_save/iMC/tox.ini b/Modules/Biophotonics/python/iMC_ipcai_jcars_save/iMC/tox.ini deleted file mode 100644 index 51e0c9f594..0000000000 --- a/Modules/Biophotonics/python/iMC_ipcai_jcars_save/iMC/tox.ini +++ /dev/null @@ -1,9 +0,0 @@ -# content of: tox.ini , put in same dir as setup.py -[tox] -envlist = py27 -[testenv] -deps=discover # install pytest in the venvs -install_command=pip install -f http://www.simpleitk.org/SimpleITK/resources/software.html --trusted-host www.simpleitk.org {opts} {packages} -#changedir=tests -commands=discover - diff --git a/Modules/BiophotonicsHardware/CMakeLists.txt b/Modules/BiophotonicsHardware/CMakeLists.txt deleted file mode 100644 index 29137eaf7c..0000000000 --- a/Modules/BiophotonicsHardware/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -#MITK_CREATE_MODULE( -# INCLUDE_DIRS ${MITK_BIN_DIR} -# INTERNAL_INCLUDE_DIRS ${INCLUDE_DIRS_INTERNAL} -# DEPENDS MitkOpenCVVideoSupport -# EXPORT_DEFINE MITK_TOFHARDWARE_EXPORT -# ADDITIONAL_LIBS ${ADDITIONAL_LIBS} -#) - - - -#Set Subfolder according to moduls -set( biophotonicsHardware_module_dir - SpectroCam -) - -# add_subdirectories for each module -foreach(biophotonicsHardware_module_dir ${biophotonicsHardware_module_dir}) - add_subdirectory(${biophotonicsHardware_module_dir}) -endforeach() - - - - -#IF(BUILD_TESTING) -# add_subdirectory(Testing) -#ENDIF(BUILD_TESTING) diff --git a/Modules/BiophotonicsHardware/SpectroCam/CMakeLists.txt b/Modules/BiophotonicsHardware/SpectroCam/CMakeLists.txt deleted file mode 100644 index 98b72e720f..0000000000 --- a/Modules/BiophotonicsHardware/SpectroCam/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -#Begin SpectroCam hardware -OPTION(MITK_USE_BiophotonicsHardware_SpectroCam "Enable support for SpectroCam camera" OFF) - -IF(MITK_USE_BiophotonicsHardware_SpectroCam) - #Find SpectroCam SDK - FIND_LIBRARY(MITK_SpectroCam_LIB SpectroCam DOC "SpectroCam access library." HINTS "C:\\Program Files (x86)\\Ocean Thin Films\\SpectroCam SDK\\Stage\\64-Bit") - FIND_PATH(MITK_SpectroCam_INCLUDE_DIR ISpectroCam.h DOC "Include directory of SpectroCam camera." HINTS "C:\\Program Files (x86)\\Ocean Thin Films\\SpectroCam SDK\\Include") - - #Find Jai SDK - FIND_LIBRARY(MITK_JAI_LIB Jai_Factory DOC "SpectroCam access library." HINTS "C:\\Program Files\\JAI\\SDK\\library\\CPP\\lib\\Win64_x64" "C:\\Programme\\JAI\\SDK\\library\\CPP\\lib\\Win64_x64") - FIND_PATH(MITK_JAI_INCLUDE_DIR Jai_Factory.h DOC "Include directory of SpectroCam camera." HINTS "C:\\Program Files\\JAI\\SDK\\library\\CPP\\include" "C:\\Programme\\JAI\\SDK\\library\\CPP\\include") - - SET(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_SpectroCam_LIB} ${MITK_JAI_LIB}) - SET(INCLUDE_DIRS_INTERNAL ${INCLUDE_DIRS_INTERNAL} ${MITK_SpectroCam_INCLUDE_DIR} ${MITK_JAI_INCLUDE_DIR}) - - -MITK_CREATE_MODULE( - INCLUDE_DIRS ${MITK_BIN_DIR} - PUBLIC ${INCLUDE_DIRS_INTERNAL} - ADDITIONAL_LIBS ${ADDITIONAL_LIBS} - DEPENDS MitkCore MitkOpenCVVideoSupport - PACKAGE_DEPENDS OpenCV ITK|ITKIOImageBase -# PUBLIC ${ADDITIONAL_LIBS} -) - - -Message("SpectroCam Module generated") - -ENDIF(MITK_USE_BiophotonicsHardware_SpectroCam) -#End SpectroCam Hardware diff --git a/Modules/BiophotonicsHardware/SpectroCam/files.cmake b/Modules/BiophotonicsHardware/SpectroCam/files.cmake deleted file mode 100644 index 18d1e3c5bb..0000000000 --- a/Modules/BiophotonicsHardware/SpectroCam/files.cmake +++ /dev/null @@ -1,8 +0,0 @@ -IF(MITK_USE_BiophotonicsHardware_SpectroCam) -set(CPP_FILES -mitkSpectroCamController.cpp - -) - - -ENDIF(MITK_USE_BiophotonicsHardware_SpectroCam) \ No newline at end of file diff --git a/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.cpp b/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.cpp deleted file mode 100644 index 96360e0b5f..0000000000 --- a/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.cpp +++ /dev/null @@ -1,745 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#include "mitkSpectroCamController.h" -#include "mitkLogMacros.h" -#include -#include - - -#include -#include -#include -#include - -//OpenCv includes -#include -#include -#include -#include - -// itk includes -#include -#include - -//Spectrocam includes -#include -#include - - - -using namespace std; -using namespace cv; - - -namespace mitk { - - - typedef itk::VectorImage CompositeCameraImageType; - - /** - Here basically all of the implementation for the Spectrocam Controller is located. - This pimpl implementation is necessary because of the additional JAI and SpectroCam libraries, which should be totally hidden - to external modules/plugins. - + due to the c - nature of the Spectrocam callback mechanism we need some global variable sharing which is not nice and should - be hidden from users. - */ - class SpectroCamController_pimpl - { - public: - SpectroCamController_pimpl(); - ~SpectroCamController_pimpl(); - - bool Ini(); - int OpenCameraConnection(); - int CloseCameraConnection(); - bool isCameraRunning(); - - - void SetCurrentImageAsWhiteBalance(); - - mitk::Image::Pointer GetCurrentImage(); - - CompositeCameraImageType::Pointer m_CompositeItkImage_1; - CompositeCameraImageType::Pointer m_CompositeItkImage_2; - mitk::Image::Pointer m_CompositeMitkImage; - - cv::Mat m_CurrentStackSmall; - cv::Mat m_CurrentTransformedStack; - cv::Mat m_FlatfieldSmall; - cv::Mat m_LLSQSolutionSmall; - - const int m_FullWidth; - const int m_FullHeight; - - const int m_SmallWidth; - const int m_SmallHeight; - - bool m_ShowOxygenation; - - // for image double buffer swap - bool m_Image1Selected; - - std::string mode; - std::string model; - - private: - - void InitializeItkImage(mitk::CompositeCameraImageType::Pointer& compositeImage); - - bool m_IsCameraRunning; - - unsigned m_NumRecordedImages; - - ISpectroCam* spectroCam; //SpectroCam var - - STREAM_HANDLE m_hDS; // Handle to the data stream - - uint32_t m_iValidBuffers; // Number of buffers allocated to image acquisition - BUF_HANDLE m_pAquBufferID; // Handles for all the image buffers - HANDLE m_hEventKill; // Event used for speeding up the termination of image capture - - - //Vars for Ini from file - FastModeSettings fastSettings; - SequenceModeSettings seqSettings; - IndexModeSettings indexSettings; - - void SaveCameraStreamToDisk(); - }; - -} - - -// Implementation - -static mitk::SpectroCamController_pimpl* my_SpectroCamController; - -mitk::Image::Pointer mitk::SpectroCamController_pimpl::GetCurrentImage() -{ - mitk::CompositeCameraImageType::Pointer selectedImage; - - // TODO SW: semaphore here so it cannot interfere with callback readout of m_Image1Selected - if (this->m_Image1Selected) - { - this->m_Image1Selected = !this->m_Image1Selected; - selectedImage = this->m_CompositeItkImage_1; - } - else - { - this->m_Image1Selected = !this->m_Image1Selected; - selectedImage = this->m_CompositeItkImage_2; - } - - this->m_CompositeMitkImage = mitk::Image::New(); - MITK_INFO << "Image created"; - this->m_CompositeMitkImage->InitializeByItk(selectedImage); - MITK_INFO << "Initialized image by ITK"; - this->m_CompositeMitkImage->SetVolume(selectedImage->GetBufferPointer()); - MITK_INFO << "Copied data"; - - - return m_CompositeMitkImage; -} - -static cv::Mat createLLSQSolutionFromHMatrix() -{ - //Create the H-Matrix - // Ox DOx //Lookup values at http://omlc.org/spectra/hemoglobin/summary.html - float H[8][4]= {{50104 , 37020. , 405, 1.}, //Filter0 = 580nm +- 10 - {33209.2 , 16156.4 , 785., 1.}, //Filter1 = 470nm +- 10 - {319.6 , 3226.56 , 280., 1.}, //Filter2 = 660nm +- 10 - {32613.2 , 53788 , 495., 1.}, //Filter3 = 560nm +- 10 - {26629.2 , 14550 , 760., 1.}, //Filter4 = 480nm +- 12,5 - {20035.2 , 25773.6 , 665., 1.}, //Filter5 = 511nm +- 10 ->took 510nm - {3200 , 14677.2 , 380., 1.}, //Filter6 = 600nm +- 10 - {290 , 1794.28 , 220., 1.}}; //Filter7 = 700nm - - //Create the hMatrix - cv::Mat hMatrix = cv::Mat(8, 4, CV_32F, &H ); //cv::Mat(rows, cols, type, fill with) - - cv::Mat transH; - transpose(hMatrix,transH); - cv::Mat mulImage = transH * hMatrix; - cv::Mat invImage = mulImage.inv(); - cv::Mat HCompononentsForLLSQ = invImage * transH; - - return HCompononentsForLLSQ; -} - -mitk::SpectroCamController_pimpl::SpectroCamController_pimpl() - :m_hDS(nullptr), - m_NumRecordedImages(1), - m_IsCameraRunning(false), - m_SmallWidth(614), - m_SmallHeight(514), - m_FullWidth(2456), - m_FullHeight(2058), - m_Image1Selected(true), - m_ShowOxygenation(false) -{ - my_SpectroCamController = this; - m_CurrentStackSmall = cv::Mat(8, m_SmallWidth * m_SmallHeight, CV_32F, cv::Scalar(0)); - m_FlatfieldSmall = cv::Mat(8, m_SmallWidth * m_SmallHeight, CV_32F, cv::Scalar(1)); - m_CurrentTransformedStack = cv::Mat(8, m_SmallWidth * m_SmallHeight, CV_32F, cv::Scalar(1)); - - - m_LLSQSolutionSmall = createLLSQSolutionFromHMatrix(); - - -} - -void mitk::SpectroCamController_pimpl::SetCurrentImageAsWhiteBalance() -{ - // deep copy of current image stack - m_FlatfieldSmall = m_CurrentStackSmall.clone(); - - cv::namedWindow("Oxygenation Estimate", WINDOW_AUTOSIZE); - m_ShowOxygenation = true; -} - - - -mitk::SpectroCamController_pimpl::~SpectroCamController_pimpl() -{ -} - - - - - -void mitk::SpectroCamController_pimpl::SaveCameraStreamToDisk() -{ - /* - //=================================Save Images to HDD================================= - imagesRecoreded=0; - - //If Rec is pressed -> Save Images to Harddrive - if (rec == true) //On pressing the Rec-Button we wan to save x Stacks with 8 images each - { - //Save Image - saveImage(in); //std::cout<< "save no."<< imagesRecoreded<< std::endl; - //Icrement counter - imagesRecoreded++; - - if (imagesRecoreded >= (NumberOfStacksToBeRecorded*8) ) //If number of images is bigger or equal to the the Image Stack we want to tecord, untoggle the rec button and reset the counter! - { - imagesRecoreded=0; - rec=false; - ReCButtonControl_Pointer->EnableWindow(TRUE); - } - } - */ -} - - - -//Initialize Camera Controller -bool mitk::SpectroCamController_pimpl::Ini() -{ - //===============Get Ini from File=============== - //Get model from file std::string CChildWindowSampleDlg::getModelNameFromIni() - std::ifstream fin("C:\\ModeSettings.txt"); //Set File to read - std::ofstream fout("C:\\ModeSettingsCheck.txt"); //Set output - const int bufferSize = 1000; - char buffer[bufferSize]; - - if (fin.fail()) - { - MITK_INFO << "Failed opening file ModeSettings.txt!" << endl ; - } - - fin.getline(buffer, bufferSize); - fin.getline(buffer, bufferSize); - model = buffer; - - - //Get mode from file - //Skipping model, getting mode - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - mode = buffer; - - // [FastModeExposure] - for (int i = 0; i < 2; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - fin >> fastSettings.exposure; - fout << fastSettings.exposure << endl;; - - // [FastModeGain] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - fin >> fastSettings.gain; - fout << fastSettings.gain << endl; - - // [SequenceModeExposures] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - for (int i = 0; i < NUMBER_FILTERS; ++i) - { - fin >> seqSettings.exposures[i]; - fout << seqSettings.exposures[i] << endl; - } - - // [SequenceModeGains] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - for (int i = 0; i < NUMBER_FILTERS; ++i) - { - fin >> seqSettings.gains[i]; - fout << seqSettings.gains[i] << endl; - } - - // [IndexModeExposures] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - for (int i = 0; i < NUMBER_FILTERS; ++i) - { - fin >> indexSettings.exposures[i]; - fout << indexSettings.exposures[i] << endl; - } - - // [IndexModeGains] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - for (int i = 0; i < NUMBER_FILTERS; ++i) - { - fin >> indexSettings.gains[i]; - fout << indexSettings.gains[i] << endl; - } - - // [IndexModeNumberFilterIterations] - for (int i = 0; i < 3; ++i) - { - fin.getline(buffer, bufferSize); - fout << buffer << endl; - } - - for (int i = 0; i < NUMBER_FILTERS; ++i) - { - fin >> indexSettings.numFilterIterations[i]; - fout << indexSettings.numFilterIterations[i] << endl; - } - - //After reading files -> close stream - fin.close(); - fout.close(); - - return 0; - -} - -void mitk::SpectroCamController_pimpl::InitializeItkImage(mitk::CompositeCameraImageType::Pointer& compositeImage) -{ - if (compositeImage.IsNull()) - { - - MITK_INFO << "initializing itk::Composite Image"; - mitk::CompositeCameraImageType::RegionType region; - mitk::CompositeCameraImageType::RegionType::SizeType size; - mitk::CompositeCameraImageType::RegionType::IndexType index; - mitk::CompositeCameraImageType::SpacingType spacing; - size.Fill( 1 ); - size[0] = this->m_FullWidth; - size[1] = this->m_FullHeight; - index.Fill(0); - spacing.Fill(1); - region.SetSize(size); - region.SetIndex(index); - - compositeImage = mitk::CompositeCameraImageType::New(); - compositeImage->SetRegions(region); - compositeImage->SetSpacing(spacing); - compositeImage->SetNumberOfComponentsPerPixel(NUMBER_FILTERS); - compositeImage->Allocate(); - } -} - -/** -* this c callback function is where the magic happens. -* it is called every time a new image has arrived from the SpectroCam. -*/ -static void DisplayCameraStream(SpectroCamImage image) -{ - - MITK_INFO << "image callback call"; - try - { - if (image.m_FilterNum < 0 || image.m_FilterNum >= NUMBER_FILTERS) - { - std::cout << "Filter number out of range.\n"<< std::endl; - } - else - { - // Allocate the buffer to hold converted the image. (We only want to do this once for performance reasons) - if (image.m_pAcqImage->pImageBuffer == nullptr) - { - if (J_Image_Malloc(image.m_pAcqImage, image.m_pAcqImage) != J_ST_SUCCESS) - { - return; - } - } - - - //============= Get data from spectrocam to opencv - - // TODO SW: probably we can get around this memcopy by simply setting data pointer? Not sure. - cv::Mat data = cv::Mat( image.m_pAcqImage->iSizeY, image.m_pAcqImage->iSizeX, CV_16U); - memcpy( data.datastart , image.m_pAcqImage->pImageBuffer , image.m_pAcqImage->iImageSize); //Copy Image from JAI-Format to OCV´s IplImage - - - //============= From opencv to mitk::Image (VectorImage) - - mitk::CompositeCameraImageType::Pointer selectedImage; - - if (my_SpectroCamController->m_Image1Selected) - { - selectedImage = my_SpectroCamController->m_CompositeItkImage_1; - } - else - { - selectedImage = my_SpectroCamController->m_CompositeItkImage_2; - } - - itk::ImageRegionIterator imageIterator(selectedImage, selectedImage->GetLargestPossibleRegion()); - - MatConstIterator_ it, end; - it = data.begin(); - end = data.end(); - - - while(!imageIterator.IsAtEnd()) - { - mitk::CompositeCameraImageType::PixelType compositePixel = imageIterator.Get(); - - compositePixel[image.m_FilterNum] = *it; - - ++it; - ++imageIterator; - } - - //both matrix and itk image shall reach end at the same time. - assert(it == end); - - - //============= Display image as opencv window == - - cv::Mat display; - cv::resize(data, display, cvSize(my_SpectroCamController->m_SmallWidth, my_SpectroCamController->m_SmallHeight) ); //do some resizeing for faster display - - display *= 16; // image is only 12 bit large, but datatype is 16 bit. Expand to full range for displaying by multiplying by 2^4. - - - - //Display Image - cv::imshow("Display window", display); //Display image - //MITK_INFO << "pixel 100,100" << display.at(0,100); - - - //============= TODO: live oxygenation estimation - - if (my_SpectroCamController->m_ShowOxygenation) - { - cv::Range slice[2]; - slice[0] = cv::Range( image.m_FilterNum, image.m_FilterNum+1 ); - slice[1] = cv::Range::all(); - - cv::Mat currentSlice = my_SpectroCamController->m_CurrentStackSmall(slice); - - cv::Mat currentImageF32; - display.convertTo(currentImageF32, CV_32F); - - currentImageF32 = currentImageF32.reshape(0, 1); - currentImageF32.copyTo(currentSlice); - - cv::Mat currentWorkingSlice = currentSlice.clone(); - - cv::Mat currentFlatfieldSlice = my_SpectroCamController->m_FlatfieldSmall(slice); - MITK_INFO << "flat current: " << currentFlatfieldSlice.at(0,100); - - - MITK_INFO << "raw measured pixel value: " << currentWorkingSlice.at(0,100); - - cv::divide(currentWorkingSlice, currentFlatfieldSlice, currentWorkingSlice); - MITK_INFO << "corrected by flatfield pixel: " << currentWorkingSlice.at(0,100); - - cv::log(currentWorkingSlice, currentWorkingSlice); - currentWorkingSlice = -0.43429 * currentWorkingSlice; - MITK_INFO << "to absorption: " << currentWorkingSlice.at(0,100); - - currentWorkingSlice.copyTo(my_SpectroCamController->m_CurrentTransformedStack(slice) ); - - //MITK_INFO << "slice 0: " << my_SpectroCamController->m_CurrentTransformedStack.at(0,100);; - - cv::Mat currentEstimate = my_SpectroCamController->m_LLSQSolutionSmall * my_SpectroCamController->m_CurrentTransformedStack; - cv::Range oxyHemo[2]; - oxyHemo[0] = cv::Range(0,1); - oxyHemo[1] = cv::Range::all(); - - cv::Range deOxyHemo[2]; - deOxyHemo[0] = cv::Range(1,2); - deOxyHemo[1] = cv::Range::all(); - - cv::Mat saO2 = currentEstimate(oxyHemo) / (currentEstimate(oxyHemo) + currentEstimate(deOxyHemo)); - - cv::Mat saO2Image = saO2.reshape(0, my_SpectroCamController->m_SmallHeight); - MITK_INFO << "saO2, 200 200: " << saO2Image.at(200,200); - - cv::threshold(saO2Image, saO2Image, 1., 1., cv::THRESH_TRUNC); - cv::threshold(saO2Image, saO2Image, 0., 0., cv::THRESH_TOZERO); - - saO2Image = saO2Image * 637.;// 255.; - - cv::Mat SaO2IntImage; - saO2Image.convertTo(SaO2IntImage, CV_8U); - // MITK_INFO << saO2Image.at(0,100); - - cv::Mat colorImage; - cv::applyColorMap(SaO2IntImage, colorImage, COLORMAP_JET); - cv::imshow("Oxygenation Estimate", colorImage); //Display image - } - - - cv::waitKey(1); - } - - }//try - - catch (std::exception &e) { - MITK_INFO << e.what(); - } -} - - - -int mitk::SpectroCamController_pimpl::OpenCameraConnection() -{ - //=====================OpenFactoryAndCamera===================== - //Create Factory and cam based on //BOOL OpenFactoryAndCamera(); // Open factory and search for cameras. Open first camera - spectroCam = CreateSpectroCam(&DisplayCameraStream, nullptr, 0); - MITK_INFO << "Camera " << model << " is running in: " << mode << "-mode" << endl; - - - - //=====================Open Streams===================== - J_STATUS_TYPE status = spectroCam->initialize(model.c_str(), (std::string("C:\\") + model + "\\").c_str()); - - if (status != J_ST_SUCCESS) - { - MITK_INFO << "Could not initialize camera!" << endl; - } - - // initialize VectorImage - this->InitializeItkImage(this->m_CompositeItkImage_1); - this->InitializeItkImage(this->m_CompositeItkImage_2); - - - - //=====================Open Streams===================== - if (mode == "Fast") - { - status = status | spectroCam->start(fastSettings); - } - - else if (mode == "Sequence") - { - status = status | spectroCam->start(seqSettings); - } - - else if (mode == "IndexFast") - { - indexSettings.filterModeSpeed = IndexModeSettings::INDEX_FAST; - status = status | spectroCam->start(indexSettings); - } - - else if (mode == "IndexSlow") - { - indexSettings.filterModeSpeed = IndexModeSettings::INDEX_SLOW; - status = status | spectroCam->start(indexSettings); - } - - else if (mode == "IndexTriggered") - { - indexSettings.filterModeSpeed = IndexModeSettings::INDEX_TRIGGERED; - status = status | spectroCam->start(indexSettings); - } - - else - { - status = status | spectroCam->start(fastSettings); - } - - MITK_INFO << "status flag: " << status; - - if (status == J_ST_SUCCESS) - { - m_IsCameraRunning = true; - } - - - cv::namedWindow( "Display window", WINDOW_AUTOSIZE );// Create a window for display. - - return status; -} - -bool mitk::SpectroCamController_pimpl::isCameraRunning() -{ - return m_IsCameraRunning; -} - - - -//Method to close down connections -int mitk::SpectroCamController_pimpl::CloseCameraConnection() -{ - - // On click -> Stop acquisition - J_STATUS_TYPE retval = 0; - CAM_HANDLE hCam = spectroCam->GetCameraHandle(); - - // Stop Acquision - if (hCam) - { - retval = retval | J_Camera_ExecuteCommand(hCam, (int8_t*) NODE_NAME_ACQSTOP); - } - - - MITK_INFO << "execute acqstop command"; - - - // Close stream (this frees all allocated buffers) - // Stop the image acquisition engine - J_DataStream_StopAcquisition(m_hDS, ACQ_STOP_FLAG_KILL); - - - MITK_INFO << "execute stop aqui"; - - // UnPrepare Buffers (this removed the buffers from the acquisition engine and frees buffers) - { - void *pPrivate; - void *pBuffer; - - // Flush Queues - J_DataStream_FlushQueue(m_hDS, ACQ_QUEUE_INPUT_TO_OUTPUT); - J_DataStream_FlushQueue(m_hDS, ACQ_QUEUE_OUTPUT_DISCARD); - - // Remove the frame buffer from the Acquisition engine. - J_DataStream_RevokeBuffer(m_hDS, m_pAquBufferID, &pBuffer , &pPrivate); - - m_pAquBufferID = 0; - - m_iValidBuffers = 0; - } - - MITK_INFO << "unprepared buffers"; - - - // Close Stream - if(m_hDS) - { - J_DataStream_Close(m_hDS); - m_hDS = nullptr; - } - - - MITK_INFO << "closed stream"; - - //===================Close Factory and destroy Cam===================== - //void CloseFactoryAndCamera(); // Close camera and factory to clean up - retval = retval | spectroCam->stop(); - - - MITK_INFO << "stopped camera"; - - //BOOL TerminateStreamThread(void); // Terminate the image acquisition thread - if (spectroCam) - { - //DestroySpectroCam(spectroCam); //Destroy SpectroCam-Objekt - } - - MITK_INFO << "destroyed spectrocam"; - - if (J_ST_SUCCESS == retval) - { - m_IsCameraRunning = false; - } - - return retval; -} - - -mitk::SpectroCamController::SpectroCamController() -{ - m_SpectroCamController_pimpl = new SpectroCamController_pimpl(); -} - -mitk::SpectroCamController::~SpectroCamController() -{ - delete m_SpectroCamController_pimpl; -} - -int mitk::SpectroCamController::OpenCameraConnection() -{ - return m_SpectroCamController_pimpl->OpenCameraConnection(); -} - -int mitk::SpectroCamController::CloseCameraConnection() -{ - return m_SpectroCamController_pimpl->CloseCameraConnection(); -} - -bool mitk::SpectroCamController::Ini() -{ - return m_SpectroCamController_pimpl->Ini(); -} - -bool mitk::SpectroCamController::isCameraRunning() -{ - return m_SpectroCamController_pimpl->isCameraRunning(); -} - - -mitk::Image::Pointer mitk::SpectroCamController::GetCurrentImage() -{ - return m_SpectroCamController_pimpl->GetCurrentImage(); -} - -void mitk::SpectroCamController::SetCurrentImageAsWhiteBalance() -{ - m_SpectroCamController_pimpl->SetCurrentImageAsWhiteBalance(); -} diff --git a/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.h b/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.h deleted file mode 100644 index 3a755e08d4..0000000000 --- a/Modules/BiophotonicsHardware/SpectroCam/mitkSpectroCamController.h +++ /dev/null @@ -1,55 +0,0 @@ -/*============================================================================ - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center (DKFZ) -All rights reserved. - -Use of this source code is governed by a 3-clause BSD license that can be -found in the LICENSE file. - -============================================================================*/ -#ifndef mitkSpectroCamController_h -#define mitkSpectroCamController_h - -#include - - -#include -#include - -namespace mitk -{ - // forward declaration of the implementation for the SpectroCam - class SpectroCamController_pimpl; - - /** - * @brief Controller for Pixelteq SpectroCam - * - * - * @ingroup BiophotonicsHardware - */ - class MITKSPECTROCAM_EXPORT SpectroCamController - { - public: - SpectroCamController(); - ~SpectroCamController(); - - bool Ini(); - int OpenCameraConnection(); - int CloseCameraConnection(); - bool isCameraRunning(); - - /** - Returns the current image stack. Is of VectorType, unsigned short - */ - mitk::Image::Pointer GetCurrentImage(); - - void SetCurrentImageAsWhiteBalance(); - - private: - SpectroCamController_pimpl* m_SpectroCamController_pimpl; - }; - -} -#endif diff --git a/Modules/CEST/CMakeLists.txt b/Modules/CEST/CMakeLists.txt index 0b43dac056..a35980ee61 100644 --- a/Modules/CEST/CMakeLists.txt +++ b/Modules/CEST/CMakeLists.txt @@ -1,9 +1,9 @@ MITK_CREATE_MODULE( DEPENDS MitkCore PRIVATE MitkDICOM PACKAGE_DEPENDS - PRIVATE ITK|ITKIOImageBase+ITKIOGDCM Poco + PRIVATE Poco ) add_subdirectory(autoload/IO) add_subdirectory(test) diff --git a/Modules/CEST/autoload/IO/CMakeLists.txt b/Modules/CEST/autoload/IO/CMakeLists.txt index bd424d386a..9b6aa610fa 100644 --- a/Modules/CEST/autoload/IO/CMakeLists.txt +++ b/Modules/CEST/autoload/IO/CMakeLists.txt @@ -1,6 +1,4 @@ MITK_CREATE_MODULE( CESTIO DEPENDS MitkCEST MitkDICOM - PACKAGE_DEPENDS - PRIVATE ITK|ITKIOGDCM AUTOLOAD_WITH MitkDICOM ) diff --git a/Modules/CEST/autoload/IO/resource/cest_DKFZ.xml b/Modules/CEST/autoload/IO/resource/cest_DKFZ.xml index b87f554740..6a35902e76 100644 --- a/Modules/CEST/autoload/IO/resource/cest_DKFZ.xml +++ b/Modules/CEST/autoload/IO/resource/cest_DKFZ.xml @@ -1,11 +1,11 @@ - + - \ No newline at end of file + diff --git a/Modules/CameraCalibration/mitkCameraIntrinsics.cpp b/Modules/CameraCalibration/mitkCameraIntrinsics.cpp index cb81b0f60b..fbb1ce2894 100644 --- a/Modules/CameraCalibration/mitkCameraIntrinsics.cpp +++ b/Modules/CameraCalibration/mitkCameraIntrinsics.cpp @@ -1,507 +1,508 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkCameraIntrinsics.h" #include #include #include +#include mitk::CameraIntrinsics::CameraIntrinsics() : m_Valid(false), m_Mutex(itk::FastMutexLock::New()) { m_CameraMatrix = cv::Mat::zeros(3, 3, cv::DataType::type); m_CameraMatrix.at(2,2) = 1.0; m_DistorsionCoeffs = cv::Mat::zeros(1, 5, cv::DataType::type); } mitk::CameraIntrinsics::CameraIntrinsics(const CameraIntrinsics& other) : itk::Object() , mitk::XMLSerializable() , m_Valid(false) , m_Mutex(itk::FastMutexLock::New()) { this->Copy(&other); } mitk::CameraIntrinsics::~CameraIntrinsics() { } bool mitk::CameraIntrinsics::Equals( const CameraIntrinsics* other ) const { return other->GetDistorsionCoeffsAsPoint4D()== this->GetDistorsionCoeffsAsPoint4D() && other->GetFocalPoint()== this->GetFocalPoint() && other->GetPrincipalPoint() == this->GetPrincipalPoint(); } void mitk::CameraIntrinsics::Copy(const CameraIntrinsics* other) { this->SetIntrinsics( other->GetCameraMatrix().clone() , other->GetDistorsionCoeffs().clone() ); this->SetValid(other->m_Valid); } bool mitk::CameraIntrinsics::IsValid() const { itk::MutexLockHolder lock(*m_Mutex); return m_Valid; } vnl_matrix_fixed mitk::CameraIntrinsics::GetVnlCameraMatrix() const { vnl_matrix_fixed mat; mat.set_identity(); { itk::MutexLockHolder lock(*m_Mutex); mat(0,0) = m_CameraMatrix.at(0,0); mat(1,1) = m_CameraMatrix.at(1,1); mat(0,2) = m_CameraMatrix.at(0,2); mat(1,2) = m_CameraMatrix.at(1,2); } return mat; } void mitk::CameraIntrinsics::SetCameraMatrix( const vnl_matrix_fixed& _CameraMatrix ) { itk::MutexLockHolder lock(*m_Mutex); m_CameraMatrix.at(0,0) = _CameraMatrix(0,0); m_CameraMatrix.at(1,1) = _CameraMatrix(1,1); m_CameraMatrix.at(0,2) = _CameraMatrix(0,2); m_CameraMatrix.at(1,2) = _CameraMatrix(1,2); } vnl_matrix_fixed mitk::CameraIntrinsics::GetVnlCameraMatrix3x4() const { vnl_matrix_fixed mat; mat.fill(0); mat.update( this->GetVnlCameraMatrix().as_matrix() ); return mat; } void mitk::CameraIntrinsics::SetIntrinsics( const cv::Mat& _CameraMatrix , const cv::Mat& _DistorsionCoeffs) { { itk::MutexLockHolder lock(*m_Mutex); if( _CameraMatrix.cols != 3 || _CameraMatrix.rows != 3) throw std::invalid_argument("Wrong format of camera matrix. Should be 3x3" " double."); endoAssertMsg( (_DistorsionCoeffs.cols == 5) && _DistorsionCoeffs.rows == 1, "Wrong format of distorsion coefficients" " vector. Should be 5x1 double."); m_CameraMatrix = _CameraMatrix.clone(); m_DistorsionCoeffs = _DistorsionCoeffs.clone(); m_Valid = true; } this->Modified(); } void mitk::CameraIntrinsics::SetIntrinsics( const mitk::Point3D& focalPoint, const mitk::Point3D& principalPoint, const mitk::Point4D& distortionCoefficients) { { itk::MutexLockHolder lock(*m_Mutex); m_CameraMatrix.at(0,0) = focalPoint[0]; m_CameraMatrix.at(1,1) = focalPoint[1]; m_CameraMatrix.at(0,2) = principalPoint[0]; m_CameraMatrix.at(1,2) = principalPoint[1]; m_DistorsionCoeffs.at(0,0) = distortionCoefficients[0]; m_DistorsionCoeffs.at(0,1) = distortionCoefficients[1]; m_DistorsionCoeffs.at(0,2) = distortionCoefficients[2]; m_DistorsionCoeffs.at(0,3) = distortionCoefficients[3]; } this->Modified(); } void mitk::CameraIntrinsics::SetFocalLength( double x, double y ) { { itk::MutexLockHolder lock(*m_Mutex); m_CameraMatrix.at(0,0) = x; m_CameraMatrix.at(1,1) = y; } this->Modified(); } void mitk::CameraIntrinsics::SetPrincipalPoint( double x, double y ) { { itk::MutexLockHolder lock(*m_Mutex); m_CameraMatrix.at(0,2) = x; m_CameraMatrix.at(1,2) = y; } this->Modified(); } void mitk::CameraIntrinsics::SetDistorsionCoeffs( double k1, double k2, double p1, double p2 ) { { itk::MutexLockHolder lock(*m_Mutex); m_DistorsionCoeffs.at(0,0) = k1; m_DistorsionCoeffs.at(0,1) = k2; m_DistorsionCoeffs.at(0,2) = p1; m_DistorsionCoeffs.at(0,3) = p2; } this->Modified(); } cv::Mat mitk::CameraIntrinsics::GetCameraMatrix() const { itk::MutexLockHolder lock(*m_Mutex); return m_CameraMatrix.clone(); // return a copy of this small matrix } cv::Mat mitk::CameraIntrinsics::GetDistorsionCoeffs() const { itk::MutexLockHolder lock(*m_Mutex); return m_DistorsionCoeffs.clone(); // return a copy of this small matrix } cv::Mat mitk::CameraIntrinsics::GetDistorsionCoeffs() { const CameraIntrinsics* intrinsics = this; return intrinsics->GetDistorsionCoeffs(); } std::string mitk::CameraIntrinsics::ToString() const { itk::MutexLockHolder lock(*m_Mutex); std::ostringstream s; s.precision(12); const cv::Mat& CameraMatrix = m_CameraMatrix; const cv::Mat& DistorsionCoeffs = m_DistorsionCoeffs; s.str(""); s << this->GetNameOfClass() << ": "; s << "fx = " << CameraMatrix.at(0,0); s << ", fy = " << CameraMatrix.at(1,1); s << ", cx = " << CameraMatrix.at(0,2); s << ", cy = " << CameraMatrix.at(1,2); s << ", k1 = " << DistorsionCoeffs.at(0,0); s << ", k2 = " << DistorsionCoeffs.at(0,1); s << ", p1 = " << DistorsionCoeffs.at(0,2); s << ", p2 = " << DistorsionCoeffs.at(0,3); //s << ", k3 = " << DistorsionCoeffs.at(0,4); return s.str(); } -void mitk::CameraIntrinsics::ToXML(TiXmlElement* elem) const +void mitk::CameraIntrinsics::ToXML(tinyxml2::XMLElement* elem) const { itk::MutexLockHolder lock(*m_Mutex); elem->SetValue(this->GetNameOfClass()); std::ostringstream s; s.precision(12); const cv::Mat& CameraMatrix = m_CameraMatrix; s.str(""); s << CameraMatrix.at(0,0); - elem->SetAttribute( "fx", s.str() ); + elem->SetAttribute( "fx", s.str().c_str() ); s.str(""); s << CameraMatrix.at(1,1); - elem->SetAttribute( "fy", s.str() ); + elem->SetAttribute( "fy", s.str().c_str()); s.str(""); s << CameraMatrix.at(0,2); - elem->SetAttribute( "cx", s.str() ); + elem->SetAttribute( "cx", s.str().c_str()); s.str(""); s << CameraMatrix.at(1,2); - elem->SetAttribute( "cy", s.str() ); + elem->SetAttribute( "cy", s.str().c_str()); const cv::Mat& DistorsionCoeffs = m_DistorsionCoeffs; s.str(""); s << DistorsionCoeffs.at(0,0); - elem->SetAttribute( "k1", s.str() ); + elem->SetAttribute( "k1", s.str().c_str()); s.str(""); s << DistorsionCoeffs.at(0,1); - elem->SetAttribute( "k2", s.str() ); + elem->SetAttribute( "k2", s.str().c_str()); s.str(""); s << DistorsionCoeffs.at(0,2); - elem->SetAttribute( "p1", s.str() ); + elem->SetAttribute( "p1", s.str().c_str()); s.str(""); s << DistorsionCoeffs.at(0,3); - elem->SetAttribute( "p2", s.str() ); - elem->SetAttribute("Valid", m_Valid); + elem->SetAttribute( "p2", s.str().c_str()); + elem->SetAttribute("Valid", static_cast(m_Valid)); //s.str(""); s << DistorsionCoeffs.at(4,0); - //elem->SetAttribute( "k3", s.str() ); + //elem->SetAttribute( "k3", s.str().c_str() ); } -void mitk::CameraIntrinsics::FromGMLCalibrationXML(TiXmlElement* elem) +void mitk::CameraIntrinsics::FromGMLCalibrationXML(const tinyxml2::XMLElement* elem) { assert( elem ); - assert( elem->ValueStr() == "results" ); + assert( std::string(elem->Value()) == "results" ); cv::Mat CameraMatrix = cv::Mat::zeros(3, 3, cv::DataType::type); CameraMatrix.at(2,2) = 1.0; cv::Mat DistorsionCoeffs = cv::Mat::zeros(1, 5, cv::DataType::type); - TiXmlElement* focus_lenXElem = elem->FirstChildElement("focus_lenX"); + const auto* focus_lenXElem = elem->FirstChildElement("focus_lenX"); endoAssert( focus_lenXElem != nullptr ); CameraMatrix.at(0,0) = atof( focus_lenXElem->GetText() ); - TiXmlElement* focus_lenYElem = elem->FirstChildElement("focus_lenY"); + const auto* focus_lenYElem = elem->FirstChildElement("focus_lenY"); endoAssert( focus_lenYElem != nullptr ); CameraMatrix.at(1,1) = atof( focus_lenYElem->GetText() ); - TiXmlElement* PrincipalXElem = elem->FirstChildElement("PrincipalX"); + const auto* PrincipalXElem = elem->FirstChildElement("PrincipalX"); endoAssert( PrincipalXElem != nullptr ); CameraMatrix.at(0,2) = atof( PrincipalXElem->GetText() ); - TiXmlElement* PrincipalYElem = elem->FirstChildElement("PrincipalY"); + const auto* PrincipalYElem = elem->FirstChildElement("PrincipalY"); endoAssert( PrincipalYElem != nullptr ); CameraMatrix.at(1,2) = atof( PrincipalYElem->GetText() ); // DISTORSION COEFFS - TiXmlElement* Dist1Elem = elem->FirstChildElement("Dist1"); + const auto* Dist1Elem = elem->FirstChildElement("Dist1"); endoAssert( Dist1Elem != nullptr ); DistorsionCoeffs.at(0,0) = atof( Dist1Elem->GetText() ); - TiXmlElement* Dist2Elem = elem->FirstChildElement("Dist2"); + const auto* Dist2Elem = elem->FirstChildElement("Dist2"); endoAssert( Dist2Elem != nullptr ); DistorsionCoeffs.at(0,1) = atof( Dist2Elem->GetText() ); - TiXmlElement* Dist3Elem = elem->FirstChildElement("Dist3"); + const auto* Dist3Elem = elem->FirstChildElement("Dist3"); endoAssert( Dist3Elem != nullptr ); DistorsionCoeffs.at(0,2) = atof( Dist3Elem->GetText() ); - TiXmlElement* Dist4Elem = elem->FirstChildElement("Dist4"); + const auto* Dist4Elem = elem->FirstChildElement("Dist4"); endoAssert( Dist4Elem != nullptr ); DistorsionCoeffs.at(0,3) = atof( Dist4Elem->GetText() ); int valid = 0; elem->QueryIntAttribute("Valid", &valid); { itk::MutexLockHolder lock(*m_Mutex); m_Valid = static_cast(valid); m_CameraMatrix = CameraMatrix; m_DistorsionCoeffs = DistorsionCoeffs; } this->Modified(); } -void mitk::CameraIntrinsics::FromXML(TiXmlElement* elem) +void mitk::CameraIntrinsics::FromXML(const tinyxml2::XMLElement* elem) { endoAssert ( elem ); MITK_DEBUG << elem->Value(); - std::string filename; - if(elem->QueryStringAttribute("file", &filename) == TIXML_SUCCESS) + const char* filename = elem->Attribute("file"); + if(nullptr != filename) { this->FromXMLFile(filename); return; } else if(strcmp(elem->Value(), "CalibrationProject") == 0) { this->FromGMLCalibrationXML(elem->FirstChildElement("results")); return; } assert ( elem ); if(strcmp(elem->Value(), this->GetNameOfClass()) != 0) elem = elem->FirstChildElement(this->GetNameOfClass()); std::ostringstream err; // CAMERA MATRIX cv::Mat CameraMatrix = cv::Mat::zeros(3, 3, cv::DataType::type); CameraMatrix.at(2,2) = 1.0; double val = 0.0; - if(elem->QueryDoubleAttribute("fx", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("fx", &val) == tinyxml2::XML_SUCCESS) CameraMatrix.at(0,0) = val; else err << "fx, "; - if(elem->QueryDoubleAttribute("fy", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("fy", &val) == tinyxml2::XML_SUCCESS) CameraMatrix.at(1,1) = val; else err << "fy, "; - if(elem->QueryDoubleAttribute("cx", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("cx", &val) == tinyxml2::XML_SUCCESS) CameraMatrix.at(0,2) = val; else err << "cx, "; - if(elem->QueryDoubleAttribute("cy", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("cy", &val) == tinyxml2::XML_SUCCESS) CameraMatrix.at(1,2) = val; else err << "cy, "; // DISTORSION COEFFS endodebug( "creating DistorsionCoeffs from XML file") cv::Mat DistorsionCoeffs = cv::Mat::zeros(1, 5, cv::DataType::type); - if(elem->QueryDoubleAttribute("k1", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("k1", &val) == tinyxml2::XML_SUCCESS) DistorsionCoeffs.at(0,0) = val; else err << "k1, "; - if(elem->QueryDoubleAttribute("k2", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("k2", &val) == tinyxml2::XML_SUCCESS) DistorsionCoeffs.at(0,1) = val; else err << "k2, "; - if(elem->QueryDoubleAttribute("p1", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("p1", &val) == tinyxml2::XML_SUCCESS) DistorsionCoeffs.at(0,2) = val; else err << "p1, "; - if(elem->QueryDoubleAttribute("p2", &val) == TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("p2", &val) == tinyxml2::XML_SUCCESS) DistorsionCoeffs.at(0,3) = val; else err << "p2, "; DistorsionCoeffs.at(0,4) = 0.0; - /*if(elem->QueryDoubleAttribute("k3", &val) == TIXML_SUCCESS) + /*if(elem->QueryDoubleAttribute("k3", &val) == tinyxml2::XML_SUCCESS) DistorsionCoeffs.at(4,0) = val; else err << "k3, ";*/ std::string errorStr = err.str(); int errLength = errorStr.length(); if(errLength > 0) { errorStr = errorStr.substr(0, errLength-2); errorStr.append(" not found"); throw std::invalid_argument(err.str()); } int valid = 0; elem->QueryIntAttribute("Valid", &valid); { itk::MutexLockHolder lock(*m_Mutex); m_Valid = static_cast(valid); m_CameraMatrix = CameraMatrix; m_DistorsionCoeffs = DistorsionCoeffs; } this->Modified(); } double mitk::CameraIntrinsics::GetFocalLengthX() const { itk::MutexLockHolder lock(*m_Mutex); double FocalLengthX = m_CameraMatrix.at(0,0); return FocalLengthX; } double mitk::CameraIntrinsics::GetFocalLengthY() const { itk::MutexLockHolder lock(*m_Mutex); double FocalLengthY = m_CameraMatrix.at(1,1);; return FocalLengthY; } double mitk::CameraIntrinsics::GetPrincipalPointX() const { itk::MutexLockHolder lock(*m_Mutex); double PrincipalPointX = m_CameraMatrix.at(0,2); return PrincipalPointX; } double mitk::CameraIntrinsics::GetPrincipalPointY() const { itk::MutexLockHolder lock(*m_Mutex); double PrincipalPointY = m_CameraMatrix.at(1,2); return PrincipalPointY; } mitk::Point4D mitk::CameraIntrinsics::GetDistorsionCoeffsAsPoint4D() const { itk::MutexLockHolder lock(*m_Mutex); mitk::Point4D coeffs; coeffs[0] = m_DistorsionCoeffs.at(0,0); coeffs[1] = m_DistorsionCoeffs.at(0,1); coeffs[2] = m_DistorsionCoeffs.at(0,2); coeffs[3] = m_DistorsionCoeffs.at(0,3); return coeffs; } mitk::Point3D mitk::CameraIntrinsics::GetFocalPoint() const { mitk::Point3D p; p[0] = this->GetFocalLengthX(); p[1] = this->GetFocalLengthY(); p[2] = 0; return p; } mitk::Point3D mitk::CameraIntrinsics::GetPrincipalPoint() const { mitk::Point3D p; p[0] = this->GetPrincipalPointX(); p[1] = this->GetPrincipalPointY(); p[2] = 0; return p; } vnl_vector_fixed mitk::CameraIntrinsics::GetFocalPointAsVnlVector() const { vnl_vector_fixed vec; vec[0] = this->GetFocalLengthX(); vec[1] = this->GetFocalLengthY(); return vec; } vnl_vector_fixed mitk::CameraIntrinsics::GetPrincipalPointAsVnlVector() const { vnl_vector_fixed vec; vec[0] = this->GetPrincipalPointX(); vec[1] = this->GetPrincipalPointY(); return vec; } std::ostream& operator<< (std::ostream& os, mitk::CameraIntrinsics::Pointer p) { os << p->ToString(); return os; } std::string mitk::CameraIntrinsics::GetString() { return this->ToString(); } std::string mitk::CameraIntrinsics::ToOctaveString( const std::string& varName) { std::ostringstream s; s << varName << " = [" << this->GetFocalLengthX() << " 0 " << this->GetPrincipalPointX() << "; 0 " << this->GetFocalLengthY() << " " << this->GetPrincipalPointY() << ";" << " 0 0 1 ];"; return s.str(); } void mitk::CameraIntrinsics::SetValid( bool valid ) { itk::MutexLockHolder lock(*m_Mutex); m_Valid = valid; } itk::LightObject::Pointer mitk::CameraIntrinsics::InternalClone() const { itk::LightObject::Pointer result(new Self(*this)); result->UnRegister(); return result; } diff --git a/Modules/CameraCalibration/mitkCameraIntrinsics.h b/Modules/CameraCalibration/mitkCameraIntrinsics.h index a6004b8960..a36cbf0a7f 100644 --- a/Modules/CameraCalibration/mitkCameraIntrinsics.h +++ b/Modules/CameraCalibration/mitkCameraIntrinsics.h @@ -1,141 +1,141 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkCameraIntrinsics_h #define mitkCameraIntrinsics_h #include #include #include #include #include #include "mitkXMLSerializable.h" #include #include "opencv2/core.hpp" int mitkCameraIntrinsicsTest(int, char* []); namespace mitk { /// /// \brief class representing camera intrinsics and related functions /// class MITKCAMERACALIBRATION_EXPORT CameraIntrinsics: virtual public itk::Object, virtual public mitk::XMLSerializable { public: /// /// for testing purposes /// friend int mitkCameraIntrinsicsTest(int argc, char* argv[]); /// /// smartpointer typedefs /// mitkClassMacroItkParent(CameraIntrinsics, itk::Object); /// /// the static new function /// itkFactorylessNewMacro(Self); /// /// make a clone of this intrinsics /// itkCloneMacro(Self); /// /// copy information from other to this /// void Copy(const CameraIntrinsics* other); /// /// checks two intrinsics for equality /// bool Equals( const CameraIntrinsics* other ) const; /// /// \return the intrinsic parameter matrix as a 3x3 vnl matrix /// vnl_matrix_fixed GetVnlCameraMatrix() const; /// /// \return the intrinsic parameter matrix as a 3x4 vnl matrix /// (the last column only containing zeros) /// vnl_matrix_fixed GetVnlCameraMatrix3x4() const; /// /// \return true if the intrinsics are set (some plausibility checks /// may be done here) /// bool IsValid() const; void SetValid(bool valid); cv::Mat GetCameraMatrix() const; cv::Mat GetDistorsionCoeffs(); cv::Mat GetDistorsionCoeffs() const; - void ToXML(TiXmlElement* elem) const override; + void ToXML(tinyxml2::XMLElement* elem) const override; std::string ToString() const; std::string GetString(); double GetFocalLengthX() const; double GetFocalLengthY() const; double GetPrincipalPointX() const; double GetPrincipalPointY() const; mitk::Point4D GetDistorsionCoeffsAsPoint4D() const; mitk::Point3D GetFocalPoint() const; mitk::Point3D GetPrincipalPoint() const; vnl_vector_fixed GetFocalPointAsVnlVector() const; vnl_vector_fixed GetPrincipalPointAsVnlVector() const; /// /// set a new camera matrix utilizing a vnl matrix /// void SetCameraMatrix( const vnl_matrix_fixed& _CameraMatrix ); void SetIntrinsics( const cv::Mat& _CameraMatrix , const cv::Mat& _DistorsionCoeffs); void SetFocalLength( double x, double y ); void SetPrincipalPoint( double x, double y ); void SetDistorsionCoeffs( double k1, double k2, double p1, double p2 ); void SetIntrinsics( const mitk::Point3D& focalPoint, const mitk::Point3D& principalPoint, const mitk::Point4D& distortionCoefficients); - void FromXML(TiXmlElement* elem) override; - void FromGMLCalibrationXML(TiXmlElement* elem); + void FromXML(const tinyxml2::XMLElement* elem) override; + void FromGMLCalibrationXML(const tinyxml2::XMLElement* elem); std::string ToOctaveString(const std::string& varName="CameraIntrinsics"); ~CameraIntrinsics() override; protected: CameraIntrinsics(); CameraIntrinsics(const CameraIntrinsics& other); cv::Mat m_CameraMatrix; cv::Mat m_DistorsionCoeffs; bool m_Valid; itk::FastMutexLock::Pointer m_Mutex; private: itk::LightObject::Pointer InternalClone() const override; }; } // namespace mitk MITKCAMERACALIBRATION_EXPORT std::ostream& operator<< (std::ostream& os, mitk::CameraIntrinsics::Pointer p); #endif // mitkCameraIntrinsics_h diff --git a/Modules/CameraCalibration/mitkEndoDebugFromXmlFile.cpp b/Modules/CameraCalibration/mitkEndoDebugFromXmlFile.cpp index a88a588b80..e9b827e034 100644 --- a/Modules/CameraCalibration/mitkEndoDebugFromXmlFile.cpp +++ b/Modules/CameraCalibration/mitkEndoDebugFromXmlFile.cpp @@ -1,159 +1,169 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkEndoDebugFromXmlFile.h" #include -#include +#include #include using namespace std; namespace mitk { struct EndoDebugFromXmlFileData { const std::string* m_FileName; // private EndoDebug* m_EndoDebug; long int m_FileModifiedTime; }; EndoDebugFromXmlFile::EndoDebugFromXmlFile( const std::string* _FileName, EndoDebug* _EndoDebug ) : d( new EndoDebugFromXmlFileData ) { d->m_FileName = _FileName; d->m_EndoDebug = _EndoDebug; d->m_FileModifiedTime = 0; } EndoDebugFromXmlFile::~EndoDebugFromXmlFile() { delete d; } void StringExplode(string str, string separator, set* results){ std::size_t found; found = str.find_first_of(separator); while(found != string::npos){ if(found != 0){ results->insert(str.substr(0,found)); } str = str.substr(found+1); found = str.find_first_of(separator); } if(!str.empty()){ results->insert(str); } } #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4390) #endif void EndoDebugFromXmlFile::Update() { endodebug( __FUNCTION__ ) std::string _FileName = *d->m_FileName; if( !itksys::SystemTools::FileExists( _FileName.c_str() ) ) { endodebug(_FileName << " does not exist"); return; } long int _FileModifiedTime = itksys::SystemTools::ModifiedTime( _FileName.c_str() ); // file has changed: we know an older version... if( d->m_FileModifiedTime >= _FileModifiedTime ) { endodebug("File not changed. No Update necessary."); return; } // reread - endodebugvar( _FileName ) - TiXmlDocument doc( _FileName ); - doc.LoadFile(); - TiXmlHandle docHandle( &doc ); - TiXmlElement* elem = docHandle.FirstChildElement().FirstChildElement( "EndoDebug" ).ToElement(); + endodebugvar(_FileName) + tinyxml2::XMLDocument doc; + doc.LoadFile(_FileName.c_str()); + tinyxml2::XMLHandle docHandle(&doc); + auto* elem = docHandle.FirstChildElement().FirstChildElement( "EndoDebug" ).ToElement(); if(elem == nullptr) { endodebug("EndoDebug element not found"); return; } int _DebugEnabled = d->m_EndoDebug->GetDebugEnabled(); - if( elem->QueryIntAttribute("DebugEnabled",&_DebugEnabled) != TIXML_SUCCESS ) + if( elem->QueryIntAttribute("DebugEnabled",&_DebugEnabled) != tinyxml2::XML_SUCCESS ) { endodebug("DebugEnabled attribute not found"); } int _ShowImagesInDebug = d->m_EndoDebug->GetShowImagesInDebug(); - if( elem->QueryIntAttribute("ShowImagesInDebug",&_ShowImagesInDebug) != TIXML_SUCCESS ) + if( elem->QueryIntAttribute("ShowImagesInDebug",&_ShowImagesInDebug) != tinyxml2::XML_SUCCESS) { endodebug("ShowImagesInDebug attribute not found"); } int _ShowImagesTimeOut = static_cast(d->m_EndoDebug->GetShowImagesTimeOut()); - if( elem->QueryIntAttribute("ShowImagesTimeOut",&_ShowImagesTimeOut) != TIXML_SUCCESS ) + if( elem->QueryIntAttribute("ShowImagesTimeOut",&_ShowImagesTimeOut) != tinyxml2::XML_SUCCESS) { endodebug("ShowImagesTimeOut attribute not found"); } - std::string _DebugImagesOutputDirectory = d->m_EndoDebug->GetDebugImagesOutputDirectory(); - if( elem->QueryStringAttribute("DebugImagesOutputDirectory",&_DebugImagesOutputDirectory) != TIXML_SUCCESS ) + std::string _DebugImagesOutputDirectory; + const char* _DebugImagesOutputDirectoryC = elem->Attribute("DebugImagesOutputDirectory"); + if(nullptr == _DebugImagesOutputDirectoryC) { + _DebugImagesOutputDirectory = d->m_EndoDebug->GetDebugImagesOutputDirectory(); endodebug("DebugImagesOutputDirectory attribute not found"); } + else + { + _DebugImagesOutputDirectory = _DebugImagesOutputDirectoryC; + } std::set _FilesToDebug; std::string _FilesToDebugString; - if( elem->QueryStringAttribute("FilesToDebug",&_FilesToDebugString) != TIXML_SUCCESS ) + const char* _FilesToDebugStringC = elem->Attribute("FilesToDebug"); + if(nullptr == _FilesToDebugStringC) { endodebug("FilesToDebug attribute not found"); } else { - StringExplode( _FilesToDebugString, ";", &_FilesToDebug ); + _FilesToDebugString = _FilesToDebugStringC; + StringExplode( _FilesToDebugString, ";", &_FilesToDebug ); } std::set _SymbolsToDebug; std::string _SymbolsToDebugString; - if( elem->QueryStringAttribute("SymbolsToDebug",&_SymbolsToDebugString) != TIXML_SUCCESS ) + const char* _SymbolsToDebugStringC = elem->Attribute("SymbolsToDebug"); + if( nullptr == _SymbolsToDebugStringC ) { endodebug("SymbolsToDebug attribute not found"); } else { - StringExplode( _SymbolsToDebugString, ";", &_SymbolsToDebug ); + _SymbolsToDebugString = _SymbolsToDebugStringC; + StringExplode( _SymbolsToDebugString, ";", &_SymbolsToDebug ); } // save mitk::EndoDebug::GetInstance().SetDebugEnabled( _DebugEnabled == 1? true: false ); mitk::EndoDebug::GetInstance().SetShowImagesInDebug( _ShowImagesInDebug == 1? true: false ); mitk::EndoDebug::GetInstance().SetShowImagesTimeOut( _ShowImagesTimeOut ); mitk::EndoDebug::GetInstance().SetDebugImagesOutputDirectory( _DebugImagesOutputDirectory ); mitk::EndoDebug::GetInstance().SetFilesToDebug(_FilesToDebug); mitk::EndoDebug::GetInstance().SetSymbolsToDebug(_SymbolsToDebug); // save that modified time d->m_FileModifiedTime = _FileModifiedTime; } #ifdef _MSC_VER # pragma warning(pop) #endif } diff --git a/Modules/CameraCalibration/mitkEndoDebugToXmlFile.cpp b/Modules/CameraCalibration/mitkEndoDebugToXmlFile.cpp index 8e0a52463c..82a0e184c1 100644 --- a/Modules/CameraCalibration/mitkEndoDebugToXmlFile.cpp +++ b/Modules/CameraCalibration/mitkEndoDebugToXmlFile.cpp @@ -1,121 +1,122 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkEndoDebugToXmlFile.h" -#include +#include namespace mitk { struct EndoDebugToXmlFileData { EndoDebug* m_EndoDebug; const std::string* m_FileName; }; EndoDebugToXmlFile::EndoDebugToXmlFile(EndoDebug *_EndoDebug, const std::string* _FileName) : d( new EndoDebugToXmlFileData ) { d->m_EndoDebug = _EndoDebug; d->m_FileName = _FileName; } EndoDebugToXmlFile::~EndoDebugToXmlFile() { delete d; } void EndoDebugToXmlFile::Update() { std::string _FileName = *d->m_FileName; - TiXmlDocument doc( _FileName.c_str() ); - TiXmlElement* root = nullptr; - TiXmlElement* elem = nullptr; + tinyxml2::XMLDocument doc; + tinyxml2::XMLElement* root = nullptr; + tinyxml2::XMLElement* elem = nullptr; // check if element is already available - if(doc.LoadFile()) + if(tinyxml2::XML_SUCCESS == doc.LoadFile(_FileName.c_str())) { root = doc.FirstChildElement("data"); - if(root) + if(nullptr != root) { elem = root->FirstChildElement( "EndoDebug" ); - if(elem) - root->RemoveChild(elem); - elem = nullptr; + if (nullptr != elem) + { + root->DeleteChild(elem); + elem = nullptr; + } } } else { // document did not exist, create new one with declration - auto decl = new TiXmlDeclaration( "1.0", "", "" ); - doc.LinkEndChild( decl ); + doc.InsertEndChild( doc.NewDeclaration() ); // create root - root = new TiXmlElement( "data" ); - doc.LinkEndChild( root ); + root = doc.NewElement( "data" ); + doc.InsertEndChild( root ); } // create elem if not existent - elem = new TiXmlElement( "EndoDebug" ); + elem = doc.NewElement( "EndoDebug" ); elem->SetAttribute( "DebugEnabled", (d->m_EndoDebug->GetDebugEnabled()? 1:0) ); elem->SetAttribute( "ShowImagesInDebug", (d->m_EndoDebug->GetShowImagesInDebug()? 1:0) ); elem->SetAttribute( "ShowImagesTimeOut", (static_cast(d->m_EndoDebug->GetShowImagesTimeOut())) ); elem->SetAttribute( "DebugImagesOutputDirectory", - d->m_EndoDebug->GetDebugImagesOutputDirectory() ); + d->m_EndoDebug->GetDebugImagesOutputDirectory().c_str() ); std::set _FilesToDebug = d->m_EndoDebug->GetFilesToDebug(); std::string _FilesToDebugString; auto it = _FilesToDebug.begin(); while( it != _FilesToDebug.end() ) { if( it != _FilesToDebug.begin() ) _FilesToDebugString.append( ";" ); _FilesToDebugString.append( *it ); ++it; } - elem->SetAttribute( "FilesToDebug", _FilesToDebugString ); + elem->SetAttribute( "FilesToDebug", _FilesToDebugString.c_str() ); std::set _SymbolsToDebug = d->m_EndoDebug->GetSymbolsToDebug(); std::string _SymbolsToDebugString; it = _SymbolsToDebug.begin(); while( it != _SymbolsToDebug.end() ) { if( it != _SymbolsToDebug.begin() ) _SymbolsToDebugString.append( ";" ); _SymbolsToDebugString.append( *it ); ++it; } - elem->SetAttribute( "SymbolsToDebug", _SymbolsToDebugString ); + elem->SetAttribute( "SymbolsToDebug", _SymbolsToDebugString.c_str() ); endodebug("adding the EndoDebug as child element of the data node") - root->LinkEndChild(elem); + root->InsertEndChild(elem); endodebug("saving file " << _FileName) - if( !doc.SaveFile( _FileName ) ) + if( tinyxml2::XML_SUCCESS != doc.SaveFile( _FileName.c_str() ) ) { endodebug("File " << _FileName << " could not be written. Please check permissions."); } } void EndoDebugToXmlFile::SetEndoDebug(EndoDebug *_EndoDebug) { d->m_EndoDebug = _EndoDebug; } void EndoDebugToXmlFile::SetFileName(const std::string *_FileName) { d->m_FileName = _FileName; } } diff --git a/Modules/CameraCalibration/mitkTransform.cpp b/Modules/CameraCalibration/mitkTransform.cpp index d77d2d87fe..0a65753afb 100644 --- a/Modules/CameraCalibration/mitkTransform.cpp +++ b/Modules/CameraCalibration/mitkTransform.cpp @@ -1,745 +1,750 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkTransform.h" #include #include #include #include #include #include +#include + namespace mitk { // DO NOT CHANGE THE VALUES OF THESE CONSTANTS!! const std::string Transform::UNKNOWN_TYPE = "Unknown type"; const std::string Transform::ENDOSCOPE_SCOPE_TOOL = "Endoscope scope tool"; const std::string Transform::ENDOSCOPE_CAM_TOOL = "Endoscope camera tool"; const std::string Transform::CHESSBOARD_TOOL = "Chessboard tool"; const std::string Transform::POINTER_TOOL = "Pointer tool"; const std::string Transform::POINTER_TO_CHESSBOARD_ORIGIN = "Pointer to chessboard origin"; const std::string Transform::POINTER_TO_CHESSBOARD_X_SUPPORT_POINT = "Pointer to chessboard X support origin"; const std::string Transform::POINTER_TO_CHESSBOARD_Y_SUPPORT_POINT = "Pointer to chessboard Y support origin"; const std::string Transform::BOARD_TO_BOARD_TOOL = "Board to board tool"; const std::string Transform::REFERENCE_CAMERA_TRANSFORM = "Reference camera transform"; const std::string Transform::REFERENCE_SCOPE_TRANSFORM = "Reference scope transform"; const std::string Transform::EYE_TO_HAND_TRANSFORM = "Eye to hand transform"; const std::string Transform::CAMERA_EXTRINSICS = "Camera extrinsics"; Transform::Transform() : m_NavData(mitk::NavigationData::New()), m_Type( UNKNOWN_TYPE ) { vnl_matrix_fixed rot; rot.set_identity(); this->SetRotation( rot ); } Transform::Transform(const mitk::NavigationData* nd) : m_NavData(mitk::NavigationData::New()), m_Type( UNKNOWN_TYPE ) { m_NavData->Graft(nd); } Transform::Transform(const std::string& s) : m_NavData(mitk::NavigationData::New()), m_Type( s ) { vnl_matrix_fixed rot; rot.set_identity(); this->SetRotation( rot ); } void Transform::Copy(const mitk::NavigationData* nd) { (const_cast(m_NavData.GetPointer()))->Graft(nd); } void Transform::Concatenate( mitk::Transform* transform ) { vnl_matrix_fixed mat = transform->GetMatrix(); mat = mat * this->GetMatrix(); // this->SetMatrix( mat ); } void Transform::Concatenate( const vnl_matrix_fixed& transform ) { Transform::Pointer t = Transform::New(); t->SetMatrix( transform ); this->Concatenate( t ); } void Transform::Concatenate( const vtkMatrix4x4* transform ) { Transform::Pointer t = Transform::New(); t->SetMatrix( transform ); this->Concatenate( t ); } void Transform::Reset() { mitk::NavigationData::Pointer nd = NavigationData::New(); this->Copy( nd ); } void Transform::SetOrientation( const vnl_quaternion& orientation) { m_NavData->SetOrientation(orientation); this->Modified(); } void Transform::SetTranslation( const vnl_vector_fixed& transl) { mitk::Point3D p; for(unsigned int i=0; i<3; ++i) p[i] = transl[i]; m_NavData->SetPosition(p); this->Modified(); } void Transform::SetTranslation( float* array ) { vnl_vector_fixed vec; for(unsigned int i=0; iSetTranslation( vec ); } void Transform::SetRotation( float* array ) { vnl_matrix_fixed mat; unsigned int row = 0; unsigned int col = 0; for(unsigned int i=0; i 0 && i % 3 == 0 ) { ++row; col = 0; } mat(row,col) = array[i]; ++col; } this->SetRotation( mat ); } void Transform::SetOrientation( const vnl_quaternion& orientation) { vnl_vector_fixed qvec; VnlVectorFixedCaster caster( &orientation, &qvec ); caster.Update(); mitk::Quaternion p( qvec ); this->SetOrientation( p ); } vnl_vector_fixed Transform::GetVnlDoubleTranslation() const { vnl_vector_fixed vecFloat = this->GetVnlTranslation(); vnl_vector_fixed vecDouble; VnlVectorFixedCaster caster( &vecFloat, &vecDouble ); caster.Update(); return vecDouble; } void Transform::SetTranslation( const vnl_vector& transl) { vnl_vector_fixed dTransl(transl); vnl_vector_fixed fTransl; VnlVectorFixedCaster caster( &dTransl, &fTransl ); caster.Update(); this->SetTranslation( fTransl ); } vnl_quaternion Transform::GetVnlDoubleQuaternion() const { mitk::Quaternion fOrientation = this->GetOrientation(); vnl_quaternion dOrientation; VnlVectorFixedCaster caster( &fOrientation, &dOrientation ); caster.Update(); return dOrientation; } void Transform::FromCSVFile(const std::string& file) { std::ifstream csvFile (file.c_str()); endoAssert ( csvFile.fail() == false ); mitk::Transform::Pointer transform = mitk::Transform::New(); vnl_matrix_fixed mat; std::string line; mitk::ScalarType d = 0.0f; int row=0,column = 0; while (std::getline (csvFile, line)) { std::istringstream linestream(line); std::string item; column = 0; while (std::getline (linestream, item, ',')) { std::istringstream number; number.str(item); number >> d; mat(row, column) = d; ++column; } ++row; } endoAssert( row == 4 && column == 4 ); transform->SetMatrix( mat ); this->SetNavigationData( transform->GetNavigationData() ); // modified is called in SetNavigationData } std::string Transform::ToCSVString() const { std::ostringstream s; s.precision(12); vnl_matrix_fixed mat = this->GetMatrix(); for( unsigned int j=0; j mat = this->GetMatrix(); s << varname << " = ["; for( unsigned int j=0; jGraft(transform->GetNavigationData()); m_Type = transform->GetType(); } mitk::Transform::Pointer Transform::Clone() const { Transform::Pointer copy = Transform::New(); copy->Copy( this ); return copy; } void Transform::SetMatrix( const vtkMatrix4x4* mat) { vnl_matrix_fixed vnlMat; for(unsigned int i=0; i<4; ++i) for(unsigned int j=0; j<4; ++j) vnlMat(i,j) = mat->GetElement(i, j); this->SetMatrix( vnlMat ); } void Transform::ToCSVFile(const std::string& file) const { std::ofstream csvFile; csvFile.open(file.c_str()); endoAssert ( csvFile.fail() == false ); csvFile << this->ToCSVString(); csvFile.close(); } void Transform::ToMatlabFile(const std::string& file , const std::string& varname) const { std::ofstream csvFile; csvFile.open(file.c_str()); endoAssert ( csvFile.fail() == false ); csvFile << this->ToMatlabString(varname); csvFile.close(); } void Transform::SetNavigationData( const mitk::NavigationData* naviData ) { endoAssert( naviData != nullptr ); m_NavData->Graft( naviData ); this->Modified(); } void Transform::SetRotation( vnl_matrix_fixed& mat) { this->m_NavData->SetOrientation( mitk::Quaternion(mat) ); this->Modified(); } void Transform::SetRotation( vnl_matrix& mat) { vnl_matrix_fixed tmp(mat); this->SetRotation( tmp ); } void Transform::SetPosition( const mitk::Point3D& transl) { this->SetTranslation( transl.GetVnlVector() ); } void Transform::SetTranslation( double array[3] ) { mitk::Point3D p; for(unsigned int i = 0; i < 3; ++i) p.SetElement(i, array[i]); this->SetTranslation( p.GetVnlVector() ); } void Transform::SetRotation( double array[3][3] ) { vnl_matrix_fixed mat; for(unsigned int i = 0; i < 3; ++i) for(unsigned int j = 0; j < 3; ++j) mat(i, j) = array[i][j]; this->SetRotation( mat ); } void Transform::Invert() { vnl_matrix_fixed tmp(this->GetMatrix()); this->SetMatrix( vnl_inverse( tmp ) ); } void Transform::SetMatrix( const vnl_matrix_fixed& mat) { // set translation first vnl_vector transl = mat.get_column(3); mitk::Point3D p; for(unsigned int i=0; i<3; ++i) p[i] = transl[i]; m_NavData->SetPosition(p); // set rotation vnl_matrix_fixed rotMatFixed( mat.extract(3,3)); this->SetRotation(rotMatFixed); } bool Transform::IsValid() const { return m_NavData->IsDataValid(); } void Transform::SetTranslation( const cv::Mat& transl) { vnl_vector vec(3); VnlVectorFromCvMat _VnlVectorFromCvMat( &transl, &vec ); _VnlVectorFromCvMat.Update(); this->SetTranslation( vnl_vector_fixed( vec ) ); } void Transform::SetRotation( const cv::Mat& mat ) { vnl_matrix vnlMat(3, 3); VnlMatrixFromCvMat _VnlMatrixFromCvMat( &mat, &vnlMat ); _VnlMatrixFromCvMat.Update(); vnl_matrix_fixed vnlMatFixed(vnlMat); this->SetRotation(vnlMatFixed); } void Transform::SetRotationVector( const cv::Mat& rotVec ) { cv::Mat rotMat; cv::Rodrigues( rotVec, rotMat ); vnl_matrix vnlMat(3, 3); VnlMatrixFromCvMat _VnlMatrixFromCvMat( &rotMat, &vnlMat ); _VnlMatrixFromCvMat.Update(); vnl_matrix_fixed vnlMatFixed(vnlMat); this->SetRotation( vnlMatFixed ); } //# getter mitk::NavigationData::Pointer Transform::GetNavigationData() const { return m_NavData; } mitk::Point3D Transform::GetTranslation() const { return m_NavData->GetPosition(); } mitk::Point3D Transform::GetPosition() const { return m_NavData->GetPosition(); } mitk::Quaternion Transform::GetOrientation() const { return m_NavData->GetOrientation(); } void Transform::GetMatrix(vtkMatrix4x4* matrix) const { vnl_matrix_fixed vnlMat = this->GetMatrix(); for(unsigned int i=0; iSetElement(i,j, vnlMat(i,j)); } void Transform::GetVtkOpenGlMatrix(vtkMatrix4x4* matrix) const { vnl_matrix vnlRotation = this->GetVnlRotationMatrix().as_matrix(); // normalize rows of rotation matrix vnlRotation.normalize_rows(); vnl_matrix vnlInverseRotation(3,3); // invert rotation vnlInverseRotation = vnl_matrix_inverse(vnlRotation); vnl_vector vnlTranslation = this->GetPosition().GetVnlVector(); // rotate translation vector by inverse rotation P = P' vnlTranslation = vnlInverseRotation * vnlTranslation; vnlTranslation *= -1; // save -P' // set position mitk::Transform::Pointer tmp = mitk::Transform::New(); tmp->SetTranslation( vnlTranslation ); tmp->SetRotation( vnlRotation ); tmp->GetMatrix(matrix); } mitk::Point3D Transform::TransformPoint(mitk::Point3D point) const { itk::Matrix R(GetVnlRotationMatrix()); itk::Point pointR = (R * point); mitk::Point3D retPoint = pointR; retPoint[0] = pointR[0] + GetPosition()[0]; retPoint[1] = pointR[1] + GetPosition()[1]; retPoint[2] = pointR[2] + GetPosition()[2]; return retPoint; } //# cv getter cv::Mat Transform::GetCvTranslation() const { cv::Mat mat; vnl_vector vec = this->GetVnlTranslation().as_vector(); endodebugvar( vec ) CvMatFromVnlVector _CvMatFromVnlVector(&vec, &mat); _CvMatFromVnlVector.Update(); return mat; } cv::Mat Transform::GetCvRotationMatrix() const { cv::Mat mat; vnl_matrix vec = this->GetVnlRotationMatrix().as_matrix(); endodebugvar( vec ) CvMatFromVnlMatrix _CvMatFromVnlMatrix(&vec, &mat); _CvMatFromVnlMatrix.Update(); return mat; } cv::Mat Transform::GetCvMatrix() const { cv::Mat mat; vnl_matrix vec = this->GetMatrix().as_matrix(); CvMatFromVnlMatrix _CvMatFromVnlMatrix(&vec, &mat); _CvMatFromVnlMatrix.Update(); return mat; } cv::Mat Transform::GetCvRotationVector() const { cv::Mat rotVec(3,1,cv::DataType::type); cv::Rodrigues( this->GetCvRotationMatrix(), rotVec ); return rotVec; } //# vnl getter vnl_vector_fixed Transform::GetVnlTranslation() const { vnl_vector_fixed vec(m_NavData->GetPosition() .GetVnlVector()); return vec; } vnl_matrix_fixed Transform::GetVnlRotationMatrix() const { return m_NavData->GetOrientation().rotation_matrix_transpose(); } vnl_matrix_fixed Transform::GetVnlDoubleMatrix() const { vnl_matrix_fixed mat = this->GetMatrix(); vnl_matrix_fixed doubleMat; for(unsigned int i=0; i( mat(i,j) ); return doubleMat; } vnl_matrix_fixed Transform::GetMatrix() const { vnl_vector_fixed transl = this->GetVnlTranslation(); vnl_matrix_fixed rot = this->GetVnlRotationMatrix(); vnl_matrix_fixed homMat; homMat.set_identity(); //std::cout << homMat << std::endl; for(unsigned int i=0; i rotMat = this->GetVnlRotationMatrix().transpose(); this->SetRotation( rotMat ); } void Transform::SetValid( bool valid ) { if( m_NavData->IsDataValid() == valid ) return; m_NavData->SetDataValid( valid ); this->Modified(); } std::string mitk::Transform::ToString() const { std::ostringstream s; s.precision(12); mitk::NavigationData::PositionType position; position.Fill(0.0); position = m_NavData->GetPosition(); mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); orientation = m_NavData->GetOrientation(); s << "Translation: [" << position[0] << ", " << position[1] << ", " << position[2] << "]"; s << ", orientation: [" << orientation[0] << ", " << orientation[1] << ", " << orientation[2] << ", " << orientation[3] << "]"; s << ", valid: [" << (this->IsValid()? "true": "false") << "]"; return s.str(); } - void mitk::Transform::ToXML(TiXmlElement* elem) const + void mitk::Transform::ToXML(tinyxml2::XMLElement* elem) const { - std::string value = elem->ValueStr(); + std::string value = elem->Value() != nullptr ? elem->Value() : ""; if(value.empty()) elem->SetValue(this->GetNameOfClass()); mitk::NavigationData::PositionType position; position.Fill(0.0); position = m_NavData->GetPosition(); mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); orientation = m_NavData->GetOrientation(); mitk::NavigationData::CovarianceMatrixType matrix; matrix.SetIdentity(); matrix = m_NavData->GetCovErrorMatrix(); bool hasPosition = true; hasPosition = m_NavData->GetHasPosition(); bool hasOrientation = true; hasOrientation = m_NavData->GetHasOrientation(); bool dataValid = false; dataValid = m_NavData->IsDataValid(); mitk::NavigationData::TimeStampType timestamp=0.0; - elem->SetAttribute("Type", m_Type); - elem->SetDoubleAttribute("Time", timestamp); - elem->SetDoubleAttribute("X", position[0]); - elem->SetDoubleAttribute("Y", position[1]); - elem->SetDoubleAttribute("Z", position[2]); - - elem->SetDoubleAttribute("QX", orientation[0]); - elem->SetDoubleAttribute("QY", orientation[1]); - elem->SetDoubleAttribute("QZ", orientation[2]); - elem->SetDoubleAttribute("QR", orientation[3]); - - elem->SetDoubleAttribute("C00", matrix[0][0]); - elem->SetDoubleAttribute("C01", matrix[0][1]); - elem->SetDoubleAttribute("C02", matrix[0][2]); - elem->SetDoubleAttribute("C03", matrix[0][3]); - elem->SetDoubleAttribute("C04", matrix[0][4]); - elem->SetDoubleAttribute("C05", matrix[0][5]); - elem->SetDoubleAttribute("C10", matrix[1][0]); - elem->SetDoubleAttribute("C11", matrix[1][1]); - elem->SetDoubleAttribute("C12", matrix[1][2]); - elem->SetDoubleAttribute("C13", matrix[1][3]); - elem->SetDoubleAttribute("C14", matrix[1][4]); - elem->SetDoubleAttribute("C15", matrix[1][5]); + elem->SetAttribute("Type", m_Type.c_str()); + elem->SetAttribute("Time", timestamp); + elem->SetAttribute("X", position[0]); + elem->SetAttribute("Y", position[1]); + elem->SetAttribute("Z", position[2]); + + elem->SetAttribute("QX", orientation[0]); + elem->SetAttribute("QY", orientation[1]); + elem->SetAttribute("QZ", orientation[2]); + elem->SetAttribute("QR", orientation[3]); + + elem->SetAttribute("C00", matrix[0][0]); + elem->SetAttribute("C01", matrix[0][1]); + elem->SetAttribute("C02", matrix[0][2]); + elem->SetAttribute("C03", matrix[0][3]); + elem->SetAttribute("C04", matrix[0][4]); + elem->SetAttribute("C05", matrix[0][5]); + elem->SetAttribute("C10", matrix[1][0]); + elem->SetAttribute("C11", matrix[1][1]); + elem->SetAttribute("C12", matrix[1][2]); + elem->SetAttribute("C13", matrix[1][3]); + elem->SetAttribute("C14", matrix[1][4]); + elem->SetAttribute("C15", matrix[1][5]); if (dataValid) elem->SetAttribute("Valid",1); else elem->SetAttribute("Valid",0); if (hasOrientation) elem->SetAttribute("hO",1); else elem->SetAttribute("hO",0); if (hasPosition) elem->SetAttribute("hP",1); else elem->SetAttribute("hP",0); } - void mitk::Transform::FromXML(TiXmlElement* elem) + void mitk::Transform::FromXML(const tinyxml2::XMLElement* elem) { assert(elem); mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0); mitk::NavigationData::TimeStampType timestamp = -1; mitk::NavigationData::CovarianceMatrixType matrix; bool hasPosition = true; bool hasOrientation = true; bool dataValid = false; position.Fill(0.0); matrix.SetIdentity(); - std::string type = Transform::UNKNOWN_TYPE; - elem->QueryStringAttribute("Type", &type); + const char* typeC = elem->Attribute("Type"); + std::string type = nullptr == typeC + ? Transform::UNKNOWN_TYPE + : typeC; + elem->QueryDoubleAttribute("Time",×tamp); // position and orientation is mandatory! - if(elem->QueryDoubleAttribute("X", &position[0]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("X", &position[0]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No X position found in xml"); - if(elem->QueryDoubleAttribute("Y", &position[1]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("Y", &position[1]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No Y position found in xml"); - if(elem->QueryDoubleAttribute("Z", &position[2]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("Z", &position[2]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No Z position found in xml"); - if(elem->QueryDoubleAttribute("QX", &orientation[0]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("QX", &orientation[0]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No QX orientation found in xml"); - if(elem->QueryDoubleAttribute("QY", &orientation[1]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("QY", &orientation[1]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No QY orientation found in xml"); - if(elem->QueryDoubleAttribute("QZ", &orientation[2]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("QZ", &orientation[2]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No QZ orientation found in xml"); - if(elem->QueryDoubleAttribute("QR", &orientation[3]) != TIXML_SUCCESS) + if(elem->QueryDoubleAttribute("QR", &orientation[3]) != tinyxml2::XML_SUCCESS) throw std::invalid_argument("No QR orientation found in xml"); elem->QueryDoubleAttribute("C00", &matrix[0][0]); elem->QueryDoubleAttribute("C01", &matrix[0][1]); elem->QueryDoubleAttribute("C02", &matrix[0][2]); elem->QueryDoubleAttribute("C03", &matrix[0][3]); elem->QueryDoubleAttribute("C04", &matrix[0][4]); elem->QueryDoubleAttribute("C05", &matrix[0][5]); elem->QueryDoubleAttribute("C10", &matrix[1][0]); elem->QueryDoubleAttribute("C11", &matrix[1][1]); elem->QueryDoubleAttribute("C12", &matrix[1][2]); elem->QueryDoubleAttribute("C13", &matrix[1][3]); elem->QueryDoubleAttribute("C14", &matrix[1][4]); elem->QueryDoubleAttribute("C15", &matrix[1][5]); int tmpval = 0; elem->QueryIntAttribute("Valid", &tmpval); if (tmpval == 0) dataValid = false; else dataValid = true; tmpval = 0; elem->QueryIntAttribute("hO", &tmpval); if (tmpval == 0) hasOrientation = false; else hasOrientation = true; tmpval = 0; elem->QueryIntAttribute("hP", &tmpval); if (tmpval == 0) hasPosition = false; else hasPosition = true; nd->SetIGTTimeStamp(timestamp); nd->SetPosition(position); nd->SetOrientation(orientation); nd->SetCovErrorMatrix(matrix); nd->SetDataValid(dataValid); nd->SetHasOrientation(hasOrientation); nd->SetHasPosition(hasPosition); m_NavData = nd; m_Type = type; this->Modified(); } } // namespace mitk std::ostream& operator<< (std::ostream& os, mitk::Transform::Pointer p) { os << p->ToString(); return os; } diff --git a/Modules/CameraCalibration/mitkTransform.h b/Modules/CameraCalibration/mitkTransform.h index 233abbc5b2..7aeabdd4b5 100644 --- a/Modules/CameraCalibration/mitkTransform.h +++ b/Modules/CameraCalibration/mitkTransform.h @@ -1,301 +1,300 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKTRANSFORM_H #define MITKTRANSFORM_H #include #include #include #include #include -#include #include #include #include #include namespace mitk { /// /// \brief class representing a transfrom in 3D /// /// internally it stores a mitk navigation data. this is more /// or less a wrapper for navigation data for easy casting /// between opencv/vnl/mitk/xml representations of transform /// data /// class MITKCAMERACALIBRATION_EXPORT Transform: public itk::Object, public XMLSerializable { public: mitkClassMacroItkParent(Transform, itk::Object); itkFactorylessNewMacro(Transform); mitkNewMacro1Param(Transform, const mitk::NavigationData*); mitkNewMacro1Param(Transform, const std::string&); /// /// constants describing the type of transform /// represented here /// static const std::string UNKNOWN_TYPE; static const std::string ENDOSCOPE_SCOPE_TOOL; static const std::string ENDOSCOPE_CAM_TOOL; static const std::string CHESSBOARD_TOOL; static const std::string POINTER_TOOL; static const std::string POINTER_TO_CHESSBOARD_ORIGIN; static const std::string POINTER_TO_CHESSBOARD_X_SUPPORT_POINT; static const std::string POINTER_TO_CHESSBOARD_Y_SUPPORT_POINT; static const std::string BOARD_TO_BOARD_TOOL; static const std::string REFERENCE_CAMERA_TRANSFORM; static const std::string REFERENCE_SCOPE_TRANSFORM; static const std::string EYE_TO_HAND_TRANSFORM; static const std::string CAMERA_EXTRINSICS; itkGetConstMacro(Type, std::string); itkSetMacro(Type, std::string&); /// /// Copies the content of transform to this /// instance /// void Copy( const mitk::Transform* transform ); /// /// Copies the content of transform to this /// instance /// void Copy( const mitk::NavigationData* transform ); /// /// Inverts the rotation of this transform /// (Polaris navigation Data have inverted rotation /// so you may want to call this function when using /// polaris data) /// void TransposeRotation(); /// /// get a copy of this transform /// mitk::Transform::Pointer Clone() const; /// /// concatenate this transform with the given one, /// i.e. this transform is done first, then transform /// ( if x is this transform, y is transform, then this will be y*x) /// post multiply semantics! /// \see vtkTransform /// void Concatenate( mitk::Transform* transform ); /// /// same as above with vnl mat argument /// void Concatenate( const vnl_matrix_fixed& transform ); /// /// same as above with vtk mat argument /// void Concatenate( const vtkMatrix4x4* transform ); /// /// invert this transform /// void Invert(); /// /// resets the internal variables except type /// void Reset(); /// /// read from xml /// - void FromXML(TiXmlElement* elem) override; + void FromXML(const tinyxml2::XMLElement* elem) override; /// /// read csv file /// void FromCSVFile(const std::string& file); /// /// grafts the data from naviData to this transform /// void SetNavigationData( const mitk::NavigationData* naviData ); /// /// method to set orientation quat /// void SetOrientation( const vnl_quaternion& orientation); /// /// method to set float valued orientation quat /// void SetOrientation( const vnl_quaternion& orientation); /// /// method to set translation /// void SetTranslation( const vnl_vector_fixed& transl); /// /// method to set a vector of doubles as translation /// void SetTranslation( const vnl_vector& transl); /// /// method to set a mitk::Point3D as position /// void SetPosition( const mitk::Point3D& transl); /// /// sets rotation with a rotation matrix /// void SetRotation( vnl_matrix_fixed& mat); /// /// sets rotation with a non fixed rotation matrix /// void SetRotation( vnl_matrix& mat); /// /// sets rotation and translation with a transformation matrix /// void SetMatrix( const vnl_matrix_fixed& mat); /// /// sets rotation and translation with a vtk transformation matrix /// void SetMatrix( const vtkMatrix4x4* mat); /// /// sets translation from a POD vector /// void SetTranslation( float* array ); /// /// sets translation from a POD vector. this must be a /// 3x3=9 sized vector in row major format (first row = first /// three elements) /// void SetRotation( float* array ); /// /// sets translation from a POD vector /// void SetTranslation( double array[3] ); /// /// sets translation from a POD vector /// void SetRotation( double array[3][3] ); /// /// method to set translation by cv vector /// void SetTranslation( const cv::Mat& transl); /// /// sets rotation with a rotation matrix /// void SetRotation( const cv::Mat& mat ); /// /// sets rotation with a rodrigues rotation vector /// void SetRotationVector( const cv::Mat& rotVec); /// /// \return the navigation data that stores all information /// mitk::NavigationData::Pointer GetNavigationData() const; /// /// calls navigationdata::GetPosition() /// mitk::Point3D GetPosition() const; /// /// same as GetPosition /// mitk::Point3D GetTranslation() const; /// /// calls navigationdata::IsValid() /// bool IsValid() const; /// /// calls navigationdata::SetValid() /// void SetValid(bool valid); /// /// calls navigationdata::GetOrientation() /// mitk::Quaternion GetOrientation() const; /// /// \return the homogeneous matrix representing this transform /// vnl_matrix_fixed GetMatrix() const; /// /// \return the homogeneous vtk matrix representing this transform /// void GetMatrix(vtkMatrix4x4* matrix) const; /// /// \return the homogeneous vtk matrix representing this transform /// in !OpenGL! left handed coordinate system /// void GetVtkOpenGlMatrix(vtkMatrix4x4* matrix) const; mitk::Point3D TransformPoint(mitk::Point3D point) const; /// /// create xml representation /// - void ToXML(TiXmlElement* elem) const override; + void ToXML(tinyxml2::XMLElement* elem) const override; /// /// create string representation /// std::string ToString() const; /// /// create string csv representation (only the transformation values!!!!) /// std::string ToCSVString() const; /// /// create matlab representation /// std::string ToMatlabString(const std::string& varname="transform", bool printLastRow=true) const; /// /// write csv representation to file (only the transformation values!!!!) /// void ToCSVFile(const std::string& file) const; /// /// write matlab representation to file /// void ToMatlabFile(const std::string& file , const std::string& varname="transform") const; /// /// conversion to cv types /// cv::Mat GetCvTranslation() const; cv::Mat GetCvRotationVector() const; cv::Mat GetCvRotationMatrix() const; cv::Mat GetCvMatrix() const; /// /// conversion to vnl types /// vnl_vector_fixed GetVnlTranslation() const; vnl_vector_fixed GetVnlDoubleTranslation() const; vnl_quaternion GetVnlDoubleQuaternion() const; vnl_matrix_fixed GetVnlRotationMatrix() const; vnl_matrix_fixed GetVnlDoubleMatrix() const; protected: Transform(); Transform(const mitk::NavigationData* nd); Transform(const std::string& s); // everything is stored here mitk::NavigationData::Pointer m_NavData; /// /// saves the type of the transform (Default is UNKNOWN_TYPE) /// std::string m_Type; }; } // namespace mitk MITKCAMERACALIBRATION_EXPORT std::ostream& operator<< (std::ostream& os, mitk::Transform::Pointer p); #endif // MITKTRANSFORM_H diff --git a/Modules/CameraCalibration/mitkXMLSerializable.cpp b/Modules/CameraCalibration/mitkXMLSerializable.cpp index 525f8456de..0479a46ab1 100644 --- a/Modules/CameraCalibration/mitkXMLSerializable.cpp +++ b/Modules/CameraCalibration/mitkXMLSerializable.cpp @@ -1,137 +1,137 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include "mitkEndoDebug.h" #include "mitkEndoMacros.h" #include +#include namespace mitk { const std::string XMLSerializable::FILE_REFERENCE_ATTRIBUTE_NAME = "fileRef"; const std::string XMLSerializable::ROOT_NAME = "data"; void mitk::XMLSerializable::ToXMLFile(const std::string& file , const std::string& elemName) { - TiXmlElement * rootElem=nullptr; - TiXmlElement * element=nullptr; + tinyxml2::XMLElement * rootElem=nullptr; + tinyxml2::XMLElement* element=nullptr; // determine element to write to std::string elementName = elemName; if(elementName.empty()) elementName = this->GetNameOfClass(); - TiXmlDocument doc( file.c_str() ); - bool loadOkay = doc.LoadFile(); + tinyxml2::XMLDocument doc; // if the document already exists ... - if(loadOkay) + if(tinyxml2::XML_SUCCESS == doc.LoadFile(file.c_str())) { // try to identify the XML element of this class as the root // or as the child of the root rootElem = doc.RootElement(); endoAssertMsg( rootElem, "No root element found in " << file ); // if root element represents this element remove the root - if( rootElem->ValueStr() == elementName ) + if( std::string(rootElem->Value() != nullptr ? rootElem->Value() : "") == elementName ) { - doc.RemoveChild(rootElem); + doc.DeleteChild(rootElem); rootElem = nullptr; } else { // if it is a child of the root remove it too - element = rootElem->FirstChildElement(elementName); + element = rootElem->FirstChildElement(elementName.c_str()); if(element) - rootElem->RemoveChild(element); + rootElem->DeleteChild(element); } } else { // document did not exist, create new one with declration - auto decl = new TiXmlDeclaration( "1.0", "", "" ); - doc.LinkEndChild( decl ); + doc.InsertEndChild( doc.NewDeclaration() ); } m_XMLFileName = file; // create element (if the document already exists this element was removed) - element = new TiXmlElement( elementName ); + element = doc.NewElement( elementName.c_str() ); this->ToXML( element ); // if we do not have a root element create a new one if(!rootElem) - rootElem = new TiXmlElement( ROOT_NAME ); + rootElem = doc.NewElement( ROOT_NAME.c_str() ); // add the element node as child - rootElem->LinkEndChild(element); + rootElem->InsertEndChild(element); // if no root element exists, add it now if(doc.RootElement() == nullptr) - doc.LinkEndChild( rootElem ); + doc.InsertEndChild( rootElem ); - if(!doc.SaveFile( file )) + if(tinyxml2::XML_SUCCESS != doc.SaveFile( file.c_str() )) { std::ostringstream s; s << "File " << file << " could not be written. Please check permissions."; throw std::logic_error(s.str()); } } std::string mitk::XMLSerializable::GetXMLFileName() const { return m_XMLFileName; } void mitk::XMLSerializable::FromXMLFile(const std::string& file , const std::string& elemName) { endodebug( "Trying to read from " << file ) - TiXmlDocument doc( file.c_str() ); - bool loadOkay = doc.LoadFile(); - if(!loadOkay) + tinyxml2::XMLDocument doc; + if(tinyxml2::XML_SUCCESS != doc.LoadFile(file.c_str())) { std::ostringstream s; s << "File " << file << " could not be loaded!"; throw std::logic_error(s.str().c_str()); } m_XMLFileName = file; - TiXmlElement* elem = doc.FirstChildElement(); + auto* elem = doc.FirstChildElement(); endoAssertMsg( elem, "No root element found" ); // determine element to read from std::string elementName = elemName; if(elementName.empty()) elementName = this->GetNameOfClass(); // try again with the first element if(strcmp(elem->Value(), elementName.c_str()) != 0) elem = elem->FirstChildElement(elementName.c_str()); endoAssertMsg( elem, "No child element \"" << elementName << "\" found in " << file ); // if theres an attribute as file reference try to load the class // from that file - std::string filename; - if(elem->QueryStringAttribute(FILE_REFERENCE_ATTRIBUTE_NAME.c_str(), &filename) - == TIXML_SUCCESS) + const char* filenameC = elem->Attribute(FILE_REFERENCE_ATTRIBUTE_NAME.c_str()); + std::string filename = nullptr != filenameC + ? filenameC + : ""; + if(!filename.empty()) { if( !itksys::SystemTools::FileIsFullPath(filename.c_str()) ) filename = itksys::SystemTools::GetFilenamePath(file) + "/" + filename; this->FromXMLFile(filename); return; // exit! } this->FromXML( elem ); } } diff --git a/Modules/CameraCalibration/mitkXMLSerializable.h b/Modules/CameraCalibration/mitkXMLSerializable.h index 31dc61d346..8c0d78ecb9 100644 --- a/Modules/CameraCalibration/mitkXMLSerializable.h +++ b/Modules/CameraCalibration/mitkXMLSerializable.h @@ -1,88 +1,92 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKXMLSerializable_H #define MITKXMLSerializable_H #include -#include #include #include #include +namespace tinyxml2 +{ + class XMLElement; +} + namespace mitk { /// /// \brief interface for all classes able to write themselves to XML files /// class MITKCAMERACALIBRATION_EXPORT XMLSerializable { public: /// /// value of the special tag for file references /// if this is attribute is found the class /// will be loaded from the file in the attributes value /// static const std::string FILE_REFERENCE_ATTRIBUTE_NAME; /// /// the name of the root node that is created when the element is saved /// static const std::string ROOT_NAME; /// /// the tag value will be equals to the class name (function /// implemented by the itkTypeMacro) /// virtual const char* GetNameOfClass() const = 0; /// /// write your values here to elem /// - virtual void ToXML(TiXmlElement* elem) const = 0; + virtual void ToXML(tinyxml2::XMLElement* elem) const = 0; /// /// read your values here from elem /// - virtual void FromXML(TiXmlElement* elem) = 0; + virtual void FromXML(const tinyxml2::XMLElement* elem) = 0; /// /// tries to write the xml data obtained in ToXML() to file /// virtual void ToXMLFile(const std::string& file , const std::string& elemName=""); /// /// loads the XML file and calls FromXML() /// takes the first child of the document /// if this root node value is not equal to GetNameOfClass() /// the method will try to find the first children of the root /// node with the value of GetNameOfClass() /// if elemName is not empty then this value will be used instead /// of GetNameOfClass() /// if this node is found it will check if an attribute named /// FILE_REFERENCE_ATTRIBUTE_NAME is found: in this case /// the method calls itself with this attributes value as parameter /// virtual void FromXMLFile(const std::string& file , const std::string& elemName=""); /// /// \see m_XMLFileName /// std::string GetXMLFileName() const; private: /// /// saves the xmlfile name set for this serializable ( in FromXMLFile() ) /// std::string m_XMLFileName; }; } #endif diff --git a/Modules/Classification/CLLibSVM/test/CMakeLists.txt b/Modules/Classification/CLLibSVM/test/CMakeLists.txt index b4f2e87ef6..5a6a2c1bf5 100644 --- a/Modules/Classification/CLLibSVM/test/CMakeLists.txt +++ b/Modules/Classification/CLLibSVM/test/CMakeLists.txt @@ -1,5 +1,5 @@ MITK_CREATE_MODULE_TESTS() if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|IOCSV) endif() diff --git a/Modules/Classification/CLMRUtilities/test/CMakeLists.txt b/Modules/Classification/CLMRUtilities/test/CMakeLists.txt index b4f2e87ef6..153cd81e2e 100644 --- a/Modules/Classification/CLMRUtilities/test/CMakeLists.txt +++ b/Modules/Classification/CLMRUtilities/test/CMakeLists.txt @@ -1,5 +1 @@ MITK_CREATE_MODULE_TESTS() - -if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK) -endif() diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index 6e45122c9a..fb5bb3b6c8 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,117 +1,117 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} - PACKAGE_DEPENDS ITK Qt5|Core Vigra VTK|IOImage + PACKAGE_DEPENDS Qt5|Core Vigra VTK|IOImage CPP_FILES ${appname}.cpp ) if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI - PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint + PACKAGE_DEPENDS Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/CMakeLists.txt b/Modules/Classification/CLUtilities/CMakeLists.txt index 3c7f86a35d..0f05dd8069 100644 --- a/Modules/Classification/CLUtilities/CMakeLists.txt +++ b/Modules/Classification/CLUtilities/CMakeLists.txt @@ -1,14 +1,10 @@ mitk_create_module( DEPENDS MitkCore MitkCLCore MitkCommandLine MitkDICOM - PACKAGE_DEPENDS PUBLIC Eigen PRIVATE tinyxml VTK|FiltersStatistics + PACKAGE_DEPENDS PUBLIC Eigen OpenMP PRIVATE tinyxml2 VTK|FiltersStatistics ) if(TARGET ${MODULE_TARGET}) - if(MITK_USE_OpenMP) - target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) - endif() - if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp index 0d3bf0c5ef..c884a41381 100644 --- a/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp +++ b/Modules/Classification/CLUtilities/src/mitkCLResultXMLWriter.cpp @@ -1,318 +1,321 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include -#include +#include template class punct_facet : public std::numpunct { public: punct_facet(charT sep) : m_Sep(sep) { } protected: charT do_decimal_point() const override { return m_Sep; } private: charT m_Sep; }; -void AddPropertyAsNode(const mitk::Image* image, const std::string& key, const std::string& tag, TiXmlElement* rootNode) +void AddPropertyAsNode(const mitk::Image* image, const std::string& key, const std::string& tag, tinyxml2::XMLElement* rootNode) { auto prop = image->GetProperty(key.c_str()); if (prop.IsNotNull()) { - auto propNode = new TiXmlElement(tag); - TiXmlText* valueText = new TiXmlText(prop->GetValueAsString()); - propNode->LinkEndChild(valueText); + auto* doc = rootNode->GetDocument(); + auto propNode = doc->NewElement(tag.c_str()); + auto* valueText = doc->NewText(prop->GetValueAsString().c_str()); + propNode->InsertEndChild(valueText); - rootNode->LinkEndChild(propNode); + rootNode->InsertEndChild(propNode); } } -void AddSeriesInstanceUID(const mitk::Image* image, TiXmlElement* xmlNode) +void AddSeriesInstanceUID(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { AddPropertyAsNode(image, mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0020, 0x000e)), "mp:seriesInstanceUID", xmlNode); } -void AddFilePath(const mitk::Image* image, TiXmlElement* xmlNode) +void AddFilePath(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()), "mp:filePath", xmlNode); } -void AddSOPInstanceUIDs(const mitk::Image* image, TiXmlElement* xmlNode) +void AddSOPInstanceUIDs(const mitk::Image* image, tinyxml2::XMLElement* xmlNode) { auto prop = image->GetProperty(mitk::DICOMTagPathToPropertyName(mitk::DICOMTagPath(0x0008, 0x0018)).c_str()); auto dicomProp = dynamic_cast(prop.GetPointer()); + auto* doc = xmlNode->GetDocument(); if (dicomProp != nullptr) { - auto instanceUIDsNode = new TiXmlElement("mp:sopInstanceUIDs"); - xmlNode->LinkEndChild(instanceUIDsNode); + auto* instanceUIDsNode = doc->NewElement("mp:sopInstanceUIDs"); + xmlNode->InsertEndChild(instanceUIDsNode); if (dicomProp->IsUniform()) { - auto instanceUIDNode = new TiXmlElement("mp:sopInstanceUID"); - TiXmlText* valueText = new TiXmlText(dicomProp->GetValueAsString()); - instanceUIDNode->LinkEndChild(valueText); - instanceUIDsNode->LinkEndChild(instanceUIDNode); + auto* instanceUIDNode = doc->NewElement("mp:sopInstanceUID"); + auto* valueText = doc->NewText(dicomProp->GetValueAsString().c_str()); + instanceUIDNode->InsertEndChild(valueText); + instanceUIDsNode->InsertEndChild(instanceUIDNode); } else { const auto timeSteps = dicomProp->GetAvailableTimeSteps(); for (auto timeStep : timeSteps) { const auto slices = dicomProp->GetAvailableSlices(timeStep); for (auto slice : slices) { - auto instanceUIDNode = new TiXmlElement("mp:sopInstanceUID"); - instanceUIDNode->SetAttribute("z", slice); - instanceUIDNode->SetAttribute("t", timeStep); - TiXmlText* valueText = new TiXmlText(dicomProp->GetValue(timeStep, slice)); - instanceUIDNode->LinkEndChild(valueText); - instanceUIDsNode->LinkEndChild(instanceUIDNode); + auto instanceUIDNode = doc->NewElement("mp:sopInstanceUID"); + instanceUIDNode->SetAttribute("z", static_cast(slice)); + instanceUIDNode->SetAttribute("t", static_cast(timeStep)); + auto* valueText = doc->NewText(dicomProp->GetValue(timeStep, slice).c_str()); + instanceUIDNode->InsertEndChild(valueText); + instanceUIDsNode->InsertEndChild(instanceUIDNode); } } } } } -void AddDateAndTime(TiXmlElement* rootNode) +void AddDateAndTime(tinyxml2::XMLElement* rootNode) { - auto dateNode = new TiXmlElement("mp:generationDate"); + auto* doc = rootNode->GetDocument(); + auto* dateNode = doc->NewElement("mp:generationDate"); auto time = std::time(nullptr); std::ostringstream sstream; sstream << std::put_time(std::localtime(&time), "%Y%m%d"); - TiXmlText* valueText = new TiXmlText(sstream.str()); - dateNode->LinkEndChild(valueText); + auto* valueText = doc->NewText(sstream.str().c_str()); + dateNode->InsertEndChild(valueText); - rootNode->LinkEndChild(dateNode); + rootNode->InsertEndChild(dateNode); - auto timeNode = new TiXmlElement("mp:generationTime"); + auto* timeNode = doc->NewElement("mp:generationTime"); std::ostringstream timestream; timestream << std::put_time(std::localtime(&time), "%H%M%S"); - valueText = new TiXmlText(timestream.str()); - timeNode->LinkEndChild(valueText); + valueText = doc->NewText(timestream.str().c_str()); + timeNode->InsertEndChild(valueText); - rootNode->LinkEndChild(timeNode); + rootNode->InsertEndChild(timeNode); } -void AddParameters(const std::map& parameters, TiXmlElement* paramsNode) +void AddParameters(const std::map& parameters, tinyxml2::XMLElement* paramsNode) { + auto* doc = paramsNode->GetDocument(); for (const auto& param : parameters) { mitk::LocaleSwitch lswitch("C"); - auto paramNode = new TiXmlElement("mp:parameter"); - paramNode->SetAttribute("name", param.first); - TiXmlText* valueText = new TiXmlText(param.second.ToString()); - paramNode->LinkEndChild(valueText); - paramsNode->LinkEndChild(paramNode); + auto paramNode = doc->NewElement("mp:parameter"); + paramNode->SetAttribute("name", param.first.c_str()); + auto* valueText = doc->NewText(param.second.ToString().c_str()); + paramNode->InsertEndChild(valueText); + paramsNode->InsertEndChild(paramNode); } } -void AddFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features, TiXmlElement* featsNode) +void AddFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features, tinyxml2::XMLElement* featsNode) { + auto* doc = featsNode->GetDocument(); for (const auto& feat : features) { - auto featNode = new TiXmlElement("mp:feature"); - featNode->SetAttribute("name", feat.first.name); - featNode->SetAttribute("version", feat.first.version); - featNode->SetAttribute("class", feat.first.featureClass); - featNode->SetAttribute("setting", feat.first.settingID); + auto featNode = doc->NewElement("mp:feature"); + featNode->SetAttribute("name", feat.first.name.c_str()); + featNode->SetAttribute("version", feat.first.version.c_str()); + featNode->SetAttribute("class", feat.first.featureClass.c_str()); + featNode->SetAttribute("setting", feat.first.settingID.c_str()); std::ostringstream sstream; sstream.imbue(std::locale("C")); sstream << feat.second; - TiXmlText* valueText = new TiXmlText(sstream.str()); - featNode->LinkEndChild(valueText); - featsNode->LinkEndChild(featNode); + auto* valueText = doc->NewText(sstream.str().c_str()); + featNode->InsertEndChild(valueText); + featsNode->InsertEndChild(featNode); } } -void AddFeatureSettings(const mitk::AbstractGlobalImageFeature::FeatureListType& features, TiXmlElement* featSettingsNode) +void AddFeatureSettings(const mitk::AbstractGlobalImageFeature::FeatureListType& features, tinyxml2::XMLElement* featSettingsNode) { + auto* doc = featSettingsNode->GetDocument(); std::list coveredSettings; for (const auto& feat : features) { auto finding = std::find(coveredSettings.begin(), coveredSettings.end(), feat.first.settingID); if (finding == coveredSettings.end()) { - auto featSettingNode = new TiXmlElement("mp:featureSetting"); - featSettingsNode->LinkEndChild(featSettingNode); - featSettingNode->SetAttribute("name", feat.first.settingID); + auto featSettingNode = doc->NewElement("mp:featureSetting"); + featSettingsNode->InsertEndChild(featSettingNode); + featSettingNode->SetAttribute("name", feat.first.settingID.c_str()); AddParameters(feat.first.parameters, featSettingNode); coveredSettings.push_back(feat.first.settingID); } } } -void AddReaderInfo(const mitk::Image* image, TiXmlElement* imageNode) +void AddReaderInfo(const mitk::Image* image, tinyxml2::XMLElement* imageNode) { - auto ioNode = new TiXmlElement("mp:IOReader"); - imageNode->LinkEndChild(ioNode); + auto* doc = imageNode->GetDocument(); + auto ioNode = doc->NewElement("mp:IOReader"); + imageNode->InsertEndChild(ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()), "mp:description", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_VERSION()), "mp:version", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()), "mp:configuration", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()), "mp:gdcmVersion", ioNode); AddPropertyAsNode(image, mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()), "mp:dcmtkVersion", ioNode); } void WriteDocument(std::ostream& stream, const mitk::Image* image, const mitk::Image* mask, const mitk::AbstractGlobalImageFeature::FeatureListType& features, const std::string& methodName, const std::string& organisation, const std::string& version, const std::string& pipelineUID, const std::map& cliArgs) { - TiXmlDocument doc; - doc.SetCondenseWhiteSpace(false); + tinyxml2::XMLDocument doc; + doc.InsertEndChild(doc.NewDeclaration()); - auto decl = new TiXmlDeclaration( - "1.0", "UTF-8", ""); - doc.LinkEndChild(decl); - - auto rootNode = new TiXmlElement("mp:measurement"); + auto* rootNode = doc.NewElement("mp:measurement"); rootNode->SetAttribute("xmlns:mp", "http://www.mitk.org/Phenotyping"); - doc.LinkEndChild(rootNode); + doc.InsertEndChild(rootNode); - auto methodNode = new TiXmlElement("mp:measurementMethod"); - rootNode->LinkEndChild(methodNode); + auto* methodNode = doc.NewElement("mp:measurementMethod"); + rootNode->InsertEndChild(methodNode); - auto methodNameNode = new TiXmlElement("mp:name"); - TiXmlText* valueText = new TiXmlText(methodName); - methodNameNode->LinkEndChild(valueText); - methodNode->LinkEndChild(methodNameNode); + auto* methodNameNode = doc.NewElement("mp:name"); + auto* valueText = doc.NewText(methodName.c_str()); + methodNameNode->InsertEndChild(valueText); + methodNode->InsertEndChild(methodNameNode); - auto organisationNode = new TiXmlElement("mp:organisation"); - valueText = new TiXmlText(organisation); - organisationNode->LinkEndChild(valueText); - methodNode->LinkEndChild(organisationNode); + auto* organisationNode = doc.NewElement("mp:organisation"); + valueText = doc.NewText(organisation.c_str()); + organisationNode->InsertEndChild(valueText); + methodNode->InsertEndChild(organisationNode); - auto versionNode = new TiXmlElement("mp:version"); - valueText = new TiXmlText(version); - versionNode->LinkEndChild(valueText); - methodNode->LinkEndChild(versionNode); + auto* versionNode = doc.NewElement("mp:version"); + valueText = doc.NewText(version.c_str()); + versionNode->InsertEndChild(valueText); + methodNode->InsertEndChild(versionNode); - auto imageNode = new TiXmlElement("mp:image"); - rootNode->LinkEndChild(imageNode); + auto* imageNode = doc.NewElement("mp:image"); + rootNode->InsertEndChild(imageNode); AddSeriesInstanceUID(image, imageNode); AddFilePath(image, imageNode); AddSOPInstanceUIDs(image, imageNode); AddReaderInfo(image,imageNode); - auto maskNode = new TiXmlElement("mp:mask"); - rootNode->LinkEndChild(maskNode); + auto* maskNode = doc.NewElement("mp:mask"); + rootNode->InsertEndChild(maskNode); AddSeriesInstanceUID(mask, maskNode); AddFilePath(mask, maskNode); AddSOPInstanceUIDs(mask, maskNode); AddReaderInfo(mask, maskNode); //todo mask reader meta info AddDateAndTime(rootNode); - auto pipelineNode = new TiXmlElement("mp:pipelineUID"); - valueText = new TiXmlText(pipelineUID); - pipelineNode->LinkEndChild(valueText); - rootNode->LinkEndChild(pipelineNode); + auto* pipelineNode = doc.NewElement("mp:pipelineUID"); + valueText = doc.NewText(pipelineUID.c_str()); + pipelineNode->InsertEndChild(valueText); + rootNode->InsertEndChild(pipelineNode); - auto paramsNode = new TiXmlElement("mp:parameters"); - rootNode->LinkEndChild(paramsNode); + auto* paramsNode = doc.NewElement("mp:parameters"); + rootNode->InsertEndChild(paramsNode); AddParameters(cliArgs, paramsNode); - auto featsNode = new TiXmlElement("mp:features"); - rootNode->LinkEndChild(featsNode); + auto* featsNode = doc.NewElement("mp:features"); + rootNode->InsertEndChild(featsNode); AddFeatures(features, featsNode); - auto featSettingsNode = new TiXmlElement("mp:featureSettings"); - rootNode->LinkEndChild(featSettingsNode); + auto* featSettingsNode = doc.NewElement("mp:featureSettings"); + rootNode->InsertEndChild(featSettingsNode); AddFeatureSettings(features, featSettingsNode); - TiXmlPrinter printer; + tinyxml2::XMLPrinter printer; + doc.Print(&printer); - doc.Accept(&printer); - stream << printer.Str(); + stream << printer.CStr(); } void mitk::cl::CLResultXMLWriter::SetImage(const Image* image) { m_Image = image; } void mitk::cl::CLResultXMLWriter::SetMask(const Image* mask) { m_Mask = mask; } void mitk::cl::CLResultXMLWriter::SetFeatures(const mitk::AbstractGlobalImageFeature::FeatureListType& features) { m_Features = features; } void mitk::cl::CLResultXMLWriter::SetMethodName(const std::string& name) { m_MethodName = name; } void mitk::cl::CLResultXMLWriter::SetMethodVersion(const std::string& version) { m_MethodVersion = version; } void mitk::cl::CLResultXMLWriter::SetOrganisation(const std::string& orga) { m_Organisation = orga; } void mitk::cl::CLResultXMLWriter::SetPipelineUID(const std::string& pipelineUID) { m_PipelineUID = pipelineUID; } void mitk::cl::CLResultXMLWriter::SetCLIArgs(const std::map& args) { m_CLIArgs = args; } void mitk::cl::CLResultXMLWriter::write(const std::string& filePath) const { std::ofstream resultFile; resultFile.open(filePath.c_str()); if (resultFile.is_open()) { this->write(resultFile); resultFile.close(); } else { MITK_ERROR << "Cannot write xml results. Unable to open file: \""< #include #include #include #include #include #include #include mitk::ContourModelUtils::ContourModelUtils() { } mitk::ContourModelUtils::~ContourModelUtils() { } mitk::ContourModel::Pointer mitk::ContourModelUtils::ProjectContourTo2DSlice( Image *slice, ContourModel *contourIn3D, bool, bool) { if (nullptr == slice || nullptr == contourIn3D) return nullptr; auto projectedContour = ContourModel::New(); projectedContour->Initialize(*contourIn3D); auto sliceGeometry = slice->GetGeometry(); auto numberOfTimesteps = static_cast(contourIn3D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn3D->Begin(t); auto end = contourIn3D->End(t); while (iter != end) { const auto ¤tPointIn3D = (*iter)->Coordinates; Point3D projectedPointIn2D; projectedPointIn2D.Fill(0.0); sliceGeometry->WorldToIndex(currentPointIn3D, projectedPointIn2D); projectedContour->AddVertex(projectedPointIn2D, t); ++iter; } } return projectedContour; } mitk::ContourModel::Pointer mitk::ContourModelUtils::BackProjectContourFrom2DSlice( const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool) { if (nullptr == sliceGeometry || nullptr == contourIn2D) return nullptr; auto worldContour = ContourModel::New(); worldContour->Initialize(*contourIn2D); auto numberOfTimesteps = static_cast(contourIn2D->GetTimeSteps()); for (decltype(numberOfTimesteps) t = 0; t < numberOfTimesteps; ++t) { auto iter = contourIn2D->Begin(t); auto end = contourIn2D->End(t); while (iter != end) { const auto ¤tPointIn2D = (*iter)->Coordinates; Point3D worldPointIn3D; worldPointIn3D.Fill(0.0); sliceGeometry->IndexToWorld(currentPointIn2D, worldPointIn3D); worldContour->AddVertex(worldPointIn3D, t); ++iter; } } return worldContour; } void mitk::ContourModelUtils::FillContourInSlice( ContourModel *projectedContour, Image *sliceImage, Image::Pointer workingImage, int paintingPixelValue) { FillContourInSlice(projectedContour, 0, sliceImage, workingImage, paintingPixelValue); } void mitk::ContourModelUtils::FillContourInSlice( ContourModel *projectedContour, unsigned int t, Image *sliceImage, Image::Pointer workingImage, int paintingPixelValue) { auto contourModelFilter = mitk::ContourModelToSurfaceFilter::New(); contourModelFilter->SetInput(projectedContour); contourModelFilter->Update(); auto surface = mitk::Surface::New(); surface = contourModelFilter->GetOutput(); if (nullptr == surface->GetVtkPolyData(t)) { MITK_WARN << "Could not create surface from contour model."; return; } auto surface2D = vtkSmartPointer::New(); surface2D->SetPoints(surface->GetVtkPolyData(t)->GetPoints()); surface2D->SetLines(surface->GetVtkPolyData(t)->GetLines()); auto image = vtkSmartPointer::New(); image->DeepCopy(sliceImage->GetVtkImageData()); const double FOREGROUND_VALUE = 255.0; const double BACKGROUND_VALUE = 0.0; vtkIdType count = image->GetNumberOfPoints(); for (decltype(count) i = 0; i < count; ++i) image->GetPointData()->GetScalars()->SetTuple1(i, FOREGROUND_VALUE); auto polyDataToImageStencil = vtkSmartPointer::New(); // Set a minimal tolerance, so that clipped pixels will be added to contour as well. polyDataToImageStencil->SetTolerance(mitk::eps); polyDataToImageStencil->SetInputData(surface2D); polyDataToImageStencil->Update(); auto imageStencil = vtkSmartPointer::New(); imageStencil->SetInputData(image); imageStencil->SetStencilConnection(polyDataToImageStencil->GetOutputPort()); imageStencil->ReverseStencilOff(); imageStencil->SetBackgroundValue(BACKGROUND_VALUE); imageStencil->Update(); vtkSmartPointer filledImage = imageStencil->GetOutput(); vtkSmartPointer resultImage = sliceImage->GetVtkImageData(); FillSliceInSlice(filledImage, resultImage, workingImage, paintingPixelValue); sliceImage->SetVolume(resultImage->GetScalarPointer()); } void mitk::ContourModelUtils::FillSliceInSlice( vtkSmartPointer filledImage, vtkSmartPointer resultImage, mitk::Image::Pointer image, int paintingPixelValue) { auto labelImage = dynamic_cast(image.GetPointer()); auto numberOfPoints = filledImage->GetNumberOfPoints(); if (nullptr == labelImage) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } else { auto backgroundValue = labelImage->GetExteriorLabel()->GetValue(); if (paintingPixelValue != backgroundValue) { for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { auto existingValue = resultImage->GetPointData()->GetScalars()->GetTuple1(i); if (!labelImage->GetLabel(existingValue, labelImage->GetActiveLayer())->GetLocked()) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } else { auto activePixelValue = labelImage->GetActiveLabel(labelImage->GetActiveLayer())->GetValue(); for (decltype(numberOfPoints) i = 0; i < numberOfPoints; ++i) { if (1 < filledImage->GetPointData()->GetScalars()->GetTuple1(i)) { if (resultImage->GetPointData()->GetScalars()->GetTuple1(i) == activePixelValue) resultImage->GetPointData()->GetScalars()->SetTuple1(i, paintingPixelValue); } } } } } mitk::ContourModel::Pointer mitk::ContourModelUtils::MoveZerothContourTimeStep(const ContourModel *contour, unsigned int t) { if (nullptr == contour) return nullptr; auto resultContour = ContourModel::New(); resultContour->Expand(t + 1); std::for_each(contour->Begin(), contour->End(), [&resultContour, t](ContourElement::VertexType *vertex) { resultContour->AddVertex(vertex, t); }); return resultContour; } + +int mitk::ContourModelUtils::GetActivePixelValue(mitk::Image* workingImage) +{ + auto* labelSetImage = dynamic_cast(workingImage); + int activePixelValue = 1; + if (nullptr != labelSetImage) + { + activePixelValue = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer())->GetValue(); + } + + return activePixelValue; +} diff --git a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h index 42c91c021e..61a33c0c87 100644 --- a/Modules/ContourModel/Algorithms/mitkContourModelUtils.h +++ b/Modules/ContourModel/Algorithms/mitkContourModelUtils.h @@ -1,96 +1,106 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkContourModelUtils_h #define mitkContourModelUtils_h #include #include #include #include namespace mitk { /** * \brief Helpful methods for working with contours and images * * */ class MITKCONTOURMODEL_EXPORT ContourModelUtils : public itk::Object { public: mitkClassMacroItkParent(ContourModelUtils, itk::Object); /** \brief Projects a contour onto an image point by point. Converts from world to index coordinates. \param slice \param contourIn3D \param correctionForIpSegmentation adds 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) \param constrainToInside */ static ContourModel::Pointer ProjectContourTo2DSlice(Image *slice, ContourModel *contourIn3D, bool correctionForIpSegmentation, bool constrainToInside); /** \brief Projects a slice index coordinates of a contour back into world coordinates. \param sliceGeometry \param contourIn2D \param correctionForIpSegmentation subtracts 0.5 to x and y index coordinates (difference between ipSegmentation and MITK contours) */ static ContourModel::Pointer BackProjectContourFrom2DSlice(const BaseGeometry *sliceGeometry, ContourModel *contourIn2D, bool correctionForIpSegmentation = false); /** \brief Fill a contour in a 2D slice with a specified pixel value at time step 0. */ static void FillContourInSlice(ContourModel *projectedContour, Image *sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue = 1); /** \brief Fill a contour in a 2D slice with a specified pixel value at a given time step. */ static void FillContourInSlice(ContourModel *projectedContour, unsigned int timeStep, Image *sliceImage, mitk::Image::Pointer workingImage, int paintingPixelValue = 1); /** \brief Fills a image (filledImage) into another image (resultImage) by incorporating the rules of LabelSet-Images */ static void FillSliceInSlice(vtkSmartPointer filledImage, vtkSmartPointer resultImage, mitk::Image::Pointer image, int paintingPixelValue); /** \brief Move the contour in time step 0 to to a new contour model at the given time step. */ static ContourModel::Pointer MoveZerothContourTimeStep(const ContourModel *contour, unsigned int timeStep); + /** + \brief Retrieves the active pixel value of a (labelset) image. + If the image is basic image, the pixel value 1 (one) will be returned. + If the image is actually a labelset image, the pixel value of the active label of the active layer will be + returned. + + \param workingImage The (labelset) image to retrieve the active pixel value of. + */ + static int GetActivePixelValue(mitk::Image* workingImage); + protected: ContourModelUtils(); ~ContourModelUtils() override; }; } #endif diff --git a/Modules/ContourModel/CMakeLists.txt b/Modules/ContourModel/CMakeLists.txt index 98b2e63246..d07e6a5245 100644 --- a/Modules/ContourModel/CMakeLists.txt +++ b/Modules/ContourModel/CMakeLists.txt @@ -1,8 +1,8 @@ -MITK_CREATE_MODULE( +mitk_create_module( INCLUDE_DIRS Algorithms DataManagement IO Rendering DEPENDS MitkCore MitkSceneSerializationBase MitkLegacyGL MitkAnnotation MitkMultilabel - PACKAGE_DEPENDS PRIVATE ITK|ITKReview VTK|RenderingContext2D+RenderingContextOpenGL2 + PACKAGE_DEPENDS PRIVATE VTK|RenderingContext2D+RenderingContextOpenGL2 # AUTOLOAD_WITH MitkCore TODO: Create IO Submodule and autoload that one instead. ) add_subdirectory(Testing) diff --git a/Modules/ContourModel/IO/mitkContourModelReader.cpp b/Modules/ContourModel/IO/mitkContourModelReader.cpp index fa0ead2c5f..1b25342e91 100644 --- a/Modules/ContourModel/IO/mitkContourModelReader.cpp +++ b/Modules/ContourModel/IO/mitkContourModelReader.cpp @@ -1,157 +1,173 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelReader.h" #include #include +#include #include #include +#include + +namespace +{ + // Previous versions of the ContourModelSetWriter produced flawed + // XML files with multiple XML declarations. + std::string RemoveErroneousXMLDeclarations(const std::string& filename) + { + std::ifstream file(filename); + file.seekg(0, std::ios_base::end); + auto size = file.tellg(); + std::string string(size, '\0'); + file.seekg(0); + file.read(&string[0], size); + file.close(); + std::regex regex("><\\?xml.+\\?>"); + return std::regex_replace(string, regex, ">"); + } +} mitk::ContourModelReader::ContourModelReader(const mitk::ContourModelReader &other) : mitk::AbstractFileReader(other) { } mitk::ContourModelReader::ContourModelReader() : AbstractFileReader() { std::string category = "Contour File"; mitk::CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("cnt"); this->SetDescription(category); this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::ContourModelReader::~ContourModelReader() { } std::vector> mitk::ContourModelReader::DoRead() { std::vector> result; std::string location = GetInputLocation(); // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); try { - TiXmlDocument doc(location.c_str()); - bool loadOkay = doc.LoadFile(); - if (loadOkay) + auto string = RemoveErroneousXMLDeclarations(location); + + tinyxml2::XMLDocument doc; + if (tinyxml2::XML_SUCCESS == doc.Parse(string.c_str())) { - TiXmlHandle docHandle(&doc); + tinyxml2::XMLHandle docHandle(&doc); /*++++ handle n contourModels within data tags ++++*/ - for (TiXmlElement *currentContourElement = docHandle.FirstChildElement("contourModel").ToElement(); + for (auto *currentContourElement = docHandle.FirstChildElement("contourModel").ToElement(); currentContourElement != nullptr; currentContourElement = currentContourElement->NextSiblingElement()) { mitk::ContourModel::Pointer newContourModel = mitk::ContourModel::New(); if (currentContourElement->FirstChildElement("data")->FirstChildElement("timestep") != nullptr) { - // handle geometry information - // TiXmlElement* currentGeometryInfo = - // currentContourElement->FirstChildElement("head")->FirstChildElement("geometryInformation")->ToElement(); - ///////////// NOT SUPPORTED YET //////////////// - /*++++ handle n timesteps within timestep tags ++++*/ - for (TiXmlElement *currentTimeSeries = + for (auto *currentTimeSeries = currentContourElement->FirstChildElement("data")->FirstChildElement("timestep")->ToElement(); currentTimeSeries != nullptr; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); currentTimeStep = atoi(currentTimeSeries->Attribute("n")); this->ReadPoints(newContourModel, currentTimeSeries, currentTimeStep); int isClosed; currentTimeSeries->QueryIntAttribute("isClosed", &isClosed); if (isClosed) { newContourModel->Close(currentTimeStep); } } /*++++ END handle n timesteps within timestep tags ++++*/ } else { // this should not happen MITK_WARN << "wrong file format!"; // newContourModel = this->ReadPoint(newContourModel, currentContourElement, 0); } newContourModel->UpdateOutputInformation(); result.push_back(dynamic_cast(newContourModel.GetPointer())); } /*++++ END handle n contourModels within data tags ++++*/ } else { MITK_WARN << "XML parser error!"; } } catch (...) { MITK_ERROR << "Cannot read contourModel."; } return result; } mitk::ContourModelReader *mitk::ContourModelReader::Clone() const { return new ContourModelReader(*this); } void mitk::ContourModelReader::ReadPoints(mitk::ContourModel::Pointer newContourModel, - TiXmlElement *currentTimeSeries, + const tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep) { // check if the timesteps in contourModel have to be expanded if (currentTimeStep != newContourModel->GetTimeSteps()) { newContourModel->Expand(currentTimeStep + 1); } // read all points within controlPoints tag if (currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != nullptr) { - for (TiXmlElement *currentPoint = + for (auto *currentPoint = currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement(); currentPoint != nullptr; currentPoint = currentPoint->NextSiblingElement()) { double x(0.0); double y(0.0); double z(0.0); x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); int isActivePoint; currentPoint->QueryIntAttribute("isActive", &isActivePoint); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newContourModel->AddVertex(point, isActivePoint, currentTimeStep); } } else { // nothing to read } } diff --git a/Modules/ContourModel/IO/mitkContourModelReader.h b/Modules/ContourModel/IO/mitkContourModelReader.h index bbeae0a7ec..f91298ae2c 100644 --- a/Modules/ContourModel/IO/mitkContourModelReader.h +++ b/Modules/ContourModel/IO/mitkContourModelReader.h @@ -1,56 +1,60 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_CONTOURMODEL_READER__H_ #define _MITK_CONTOURMODEL_READER__H_ // MITK #include #include #include #include #include #include -#include #include +namespace tinyxml2 +{ + class XMLElement; +} + namespace mitk { /** * @brief * @ingroup MitkContourModelModule */ class ContourModelReader : public mitk::AbstractFileReader { public: ContourModelReader(const ContourModelReader &other); ContourModelReader(); ~ContourModelReader() override; using AbstractFileReader::Read; protected: virtual void ReadPoints(mitk::ContourModel::Pointer newContourModel, - TiXmlElement *currentTimeSeries, + const tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep); std::vector> DoRead() override; private: ContourModelReader *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } #endif diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.h b/Modules/ContourModel/IO/mitkContourModelSetReader.h index 91e24180a1..3472efff46 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetReader.h +++ b/Modules/ContourModel/IO/mitkContourModelSetReader.h @@ -1,54 +1,53 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_ContourModelSetReader__H_ #define _MITK_ContourModelSetReader__H_ // MITK #include #include #include #include #include #include #include -#include #include namespace mitk { /** * @brief * @ingroup MitkContourModelModule */ class ContourModelSetReader : public mitk::AbstractFileReader { public: ContourModelSetReader(const ContourModelSetReader &other); ContourModelSetReader(); ~ContourModelSetReader() override; using AbstractFileReader::Read; protected: std::vector> DoRead() override; private: ContourModelSetReader *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } #endif diff --git a/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp b/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp index c437dd022b..deb595a399 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSetWriter.cpp @@ -1,82 +1,85 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelSetWriter.h" #include "mitkContourModelWriter.h" #include #include #include mitk::ContourModelSetWriter::ContourModelSetWriter() : AbstractFileWriter(ContourModelSet::GetStaticNameOfClass()) { std::string category = "ContourModelSet File"; mitk::CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("cnt_set"); this->SetDescription(category); this->SetMimeType(customMimeType); RegisterService(); } mitk::ContourModelSetWriter::ContourModelSetWriter(const mitk::ContourModelSetWriter &other) : AbstractFileWriter(other) { } mitk::ContourModelSetWriter::~ContourModelSetWriter() { } void mitk::ContourModelSetWriter::Write() { std::ostream *out; std::ofstream outStream; if (this->GetOutputStream()) { out = this->GetOutputStream(); } else { outStream.open(this->GetOutputLocation().c_str()); out = &outStream; } if (!out->good()) { mitkThrow() << "Stream not good."; } + *out << "\n"; + // Use regular ContourModel writer to write each contour of the set to a single file. // Just use a different file extension .cnt_set - mitk::ContourModelWriter writer; + bool writeXMLHeader = false; + mitk::ContourModelWriter writer(writeXMLHeader); mitk::ContourModelSet::ConstPointer contourModelSet = dynamic_cast(this->GetInput()); // // for each contour object set input of writer // for (int i = 0; i < contourModelSet->GetSize(); ++i) { const mitk::ContourModel *contour = contourModelSet->GetContourModelAt(i); writer.SetInput(contour); writer.SetOutputStream(this->GetOutputLocation(), out); writer.Write(); } } mitk::ContourModelSetWriter *mitk::ContourModelSetWriter::Clone() const { return new ContourModelSetWriter(*this); } diff --git a/Modules/ContourModel/IO/mitkContourModelWriter.cpp b/Modules/ContourModel/IO/mitkContourModelWriter.cpp index f41a1d83f4..8e7710a626 100644 --- a/Modules/ContourModel/IO/mitkContourModelWriter.cpp +++ b/Modules/ContourModel/IO/mitkContourModelWriter.cpp @@ -1,335 +1,335 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelWriter.h" #include "mitkIOMimeTypes.h" #include "mitkTimeGeometry.h" #include #include #include /* * The xml file will look like: * * * * * * * * * * * * * * * * * * * */ // // Initialization of the xml tags. // const char *mitk::ContourModelWriter::XML_CONTOURMODEL = "contourModel"; const char *mitk::ContourModelWriter::XML_HEAD = "head"; const char *mitk::ContourModelWriter::XML_GEOMETRY_INFO = "geometryInfo"; const char *mitk::ContourModelWriter::XML_DATA = "data"; const char *mitk::ContourModelWriter::XML_TIME_STEP = "timestep"; const char *mitk::ContourModelWriter::XML_CONTROL_POINTS = "controlPoints"; const char *mitk::ContourModelWriter::XML_POINT = "point"; const char *mitk::ContourModelWriter::XML_X = "x"; const char *mitk::ContourModelWriter::XML_Y = "y"; const char *mitk::ContourModelWriter::XML_Z = "z"; -mitk::ContourModelWriter::ContourModelWriter() - : AbstractFileWriter(ContourModel::GetStaticNameOfClass()), m_IndentDepth(0), m_Indent(2) +mitk::ContourModelWriter::ContourModelWriter(bool writeXMLHeader) + : AbstractFileWriter(ContourModel::GetStaticNameOfClass()), m_WriteXMLHeader(writeXMLHeader), m_IndentDepth(0), m_Indent(2) { std::string category = "Contour File"; mitk::CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("cnt"); this->SetDescription(category); this->SetMimeType(customMimeType); RegisterService(); } mitk::ContourModelWriter::ContourModelWriter(const mitk::ContourModelWriter &other) : AbstractFileWriter(other), m_IndentDepth(other.m_IndentDepth), m_Indent(other.m_Indent) { } mitk::ContourModelWriter::~ContourModelWriter() { } void mitk::ContourModelWriter::Write() { std::ostream *out; std::ofstream outStream; if (this->GetOutputStream()) { out = this->GetOutputStream(); } else { outStream.open(this->GetOutputLocation().c_str()); out = &outStream; } if (!out->good()) { mitkThrow() << "Stream not good."; } std::locale previousLocale(out->getloc()); - std::locale I("C"); - out->imbue(I); + out->imbue(std::locale::classic()); /*+++++++++++ Here the actual xml writing begins +++++++++*/ /*++++ ++++*/ - WriteXMLHeader(*out); + if (m_WriteXMLHeader) + WriteXMLHeader(*out); // // for each input object write its xml representation to // the stream // mitk::ContourModel::ConstPointer contourModel = dynamic_cast(this->GetInput()); assert(contourModel.IsNotNull()); WriteXML(contourModel.GetPointer(), *out); out->imbue(previousLocale); if (!out->good()) // some error during output { throw std::ios_base::failure("Some error during contour writing."); } } mitk::ContourModelWriter *mitk::ContourModelWriter::Clone() const { return new ContourModelWriter(*this); } void mitk::ContourModelWriter::WriteXML(const mitk::ContourModel *contourModel, std::ostream &out) { /*++++ ++++*/ WriteStartElement(XML_CONTOURMODEL, out); /*++++ ++++*/ WriteStartElement(XML_HEAD, out); /*++++ ++++*/ WriteStartElement(XML_GEOMETRY_INFO, out); WriteGeometryInformation(contourModel->GetTimeGeometry(), out); /*++++ ++++*/ WriteEndElement(XML_GEOMETRY_INFO, out); /*++++ ++++*/ WriteEndElement(XML_HEAD, out); /*++++ ++++*/ WriteStartElement(XML_DATA, out); unsigned int timecount = contourModel->GetTimeSteps(); for (unsigned int i = 0; i < timecount; i++) { /*++++ ++++*/ std::vector at; at.push_back("n"); std::vector val; val.push_back(ConvertToString(i)); at.push_back("isClosed"); val.push_back(ConvertToString(contourModel->IsClosed())); WriteStartElementWithAttribut(XML_TIME_STEP, at, val, out); /*++++ ++++*/ WriteStartElement(XML_CONTROL_POINTS, out); auto it = contourModel->IteratorBegin(); auto end = contourModel->IteratorEnd(); while (it != end) { mitk::ContourModel::VertexType *v = *it; /*++++ ++++*/ std::vector attr; attr.push_back("IsControlPoint"); std::vector value; value.push_back(ConvertToString(v->IsControlPoint)); WriteStartElementWithAttribut(XML_POINT, attr, value, out); /*++++ ++++*/ WriteStartElement(XML_X, out); WriteCharacterData(ConvertToString(v->Coordinates[0]).c_str(), out); /*++++ ++++*/ WriteEndElement(XML_X, out, false); /*++++ ++++*/ WriteStartElement(XML_Y, out); WriteCharacterData(ConvertToString(v->Coordinates[1]).c_str(), out); /*++++ ++++*/ WriteEndElement(XML_Y, out, false); /*++++ ++++*/ WriteStartElement(XML_Z, out); WriteCharacterData(ConvertToString(v->Coordinates[2]).c_str(), out); /*++++ ++++*/ WriteEndElement(XML_Z, out, false); /*++++ ++++*/ WriteEndElement(XML_POINT, out); it++; } /*++++ ++++*/ WriteEndElement(XML_CONTROL_POINTS, out); /*++++ ++++*/ WriteEndElement(XML_TIME_STEP, out); } /*++++ ++++*/ WriteEndElement(XML_DATA, out); /*++++ ++++*/ WriteEndElement(XML_CONTOURMODEL, out); } void mitk::ContourModelWriter::WriteGeometryInformation(const mitk::TimeGeometry * /*geometry*/, std::ostream &out) { WriteCharacterData("", out); } template std::string mitk::ContourModelWriter::ConvertToString(T value) { std::ostringstream o; std::locale I("C"); o.imbue(I); if (o << value) { return o.str(); } else return "conversion error"; } void mitk::ContourModelWriter::WriteXMLHeader(std::ostream &file) { file << ""; } void mitk::ContourModelWriter::WriteStartElement(const char *const tag, std::ostream &file) { file << std::endl; WriteIndent(file); file << '<' << tag << '>'; m_IndentDepth++; } void mitk::ContourModelWriter::WriteStartElementWithAttribut(const char *const tag, std::vector attributes, std::vector values, std::ostream &file) { file << std::endl; WriteIndent(file); file << '<' << tag; unsigned int attributesSize = attributes.size(); unsigned int valuesSize = values.size(); if (attributesSize == valuesSize) { auto attributesIt = attributes.begin(); auto end = attributes.end(); auto valuesIt = values.begin(); while (attributesIt != end) { file << ' '; WriteCharacterData(*attributesIt, file); file << '=' << '"'; WriteCharacterData(*valuesIt, file); file << '"'; attributesIt++; valuesIt++; } } file << '>'; m_IndentDepth++; } void mitk::ContourModelWriter::WriteEndElement(const char *const tag, std::ostream &file, const bool &indent) { m_IndentDepth--; if (indent) { file << std::endl; WriteIndent(file); } file << '<' << '/' << tag << '>'; } void mitk::ContourModelWriter::WriteCharacterData(const char *const data, std::ostream &file) { file << data; } void mitk::ContourModelWriter::WriteStartElement(std::string &tag, std::ostream &file) { WriteStartElement(tag.c_str(), file); } void mitk::ContourModelWriter::WriteEndElement(std::string &tag, std::ostream &file, const bool &indent) { WriteEndElement(tag.c_str(), file, indent); } void mitk::ContourModelWriter::WriteCharacterData(std::string &data, std::ostream &file) { WriteCharacterData(data.c_str(), file); } void mitk::ContourModelWriter::WriteIndent(std::ostream &file) { std::string spaces(m_IndentDepth * m_Indent, ' '); file << spaces.c_str(); } diff --git a/Modules/ContourModel/IO/mitkContourModelWriter.h b/Modules/ContourModel/IO/mitkContourModelWriter.h index e338c4eee8..3a1b587533 100644 --- a/Modules/ContourModel/IO/mitkContourModelWriter.h +++ b/Modules/ContourModel/IO/mitkContourModelWriter.h @@ -1,169 +1,171 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_CONTOURMODEL_WRITER__H_ #define _MITK_CONTOURMODEL_WRITER__H_ #include #include // DEPRECATED #include namespace mitk { /** * @brief XML-based writer for mitk::ContourModels * * XML-based writer for mitk::ContourModels. Multiple ContourModels can be written in * a single XML file by simply setting multiple inputs to the filter. * * The xml file will look like: * * * * * * * * * * * * * * * * * * * * * @ingroup MitkContourModelModule */ class TimeSlicedGeometry; class ContourModelWriter : public mitk::AbstractFileWriter { public: - ContourModelWriter(); + explicit ContourModelWriter(bool writeXMLHeader = true); ~ContourModelWriter() override; using AbstractFileWriter::Write; void Write() override; protected: ContourModelWriter(const ContourModelWriter &other); mitk::ContourModelWriter *Clone() const override; /** * Converts an arbitrary type to a string. The type has to * support the << operator. This works fine at least for integral * data types as float, int, long etc. * @param value the value to convert * @returns the string representation of value */ template std::string ConvertToString(T value); /** * Writes an XML representation of the given point set to * an outstream. The XML-Header an root node is not included! * @param contourModel the point set to be converted to xml * @param out the stream to write to. */ void WriteXML(const mitk::ContourModel *contourModel, std::ostream &out); /** * Writes the geometry information of the TimeGeometry to an outstream. * The root tag is not included. * @param geometry the TimeGeometry of the contour. * @param out the stream to write to. */ void WriteGeometryInformation(const mitk::TimeGeometry *geometry, std::ostream &out); /** * Writes the geometry information of the TimeGeometry to an outstream. * The root tag is not included. * @param geometry the TimeGeometry of the contour. * @param out the stream to write to. * * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void WriteGeometryInformation(const mitk::TimeSlicedGeometry *geometry, std::ostream &out)); /** * Writes an standard xml header to the given stream. * @param file the stream in which the header is written. */ void WriteXMLHeader(std::ostream &file); /** Write a start element tag */ void WriteStartElement(const char *const tag, std::ostream &file); void WriteStartElementWithAttribut(const char *const tag, std::vector attributes, std::vector values, std::ostream &file); /** * Write an end element tag * End-Elements following character data should pass indent = false. */ void WriteEndElement(const char *const tag, std::ostream &file, const bool &indent = true); /** Write character data inside a tag. */ void WriteCharacterData(const char *const data, std::ostream &file); /** Write a start element tag */ void WriteStartElement(std::string &tag, std::ostream &file); /** Write an end element tag */ void WriteEndElement(std::string &tag, std::ostream &file, const bool &indent = true); /** Write character data inside a tag. */ void WriteCharacterData(std::string &data, std::ostream &file); /** Writes empty spaces to the stream according to m_IndentDepth and m_Indent */ void WriteIndent(std::ostream &file); + bool m_WriteXMLHeader; + unsigned int m_IndentDepth; unsigned int m_Indent; public: static const char *XML_CONTOURMODEL; static const char *XML_HEAD; static const char *XML_GEOMETRY_INFO; static const char *XML_DATA; static const char *XML_TIME_STEP; static const char *XML_CONTROL_POINTS; static const char *XML_POINT; static const char *XML_X; static const char *XML_Y; static const char *XML_Z; }; } #endif diff --git a/Modules/Core/CMakeLists.txt b/Modules/Core/CMakeLists.txt index 40e19fd8b4..b38af61df6 100644 --- a/Modules/Core/CMakeLists.txt +++ b/Modules/Core/CMakeLists.txt @@ -1,65 +1,77 @@ - set(TOOL_CPPS "") # temporary suppress warnings in the following files until image accessors are fully integrated. set_source_files_properties( src/DataManagement/mitkImage.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) set_source_files_properties( src/Controllers/mitkSliceNavigationController.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) -MITK_CREATE_MODULE( +#if(MSVC) +# set(optional_private_package_depends psapi) +#endif() + +mitk_create_module( INCLUDE_DIRS - PUBLIC ${MITK_BINARY_DIR} - PRIVATE src/Algorithms src/Controllers src/DataManagement src/Interactions src/IO src/Rendering ${OPENGL_INCLUDE_DIR} - DEPENDS PUBLIC mbilog CppMicroServices + PUBLIC + ${MITK_BINARY_DIR} + PRIVATE + src/Algorithms + src/Controllers + src/DataManagement + src/Interactions + src/IO + src/Rendering + DEPENDS + PUBLIC + mbilog + CppMicroServices PACKAGE_DEPENDS - PRIVATE tinyxml OpenGL - PUBLIC ITK|ITKTransform+ITKImageGrid+ITKImageFeature+ITKIOImageBase+ITKIOHDF5+ITKIOLSM+ITKIOMRC+ITKIOBioRad+ITKIOGE+ITKIOStimulate+ITKIOBruker+ITKIOMINC - # We privately use/link all ITK modules in order to support all IO, Transform, etc. - # factories from ITK which are registered "automatically" via a factory manager. - PRIVATE ITK - PUBLIC VTK|FiltersTexture+FiltersParallel+ImagingStencil+ImagingMath+InteractionStyle+RenderingOpenGL2+RenderingVolumeOpenGL2+RenderingFreeType+RenderingLabel+InteractionWidgets+IOGeometry+IOXML - PUBLIC Boost|boost + PUBLIC + Boost + ITK|IOImageBase+SpatialObjects+Statistics + #ITK|Statistics+Transform + VTK|FiltersTexture+FiltersParallel+ImagingStencil+ImagingMath+InteractionStyle+RenderingOpenGL2+RenderingVolumeOpenGL2+RenderingFreeType+RenderingLabel+InteractionWidgets+IOGeometry+IOXML + PRIVATE + ITK|IOBioRad+IOBMP+IOBruker+IOCSV+IOGDCM+IOGE+IOGIPL+IOHDF5+IOIPL+IOJPEG+IOLSM+IOMesh+IOMeta+IOMINC+IOMRC+IONIFTI+IONRRD+IOPNG+IOSiemens+IOSpatialObjects+IOStimulate+IOTIFF+IOTransformBase+IOTransformHDF5+IOTransformInsightLegacy+IOTransformMatlab+IOVTK+IOXML + tinyxml2 + ${optional_private_package_depends} # Do not automatically create CppMicroServices initialization code. - # Because the VTK 6 "auto-init" functionality injects file-local static + # Because the VTK "auto-init" functionality injects file-local static # initialization code in every cpp file which includes a VTK header, # static initialization order becomes an issue again. For the Mitk # core library, we need to ensure that the VTK static initialization stuff # happens before the CppMicroServices initialization, since the latter # might already use VTK code which needs to access VTK object factories. # Hence, CppMicroServices initialization code is placed manually within # the mitkCoreActivator.cpp file. NO_INIT ) if(NOT TARGET ${MODULE_TARGET}) message(SEND_ERROR "Core target ${MODULE_TARGET} does not exist") endif() + function(_itk_create_factory_register_manager) # In MITK_ITK_Config.cmake, we do *not* include ITK_USE_FILE, which # prevents multiple registrations/unregistrations of ITK IO factories # during library loading/unloading (of MITK libraries). However, we need # "one" place where the IO factories are registered at # least once. This could be the application executable, but every executable would # need to take care of that itself. Instead, we allow the auto registration in the # Mitk Core library. set(NO_DIRECTORY_SCOPED_ITK_COMPILE_DEFINITION 1) find_package(ITK) include(${ITK_USE_FILE}) if(NOT ITK_NO_IO_FACTORY_REGISTER_MANAGER) # We manually add the define which will be of target scope. MITK # patches ITK_USE_FILE to remove the directory scoped compile # definition since it would be propagated to other targets in the # same directory scope but these targets might want to *not* # use the ITK factory manager stuff. target_compile_definitions(${MODULE_TARGET} PRIVATE ITK_IO_FACTORY_REGISTER_MANAGER) endif() endfunction() _itk_create_factory_register_manager() -if(MSVC_IDE OR MSVC_VERSION) - target_link_libraries(${MODULE_TARGET} PRIVATE psapi.lib) -endif() - if(BUILD_TESTING) add_subdirectory(TestingHelper) add_subdirectory(test) endif() diff --git a/Modules/Core/TestingHelper/CMakeLists.txt b/Modules/Core/TestingHelper/CMakeLists.txt index c1d32c6cfd..ba38e5b698 100644 --- a/Modules/Core/TestingHelper/CMakeLists.txt +++ b/Modules/Core/TestingHelper/CMakeLists.txt @@ -1,7 +1,6 @@ mitk_create_module( DEPENDS PUBLIC MitkCore PACKAGE_DEPENDS - PUBLIC CppUnit - PRIVATE VTK|IOImage+TestingRendering tinyxml OpenGL + PUBLIC CppUnit tinyxml2 + PRIVATE VTK|IOImage+TestingRendering ) - diff --git a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp index dea87c3ef7..92578ca3cf 100644 --- a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp @@ -1,432 +1,429 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include #include #include #include #include // VTK #include #include // us #include -#include +#include mitk::InteractionTestHelper::InteractionTestHelper(const std::string &interactionXmlFilePath) : m_InteractionFilePath(interactionXmlFilePath) { this->Initialize(interactionXmlFilePath); } void mitk::InteractionTestHelper::Initialize(const std::string &interactionXmlFilePath) { - // TiXmlDocument document(interactionXmlPath.c_str()); - TiXmlDocument document(interactionXmlFilePath); - bool loadOkay = document.LoadFile(); - if (loadOkay) + tinyxml2::XMLDocument document; + if (tinyxml2::XML_SUCCESS == document.LoadFile(interactionXmlFilePath.c_str())) { // get RenderingManager instance auto rm = mitk::RenderingManager::GetInstance(); // create data storage m_DataStorage = mitk::StandaloneDataStorage::New(); // for each renderer found create a render window and configure - for (TiXmlElement *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions()) - ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot()) - ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer()); + for (auto *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions().c_str()) + ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot().c_str()) + ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer().c_str()); element != nullptr; - element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer())) + element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer().c_str())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get view direction mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Axial; - if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection().c_str()) != nullptr) { int viewDirectionNum = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection().c_str())); viewDirection = static_cast(viewDirectionNum); } // get mapper slot id mitk::BaseRenderer::MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; - if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str()) != nullptr) { int mapperIDNum = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str())); mapperID = static_cast(mapperIDNum); } // Get Size of Render Windows int size[3]; size[0] = size[1] = size[2] = 0; - if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX().c_str()) != nullptr) { - size[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX())->c_str()); + size[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX().c_str())); } - if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY().c_str()) != nullptr) { - size[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY())->c_str()); + size[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY().c_str())); } - if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ().c_str()) != nullptr) { - size[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ())->c_str()); + size[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ().c_str())); } // create renderWindow, renderer and dispatcher auto rw = RenderWindow::New(nullptr, rendererName); // VtkRenderWindow is created within constructor if nullptr if (size[0] != 0 && size[1] != 0) { rw->SetSize(size[0], size[1]); rw->GetRenderer()->Resize(size[0], size[1]); } // set storage of renderer rw->GetRenderer()->SetDataStorage(m_DataStorage); // set view direction to axial rw->GetSliceNavigationController()->SetDefaultViewDirection(viewDirection); // set renderer to render 2D rw->GetRenderer()->SetMapperID(mapperID); rw->GetRenderer()->PrepareRender(); // Some more magic for the 3D render window case: // Camera view direction, position and focal point if (mapperID == mitk::BaseRenderer::Standard3D) { - if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str())); cameraFocalPoint[1] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY().c_str())); cameraFocalPoint[2] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } - if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str()) != nullptr) { double cameraPosition[3]; - cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX())->c_str()); - cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY())->c_str()); - cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ())->c_str()); + cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str())); + cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY().c_str())); + cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } - if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str()) != nullptr) { double viewUp[3]; - viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX())->c_str()); - viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY())->c_str()); - viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ())->c_str()); + viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str())); + viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY().c_str())); + viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ().c_str())); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } } rw->GetVtkRenderWindow()->Render(); rw->GetVtkRenderWindow()->WaitForCompletion(); // connect SliceNavigationControllers to timestep changed event of TimeNavigationController rw->GetSliceNavigationController()->ConnectGeometryTimeEvent(rm->GetTimeNavigationController(), false); rm->GetTimeNavigationController()->ConnectGeometryTimeEvent(rw->GetSliceNavigationController(), false); // add to list of kown render windows m_RenderWindowList.push_back(rw); } // TODO: check the following lines taken from QmitkStdMultiWidget and adapt them to be executed in our code here. // mitkWidget1->GetSliceNavigationController() // ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); //########### register display interactor to handle scroll events ################## // use MouseModeSwitcher to ensure that the statemachine of DisplayInteractor is loaded correctly m_MouseModeSwitcher = mitk::MouseModeSwitcher::New(); } else { mitkThrow() << "Can not load interaction xml file <" << m_InteractionFilePath << ">"; } // WARNING assumes a 3D window exists !!!! this->AddDisplayPlaneSubTree(); } mitk::InteractionTestHelper::~InteractionTestHelper() { mitk::RenderingManager *rm = mitk::RenderingManager::GetInstance(); // unregister renderers auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { rm->GetTimeNavigationController()->Disconnect((*it)->GetSliceNavigationController()); (*it)->GetSliceNavigationController()->Disconnect(rm->GetTimeNavigationController()); mitk::BaseRenderer::RemoveInstance((*it)->GetVtkRenderWindow()); } rm->RemoveAllObservers(); } mitk::DataStorage::Pointer mitk::InteractionTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::InteractionTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); this->Set3dCameraSettings(); } void mitk::InteractionTestHelper::PlaybackInteraction() { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); // load events if not loaded yet if (m_Events.empty()) this->LoadInteraction(); auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { (*it)->GetRenderer()->PrepareRender(); (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); it = m_RenderWindowList.begin(); for (; it != end; ++it) { (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } // mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); // playback all events in queue for (unsigned long i = 0; i < m_Events.size(); ++i) { // let dispatcher of sending renderer process the event m_Events.at(i)->GetSender()->GetDispatcher()->ProcessEvent(m_Events.at(i)); } if (false) { it--; (*it)->GetVtkRenderWindow()->GetInteractor()->Start(); } } void mitk::InteractionTestHelper::LoadInteraction() { // load interaction pattern from xml file std::ifstream xmlStream(m_InteractionFilePath.c_str()); mitk::XML2EventParser parser(xmlStream); m_Events = parser.GetInteractions(); xmlStream.close(); // Avoid VTK warning: Trying to delete object with non-zero reference count. parser.SetReferenceCount(0); } void mitk::InteractionTestHelper::SetTimeStep(int newTimeStep) { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); bool timeStepIsvalid = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetCreatedWorldGeometry()->IsValidTimeStep( newTimeStep); if (timeStepIsvalid) { mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->SetPos(newTimeStep); } } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByName(const std::string &name) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (name.compare((*it)->GetRenderer()->GetName()) == 0) return (*it).GetPointer(); } return nullptr; } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByDefaultViewDirection( mitk::SliceNavigationController::ViewDirection viewDirection) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (viewDirection == (*it)->GetSliceNavigationController()->GetDefaultViewDirection()) return (*it).GetPointer(); } return nullptr; } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindow(unsigned int index) { if (index < m_RenderWindowList.size()) { return m_RenderWindowList.at(index).GetPointer(); } else { return nullptr; } } void mitk::InteractionTestHelper::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; mitk::IntProperty::Pointer layer = mitk::IntProperty::New(1000); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetProperty("name", mitk::StringProperty::New("Widgets")); node->SetProperty("helper object", mitk::BoolProperty::New(true)); m_DataStorage->Add(node); for (auto it : m_RenderWindowList) { if (it->GetRenderer()->GetMapperID() == BaseRenderer::Standard3D) continue; // ... of widget 1 mitk::DataNode::Pointer planeNode1 = (mitk::BaseRenderer::GetInstance(it->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); planeNode1->SetProperty("visible", mitk::BoolProperty::New(true)); planeNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); planeNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); planeNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); planeNode1->SetProperty("layer", layer); planeNode1->SetColor(1.0, 0.0, 0.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); planeNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_DataStorage->Add(planeNode1, node); } } void mitk::InteractionTestHelper::Set3dCameraSettings() { - TiXmlDocument document(m_InteractionFilePath); - bool loadOkay = document.LoadFile(); - if (loadOkay) + tinyxml2::XMLDocument document; + if (tinyxml2::XML_SUCCESS == document.LoadFile(m_InteractionFilePath.c_str())) { // for each renderer found create a render window and configure - for (TiXmlElement *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions()) - ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot()) - ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer()); + for (auto *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions().c_str()) + ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot().c_str()) + ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer().c_str()); element != nullptr; - element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer())) + element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer().c_str())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get mapper slot id mitk::BaseRenderer::MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; - if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str()) != nullptr) { int mapperIDNum = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID().c_str())); mapperID = static_cast(mapperIDNum); } if (mapperID == mitk::BaseRenderer::Standard3D) { RenderWindow *namedRenderer = nullptr; for (auto it : m_RenderWindowList) { if (strcmp(it->GetRenderer()->GetName(), rendererName) == 0) { namedRenderer = it.GetPointer(); break; } } if (namedRenderer == nullptr) { MITK_ERROR << "No match for render window was found."; return; } namedRenderer->GetRenderer()->PrepareRender(); - if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX().c_str())); cameraFocalPoint[1] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY().c_str())); cameraFocalPoint[2] = - std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ())->c_str()); + std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } - if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str()) != nullptr) { double cameraPosition[3]; - cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX())->c_str()); - cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY())->c_str()); - cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ())->c_str()); + cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX().c_str())); + cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY().c_str())); + cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } - if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX()) != nullptr) + if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str()) != nullptr) { double viewUp[3]; - viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX())->c_str()); - viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY())->c_str()); - viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ())->c_str()); + viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX().c_str())); + viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY().c_str())); + viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ().c_str())); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } namedRenderer->GetVtkRenderWindow()->Render(); } } } } diff --git a/Modules/Core/include/mitkGeometryDataReaderService.h b/Modules/Core/include/mitkGeometryDataReaderService.h index 1c7f8e23cb..aa95947ed4 100644 --- a/Modules/Core/include/mitkGeometryDataReaderService.h +++ b/Modules/Core/include/mitkGeometryDataReaderService.h @@ -1,61 +1,59 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGeometryDataReaderService_h #define mitkGeometryDataReaderService_h // MITK #include #include -class TiXmlElement; - namespace mitk { /** * @internal * * @brief reads XML representations of mitk::GeometryData from a file/stream. * * To be used via IOUtil. * * Reader for XML files containing one or multiple XML represenations of * mitk::GeometryData. If multiple mitk::GeometryData objects are stored in one file, * these are assigned to multiple BaseData objects. * * @sa Geometry3DToXML * * @ingroup IO */ class GeometryDataReaderService : public AbstractFileReader { public: GeometryDataReaderService(); ~GeometryDataReaderService() override; using AbstractFileReader::Read; /** * @brief Provides the MIME type for reader and writer. */ static CustomMimeType GEOMETRY_DATA_MIMETYPE(); protected: std::vector> DoRead() override; private: GeometryDataReaderService(const GeometryDataReaderService &other); GeometryDataReaderService *Clone() const override; }; } #endif diff --git a/Modules/Core/include/mitkGeometryDataWriterService.h b/Modules/Core/include/mitkGeometryDataWriterService.h index 6544cd8f4e..6de0ddabd4 100644 --- a/Modules/Core/include/mitkGeometryDataWriterService.h +++ b/Modules/Core/include/mitkGeometryDataWriterService.h @@ -1,55 +1,52 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGeometryDataWriterService_h #define mitkGeometryDataWriterService_h #include #include -// forward -class TiXmlNode; - namespace mitk { // forward class Geometry3D; /** * @internal * * @brief XML-based writer for mitk::GeometryData * * XML-based writer for mitk::GeometryData. Multiple GeometryData instances * can be written in a single XML file by simply setting multiple inputs to the filter. * * @sa Geometry3DToXML * * @ingroup IO */ class GeometryDataWriterService : public AbstractFileWriter { public: GeometryDataWriterService(); ~GeometryDataWriterService() override; using AbstractFileWriter::Write; void Write() override; private: GeometryDataWriterService(const GeometryDataWriterService &other); mitk::GeometryDataWriterService *Clone() const override; }; } #endif diff --git a/Modules/Core/include/mitkPlaneOrientationProperty.h b/Modules/Core/include/mitkPlaneOrientationProperty.h index 54798b7f00..3d97490348 100644 --- a/Modules/Core/include/mitkPlaneOrientationProperty.h +++ b/Modules/Core/include/mitkPlaneOrientationProperty.h @@ -1,122 +1,122 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITK_PLANE_DECORATION_PROPERTY__H #define MITK_PLANE_DECORATION_PROPERTY__H #include "mitkEnumerationProperty.h" namespace mitk { #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4522) #endif /** * Property which controls whether 2D line representation of a PlaneGeometry * should have small arrows at both ends to indicate the orientation of * the plane, and whether the arrows should be oriented in the direction of * the plane's normal or against it. * * Valid values of the enumeration property are * - PLANE_DECORATION_NONE (no arrows) * - PLANE_DECORATION_POSITIVE_ORIENTATION (arrows pointing upwards) * - PLANE_DECORATION_NEGATIVE_ORIENTATION (arrows pointing downwards) * * See also mitk::PlaneGeometryDataMapper2D::DrawOrientationArrow() */ class MITKCORE_EXPORT PlaneOrientationProperty : public EnumerationProperty { public: mitkClassMacro(PlaneOrientationProperty, EnumerationProperty); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - mitkNewMacro1Param(PlaneOrientationProperty, const IdType &); + mitkNewMacro1Param(PlaneOrientationProperty, const IdType &); mitkNewMacro1Param(PlaneOrientationProperty, const std::string &); enum { PLANE_DECORATION_NONE, PLANE_DECORATION_POSITIVE_ORIENTATION, PLANE_DECORATION_NEGATIVE_ORIENTATION }; /** * Returns the state of plane decoration. */ virtual int GetPlaneDecoration(); /** * Sets the decoration type to no decoration. */ virtual void SetPlaneDecorationToNone(); /** * Sets the decoration type to arrows in positive plane direction. */ virtual void SetPlaneDecorationToPositiveOrientation(); /** * Sets the decoration type to arrows in negative plane direction. */ virtual void SetPlaneDecorationToNegativeOrientation(); using BaseProperty::operator=; protected: /** * Constructor. Sets the decoration type to none. */ PlaneOrientationProperty(); /** * Constructor. Sets the decoration type to the given value. If it is not * valid, the interpolation is set to none */ PlaneOrientationProperty(const IdType &value); /** * Constructor. Sets the decoration type to the given value. If it is not * valid, the representation is set to none */ PlaneOrientationProperty(const std::string &value); /** * this function is overridden as protected, so that the user may not add * additional invalid types. */ bool AddEnum(const std::string &name, const IdType &id) override; /** * Adds the standard enumeration types with corresponding strings. */ virtual void AddDecorationTypes(); private: // purposely not implemented PlaneOrientationProperty &operator=(const PlaneOrientationProperty &); itk::LightObject::Pointer InternalClone() const override; }; #ifdef _MSC_VER #pragma warning(pop) #endif } // end of namespace mitk #endif diff --git a/Modules/Core/src/IO/mitkGeometry3DToXML.cpp b/Modules/Core/src/IO/mitkGeometry3DToXML.cpp index c611eac6c7..e9ee434cf7 100644 --- a/Modules/Core/src/IO/mitkGeometry3DToXML.cpp +++ b/Modules/Core/src/IO/mitkGeometry3DToXML.cpp @@ -1,236 +1,242 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkGeometry3DToXML.h" #include -#include +#include -TiXmlElement *mitk::Geometry3DToXML::ToXML(const Geometry3D *geom3D) +#include + +tinyxml2::XMLElement *mitk::Geometry3DToXML::ToXML(tinyxml2::XMLDocument& doc, 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"); + auto *geomElem = doc.NewElement("Geometry3D"); + geomElem->SetAttribute("ImageGeometry", isImageGeometry); geomElem->SetAttribute("FrameOfReferenceID", geom3D->GetFrameOfReferenceID()); // coefficients are matrix[row][column]! - auto *matrixElem = new TiXmlElement("IndexToWorld"); + auto *matrixElem = doc.NewElement("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"); + matrixElem->SetAttribute("m_0_0", boost::lexical_cast(matrix[0][0]).c_str()); + matrixElem->SetAttribute("m_0_1", boost::lexical_cast(matrix[0][1]).c_str()); + matrixElem->SetAttribute("m_0_2", boost::lexical_cast(matrix[0][2]).c_str()); + matrixElem->SetAttribute("m_1_0", boost::lexical_cast(matrix[1][0]).c_str()); + matrixElem->SetAttribute("m_1_1", boost::lexical_cast(matrix[1][1]).c_str()); + matrixElem->SetAttribute("m_1_2", boost::lexical_cast(matrix[1][2]).c_str()); + matrixElem->SetAttribute("m_2_0", boost::lexical_cast(matrix[2][0]).c_str()); + matrixElem->SetAttribute("m_2_1", boost::lexical_cast(matrix[2][1]).c_str()); + matrixElem->SetAttribute("m_2_2", boost::lexical_cast(matrix[2][2]).c_str()); + geomElem->InsertEndChild(matrixElem); + + auto *offsetElem = doc.NewElement("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); + offsetElem->SetAttribute("x", boost::lexical_cast(offset[0]).c_str()); + offsetElem->SetAttribute("y", boost::lexical_cast(offset[1]).c_str()); + offsetElem->SetAttribute("z", boost::lexical_cast(offset[2]).c_str()); + geomElem->InsertEndChild(offsetElem); - auto *boundsElem = new TiXmlElement("Bounds"); - auto *boundsMinElem = new TiXmlElement("Min"); + auto *boundsElem = doc.NewElement("Bounds"); + auto *boundsMinElem = doc.NewElement("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"); + boundsMinElem->SetAttribute("x", boost::lexical_cast(bounds[0]).c_str()); + boundsMinElem->SetAttribute("y", boost::lexical_cast(bounds[2]).c_str()); + boundsMinElem->SetAttribute("z", boost::lexical_cast(bounds[4]).c_str()); + boundsElem->InsertEndChild(boundsMinElem); + auto *boundsMaxElem = doc.NewElement("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); + boundsMaxElem->SetAttribute("x", boost::lexical_cast(bounds[1]).c_str()); + boundsMaxElem->SetAttribute("y", boost::lexical_cast(bounds[3]).c_str()); + boundsMaxElem->SetAttribute("z", boost::lexical_cast(bounds[5]).c_str()); + boundsElem->InsertEndChild(boundsMaxElem); + geomElem->InsertEndChild(boundsElem); return geomElem; } -mitk::Geometry3D::Pointer mitk::Geometry3DToXML::FromXML(TiXmlElement *geometryElement) +mitk::Geometry3D::Pointer mitk::Geometry3DToXML::FromXML(const tinyxml2::XMLElement *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)) + if (tinyxml2::XML_SUCCESS != geometryElement->QueryUnsignedAttribute("FrameOfReferenceID", &frameOfReferenceID)) { MITK_WARN << "Missing FrameOfReference for Geometry3D."; } - if (TIXML_SUCCESS != geometryElement->QueryBoolAttribute("ImageGeometry", &isImageGeometry)) + if (tinyxml2::XML_SUCCESS != geometryElement->QueryBoolAttribute("ImageGeometry", &isImageGeometry)) { MITK_WARN << "Missing bool ImageGeometry for Geometry3D."; } // matrix - if (TiXmlElement *matrixElem = geometryElement->FirstChildElement("IndexToWorld")->ToElement()) + if (auto *matrixElem = geometryElement->FirstChildElement("IndexToWorld")) { 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)) + const char* string_value = matrixElem->Attribute(element_namer.str().c_str()); + if (nullptr != string_value) { try { matrix[r][c] = boost::lexical_cast(string_value); } 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()) + if (auto *offsetElem = geometryElement->FirstChildElement("Offset")) { - 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]); + std::array offset_string = { + offsetElem->Attribute("x"), + offsetElem->Attribute("y"), + offsetElem->Attribute("z") + }; - if (!vectorComplete) + if (nullptr == offset_string[0] || nullptr == offset_string[1] || nullptr == offset_string[2]) { 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 ( 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()) + if (auto *boundsElem = geometryElement->FirstChildElement("Bounds")) { - bool vectorsComplete(true); - std::string bounds_string[6]; - if (TiXmlElement *minElem = boundsElem->FirstChildElement("Min")->ToElement()) + bool vectorsComplete; + std::array bounds_string; + if (auto* minElem = boundsElem->FirstChildElement("Min")) { - 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]); + bounds_string[0] = minElem->Attribute("x"); + bounds_string[2] = minElem->Attribute("y"); + bounds_string[4] = minElem->Attribute("z"); + + vectorsComplete = !(nullptr == bounds_string[0] || nullptr == bounds_string[2] || nullptr == bounds_string[4]); } else { vectorsComplete = false; } - if (TiXmlElement *maxElem = boundsElem->FirstChildElement("Max")->ToElement()) + if (auto *maxElem = boundsElem->FirstChildElement("Max")) { - 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]); + bounds_string[1] = maxElem->Attribute("x"); + bounds_string[3] = maxElem->Attribute("y"); + bounds_string[5] = maxElem->Attribute("z"); + + vectorsComplete = !(nullptr == bounds_string[1] || nullptr == bounds_string[3] || nullptr == 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 ( 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/mitkGeometry3DToXML.h b/Modules/Core/src/IO/mitkGeometry3DToXML.h index d0cd9d0f6d..ef3a2454eb 100644 --- a/Modules/Core/src/IO/mitkGeometry3DToXML.h +++ b/Modules/Core/src/IO/mitkGeometry3DToXML.h @@ -1,51 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGeometry3DToXML_h #define mitkGeometry3DToXML_h // MITK #include "mitkGeometry3D.h" -class TiXmlElement; +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; +} namespace mitk { /** * @internal * * @brief Helper for Geometry3D related I/O classes. * * Creates TinyXML elements (blocks) that describe a Geometry3D. * Also offers a method to read such blocks and create a corresponding Geometry3D. * * @sa GeometryDataReaderService, GeometryDataWriterService, PointSetWriterService, PointSetReaderService * * @ingroup IO */ class Geometry3DToXML { public: /** * @brief Serialize given geometry to XML. */ - static TiXmlElement *ToXML(const Geometry3D *geometry); + static tinyxml2::XMLElement *ToXML(tinyxml2::XMLDocument& doc, const Geometry3D *geometry); /** * @brief Create a Geometry3D from XML. * Interprets only the format created by ToXML(). */ - static Geometry3D::Pointer FromXML(TiXmlElement *node); + static Geometry3D::Pointer FromXML(const tinyxml2::XMLElement *node); }; } #endif diff --git a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp index 0b13ffe89c..8731ae70e8 100644 --- a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp +++ b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp @@ -1,112 +1,113 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkGeometryDataReaderService.h" #include "mitkGeometry3DToXML.h" #include "mitkIOMimeTypes.h" #include "mitkProportionalTimeGeometryToXML.h" // STL #include -#include +#include mitk::GeometryDataReaderService::GeometryDataReaderService() : AbstractFileReader(IOMimeTypes::GEOMETRY_DATA_MIMETYPE(), "MITK Geometry Data Reader") { RegisterService(); } mitk::GeometryDataReaderService::~GeometryDataReaderService() { } std::vector> mitk::GeometryDataReaderService::DoRead() { // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); std::vector> result; InputStream stream(this); - TiXmlDocument doc; - stream >> doc; + std::string s(std::istreambuf_iterator{stream.rdbuf()}, std::istreambuf_iterator()); + tinyxml2::XMLDocument doc; + doc.Parse(s.c_str(), s.size()); if (!doc.Error()) { - TiXmlHandle docHandle(&doc); + tinyxml2::XMLHandle docHandle(&doc); - for (TiXmlElement *geomDataElement = docHandle.FirstChildElement("GeometryData").ToElement(); + for (auto *geomDataElement = docHandle.FirstChildElement("GeometryData").ToElement(); geomDataElement != nullptr; geomDataElement = geomDataElement->NextSiblingElement()) { - for (TiXmlElement *currentElement = geomDataElement->FirstChildElement(); currentElement != nullptr; + for (auto *currentElement = geomDataElement->FirstChildElement(); currentElement != nullptr; currentElement = currentElement->NextSiblingElement()) { // different geometries could have been serialized from a GeometryData // object: std::string tagName = currentElement->Value(); if (tagName == "Geometry3D") { Geometry3D::Pointer restoredGeometry = Geometry3DToXML::FromXML(currentElement); if (restoredGeometry.IsNotNull()) { GeometryData::Pointer newGeometryData = GeometryData::New(); newGeometryData->SetGeometry(restoredGeometry); result.push_back(newGeometryData.GetPointer()); } else { MITK_ERROR << "Invalid tag encountered. Skipping."; } } else if (tagName == "ProportionalTimeGeometry") { ProportionalTimeGeometry::Pointer restoredTimeGeometry = ProportionalTimeGeometryToXML::FromXML(currentElement); if (restoredTimeGeometry.IsNotNull()) { GeometryData::Pointer newGeometryData = GeometryData::New(); newGeometryData->SetTimeGeometry(restoredTimeGeometry); result.push_back(newGeometryData.GetPointer()); } else { MITK_ERROR << "Invalid tag encountered. Skipping."; } } } // for child of } // for } else { - mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); + mitkThrow() << doc.ErrorStr(); } if (result.empty()) { mitkThrow() << "Did not read a single GeometryData object from input."; } return result; } mitk::GeometryDataReaderService::GeometryDataReaderService(const mitk::GeometryDataReaderService &other) : mitk::AbstractFileReader(other) { } mitk::GeometryDataReaderService *mitk::GeometryDataReaderService::Clone() const { return new GeometryDataReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkGeometryDataWriterService.cpp b/Modules/Core/src/IO/mitkGeometryDataWriterService.cpp index 1ca99cb8d0..57f02597a9 100644 --- a/Modules/Core/src/IO/mitkGeometryDataWriterService.cpp +++ b/Modules/Core/src/IO/mitkGeometryDataWriterService.cpp @@ -1,91 +1,90 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkGeometryDataWriterService.h" #include "mitkIOMimeTypes.h" #include "mitkProportionalTimeGeometryToXML.h" -#include +#include #include mitk::GeometryDataWriterService::GeometryDataWriterService() : AbstractFileWriter( GeometryData::GetStaticNameOfClass(), IOMimeTypes::GEOMETRY_DATA_MIMETYPE(), "MITK Geometry Data Writer") { RegisterService(); } mitk::GeometryDataWriterService::GeometryDataWriterService(const mitk::GeometryDataWriterService &other) : AbstractFileWriter(other) { } mitk::GeometryDataWriterService::~GeometryDataWriterService() { } void mitk::GeometryDataWriterService::Write() { /* using the stream interface produces files without line breaks or indentation.. But before changing to file interface, need to understand the new I/O classes */ OutputStream out(this); if (!out.good()) { mitkThrow() << "Stream not good."; } // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); // Open XML file using TinyXML, // loop over all inputs, // call appropriate serializing functions - TiXmlDocument doc; + tinyxml2::XMLDocument doc; + doc.InsertEndChild(doc.NewDeclaration()); - auto *decl = new TiXmlDeclaration( - "1.0", "UTF-8", ""); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... - doc.LinkEndChild(decl); - - auto *rootNode = new TiXmlElement("GeometryData"); - doc.LinkEndChild(rootNode); + auto* rootNode = doc.NewElement("GeometryData"); + doc.InsertEndChild(rootNode); // note version info - auto *version = new TiXmlElement("Version"); + auto *version = doc.NewElement("Version"); version->SetAttribute("Writer", __FILE__); version->SetAttribute("FileVersion", 1); - rootNode->LinkEndChild(version); + rootNode->InsertEndChild(version); const auto *data = static_cast(this->GetInput()); const ProportionalTimeGeometry *timeGeometry(nullptr); if ((timeGeometry = dynamic_cast(data->GetTimeGeometry()))) { - TiXmlElement *timeGeometryElement = ProportionalTimeGeometryToXML::ToXML(timeGeometry); - rootNode->LinkEndChild(timeGeometryElement); + auto *timeGeometryElement = ProportionalTimeGeometryToXML::ToXML(doc, timeGeometry); + rootNode->InsertEndChild(timeGeometryElement); } else { MITK_WARN << "Serializing GeometryData that does not have a valid ProportionalTimeGeometry! Not implemented!"; } // Write out document - out << doc; + tinyxml2::XMLPrinter printer; + doc.Print(&printer); + out << printer.CStr(); } mitk::GeometryDataWriterService *mitk::GeometryDataWriterService::Clone() const { return new GeometryDataWriterService(*this); } diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.cpp b/Modules/Core/src/IO/mitkPointSetReaderService.cpp index 68cc84f562..63d3018782 100644 --- a/Modules/Core/src/IO/mitkPointSetReaderService.cpp +++ b/Modules/Core/src/IO/mitkPointSetReaderService.cpp @@ -1,275 +1,276 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkPointSetReaderService.h" #include "mitkGeometry3DToXML.h" #include "mitkIOMimeTypes.h" #include "mitkProportionalTimeGeometry.h" +#include // STL #include #include -#include -#include +#include mitk::PointSetReaderService::PointSetReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE()), "MITK Point Set Reader") { RegisterService(); } mitk::PointSetReaderService::~PointSetReaderService() { } std::vector> mitk::PointSetReaderService::DoRead() { // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); std::vector> result; InputStream stream(this); - TiXmlDocument doc; - stream >> doc; + std::string s(std::istreambuf_iterator{stream.rdbuf()}, std::istreambuf_iterator()); + tinyxml2::XMLDocument doc; + doc.Parse(s.c_str(), s.size()); if (!doc.Error()) { - TiXmlHandle docHandle(&doc); + tinyxml2::XMLHandle docHandle(&doc); // unsigned int pointSetCounter(0); - for (TiXmlElement *currentPointSetElement = + for (auto *currentPointSetElement = docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement(); currentPointSetElement != nullptr; currentPointSetElement = currentPointSetElement->NextSiblingElement()) { mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); // time geometry assembled for addition after all points // else the SetPoint method would already transform the points that we provide it mitk::ProportionalTimeGeometry::Pointer timeGeometry = mitk::ProportionalTimeGeometry::New(); if (currentPointSetElement->FirstChildElement("time_series") != nullptr) { - for (TiXmlElement *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); + for (auto *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); currentTimeSeries != nullptr; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); - TiXmlElement *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); + auto *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); currentTimeStep = atoi(currentTimeSeriesID->GetText()); timeGeometry->Expand(currentTimeStep + 1); // expand (default to identity) in any case - TiXmlElement *geometryElem = currentTimeSeries->FirstChildElement("Geometry3D"); + auto *geometryElem = currentTimeSeries->FirstChildElement("Geometry3D"); if (geometryElem) { Geometry3D::Pointer geometry = Geometry3DToXML::FromXML(geometryElem); if (geometry.IsNotNull()) { timeGeometry->SetTimeStepGeometry(geometry, currentTimeStep); } else { MITK_ERROR << "Could not deserialize Geometry3D element."; } } else { MITK_WARN << "Fallback to legacy behavior: defining PointSet geometry as identity"; } newPointSet = this->ReadPoints(newPointSet, currentTimeSeries, currentTimeStep); } } else { newPointSet = this->ReadPoints(newPointSet, currentPointSetElement, 0); } newPointSet->SetTimeGeometry(timeGeometry); result.push_back(newPointSet.GetPointer()); } } else { - mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); + mitkThrow() << doc.ErrorStr(); } return result; } -mitk::BaseGeometry::Pointer mitk::PointSetReaderService::ReadGeometry(TiXmlElement *parentElement) +mitk::BaseGeometry::Pointer mitk::PointSetReaderService::ReadGeometry(tinyxml2::XMLElement *parentElement) { - TiXmlElement *geometryElem = parentElement->FirstChildElement("geometry3d"); + auto *geometryElem = parentElement->FirstChildElement("geometry3d"); if (!geometryElem) return nullptr; // data to generate AffineTransform3D::MatrixType matrix; AffineTransform3D::OffsetType offset; bool isImageGeometry(false); unsigned int frameOfReferenceID(0); BaseGeometry::BoundsArrayType bounds; bool somethingMissing(false); // find data in xml structure - TiXmlElement *imageGeometryElem = geometryElem->FirstChildElement("image_geometry"); + auto *imageGeometryElem = geometryElem->FirstChildElement("image_geometry"); if (imageGeometryElem) { std::string igs = imageGeometryElem->GetText(); isImageGeometry = igs == "true" || igs == "TRUE" || igs == "1"; } else somethingMissing = true; - TiXmlElement *frameOfReferenceElem = geometryElem->FirstChildElement("frame_of_reference_id"); + auto *frameOfReferenceElem = geometryElem->FirstChildElement("frame_of_reference_id"); if (frameOfReferenceElem) { frameOfReferenceID = atoi(frameOfReferenceElem->GetText()); } else somethingMissing = true; - TiXmlElement *indexToWorldElem = geometryElem->FirstChildElement("index_to_world"); + auto *indexToWorldElem = geometryElem->FirstChildElement("index_to_world"); if (indexToWorldElem) { - TiXmlElement *matrixElem = indexToWorldElem->FirstChildElement("matrix3x3"); - TiXmlElement *offsetElem = indexToWorldElem->FirstChildElement("offset"); + auto *matrixElem = indexToWorldElem->FirstChildElement("matrix3x3"); + auto *offsetElem = indexToWorldElem->FirstChildElement("offset"); if (indexToWorldElem && offsetElem) { - TiXmlElement *col0 = matrixElem->FirstChildElement("column_0"); - TiXmlElement *col1 = matrixElem->FirstChildElement("column_1"); - TiXmlElement *col2 = matrixElem->FirstChildElement("column_2"); + auto*col0 = matrixElem->FirstChildElement("column_0"); + auto*col1 = matrixElem->FirstChildElement("column_1"); + auto*col2 = matrixElem->FirstChildElement("column_2"); if (col0 && col1 && col2) { - somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("x", &matrix[0][0]); - somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("y", &matrix[1][0]); - somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("z", &matrix[2][0]); + somethingMissing |= tinyxml2::XML_SUCCESS != col0->QueryDoubleAttribute("x", &matrix[0][0]); + somethingMissing |= tinyxml2::XML_SUCCESS != col0->QueryDoubleAttribute("y", &matrix[1][0]); + somethingMissing |= tinyxml2::XML_SUCCESS != col0->QueryDoubleAttribute("z", &matrix[2][0]); - somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("x", &matrix[0][1]); - somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("y", &matrix[1][1]); - somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("z", &matrix[2][1]); + somethingMissing |= tinyxml2::XML_SUCCESS != col1->QueryDoubleAttribute("x", &matrix[0][1]); + somethingMissing |= tinyxml2::XML_SUCCESS != col1->QueryDoubleAttribute("y", &matrix[1][1]); + somethingMissing |= tinyxml2::XML_SUCCESS != col1->QueryDoubleAttribute("z", &matrix[2][1]); - somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("x", &matrix[0][2]); - somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("y", &matrix[1][2]); - somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("z", &matrix[2][2]); + somethingMissing |= tinyxml2::XML_SUCCESS != col2->QueryDoubleAttribute("x", &matrix[0][2]); + somethingMissing |= tinyxml2::XML_SUCCESS != col2->QueryDoubleAttribute("y", &matrix[1][2]); + somethingMissing |= tinyxml2::XML_SUCCESS != col2->QueryDoubleAttribute("z", &matrix[2][2]); } else somethingMissing = true; - somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("x", &offset[0]); - somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("y", &offset[1]); - somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("z", &offset[2]); + somethingMissing |= tinyxml2::XML_SUCCESS != offsetElem->QueryDoubleAttribute("x", &offset[0]); + somethingMissing |= tinyxml2::XML_SUCCESS != offsetElem->QueryDoubleAttribute("y", &offset[1]); + somethingMissing |= tinyxml2::XML_SUCCESS != offsetElem->QueryDoubleAttribute("z", &offset[2]); } else somethingMissing = true; - TiXmlElement *boundsElem = geometryElem->FirstChildElement("bounds"); + auto *boundsElem = geometryElem->FirstChildElement("bounds"); if (boundsElem) { - TiXmlElement *minBoundsElem = boundsElem->FirstChildElement("min"); - TiXmlElement *maxBoundsElem = boundsElem->FirstChildElement("max"); + auto *minBoundsElem = boundsElem->FirstChildElement("min"); + auto *maxBoundsElem = boundsElem->FirstChildElement("max"); if (minBoundsElem && maxBoundsElem) { - somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("x", &bounds[0]); - somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("y", &bounds[2]); - somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("z", &bounds[4]); + somethingMissing |= tinyxml2::XML_SUCCESS != minBoundsElem->QueryDoubleAttribute("x", &bounds[0]); + somethingMissing |= tinyxml2::XML_SUCCESS != minBoundsElem->QueryDoubleAttribute("y", &bounds[2]); + somethingMissing |= tinyxml2::XML_SUCCESS != minBoundsElem->QueryDoubleAttribute("z", &bounds[4]); - somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("x", &bounds[1]); - somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("y", &bounds[3]); - somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("z", &bounds[5]); + somethingMissing |= tinyxml2::XML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("x", &bounds[1]); + somethingMissing |= tinyxml2::XML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("y", &bounds[3]); + somethingMissing |= tinyxml2::XML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("z", &bounds[5]); } else somethingMissing = true; } else somethingMissing = true; } else somethingMissing = true; if (somethingMissing) { MITK_ERROR << "XML structure of geometry inside a PointSet file broken. Refusing to build Geometry3D"; return nullptr; } else { Geometry3D::Pointer g = Geometry3D::New(); g->SetImageGeometry(isImageGeometry); g->SetFrameOfReferenceID(frameOfReferenceID); g->SetBounds(bounds); AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(offset); g->SetIndexToWorldTransform(transform); return g.GetPointer(); } } mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoints(mitk::PointSet::Pointer newPointSet, - TiXmlElement *currentTimeSeries, + tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep) { if (currentTimeSeries->FirstChildElement("point") != nullptr) { - for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != nullptr; + for (auto *currentPoint = currentTimeSeries->FirstChildElement("point"); currentPoint != nullptr; currentPoint = currentPoint->NextSiblingElement()) { unsigned int id(0); auto spec((mitk::PointSpecificationType)0); double x(0.0); double y(0.0); double z(0.0); id = atoi(currentPoint->FirstChildElement("id")->GetText()); if (currentPoint->FirstChildElement("specification") != nullptr) { spec = (mitk::PointSpecificationType)atoi(currentPoint->FirstChildElement("specification")->GetText()); } x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newPointSet->SetPoint(id, point, spec, currentTimeStep); } } else { if (currentTimeStep != newPointSet->GetTimeSteps() + 1) { newPointSet->Expand(currentTimeStep + 1); // expand time step series with empty time step } } return newPointSet; } mitk::PointSetReaderService::PointSetReaderService(const mitk::PointSetReaderService &other) : mitk::AbstractFileReader(other) { } mitk::PointSetReaderService *mitk::PointSetReaderService::Clone() const { return new mitk::PointSetReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.h b/Modules/Core/src/IO/mitkPointSetReaderService.h index 5aba51b592..f72bc23fdb 100644 --- a/Modules/Core/src/IO/mitkPointSetReaderService.h +++ b/Modules/Core/src/IO/mitkPointSetReaderService.h @@ -1,62 +1,65 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_POINT_SET_READER_SERVICE__H_ #define _MITK_POINT_SET_READER_SERVICE__H_ // MITK #include #include -class TiXmlElement; +namespace tinyxml2 +{ + class XMLElement; +} namespace mitk { /** * @internal * * @brief reads xml representations of mitk::PointSets from a file * * Reader for xml files containing one or multiple xml represenations of * mitk::PointSet. If multiple mitk::PointSet objects are stored in one file, * these are assigned to multiple BaseData objects. * * The reader is able to read the old 3D Pointsets without the "specification" and "timeseries" tags and the new 4D * Pointsets. * * @ingroup IO */ class PointSetReaderService : public AbstractFileReader { public: PointSetReaderService(); ~PointSetReaderService() override; using AbstractFileReader::Read; protected: std::vector> DoRead() override; private: PointSetReaderService(const PointSetReaderService &other); - mitk::BaseGeometry::Pointer ReadGeometry(TiXmlElement *parentElement); + mitk::BaseGeometry::Pointer ReadGeometry(tinyxml2::XMLElement *parentElement); mitk::PointSet::Pointer ReadPoints(mitk::PointSet::Pointer newPointSet, - TiXmlElement *currentTimeSeries, + tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep); PointSetReaderService *Clone() const override; }; } #endif diff --git a/Modules/Core/src/IO/mitkPointSetWriterService.cpp b/Modules/Core/src/IO/mitkPointSetWriterService.cpp index 30a5d25dcc..63e99ad061 100644 --- a/Modules/Core/src/IO/mitkPointSetWriterService.cpp +++ b/Modules/Core/src/IO/mitkPointSetWriterService.cpp @@ -1,182 +1,179 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPointSetWriterService.h" #include "mitkGeometry3DToXML.h" #include "mitkIOMimeTypes.h" #include "mitkLocaleSwitch.h" #include "mitkGeometry3D.h" -#include - #include #include #include +#include + // // Initialization of the xml tags. // const std::string mitk::PointSetWriterService::XML_POINT_SET_FILE = "point_set_file"; const std::string mitk::PointSetWriterService::XML_FILE_VERSION = "file_version"; const std::string mitk::PointSetWriterService::XML_POINT_SET = "point_set"; const std::string mitk::PointSetWriterService::XML_TIME_SERIES = "time_series"; const std::string mitk::PointSetWriterService::XML_TIME_SERIES_ID = "time_series_id"; const std::string mitk::PointSetWriterService::XML_POINT = "point"; const std::string mitk::PointSetWriterService::XML_ID = "id"; const std::string mitk::PointSetWriterService::XML_SPEC = "specification"; const std::string mitk::PointSetWriterService::XML_X = "x"; const std::string mitk::PointSetWriterService::XML_Y = "y"; const std::string mitk::PointSetWriterService::XML_Z = "z"; const std::string mitk::PointSetWriterService::VERSION_STRING = "0.1"; mitk::PointSetWriterService::PointSetWriterService() : AbstractFileWriter( PointSet::GetStaticNameOfClass(), CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE()), "MITK Point Set Writer") { RegisterService(); } mitk::PointSetWriterService::PointSetWriterService(const mitk::PointSetWriterService &other) : AbstractFileWriter(other) { } mitk::PointSetWriterService::~PointSetWriterService() { } void mitk::PointSetWriterService::Write() { mitk::LocaleSwitch localeC("C"); - TiXmlDocument doc; - - auto *decl = new TiXmlDeclaration( - "1.0", "UTF-8", ""); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... - doc.LinkEndChild(decl); + tinyxml2::XMLDocument doc; + doc.InsertEndChild(doc.NewDeclaration()); - auto *rootNode = new TiXmlElement(XML_POINT_SET_FILE); - doc.LinkEndChild(rootNode); + auto *rootNode = doc.NewElement(XML_POINT_SET_FILE.c_str()); + doc.InsertEndChild(rootNode); - auto *versionNode = new TiXmlElement(XML_FILE_VERSION); - auto *versionText = new TiXmlText(VERSION_STRING); - versionNode->LinkEndChild(versionText); - rootNode->LinkEndChild(versionNode); + auto *versionNode = doc.NewElement(XML_FILE_VERSION.c_str()); + auto *versionText = doc.NewText(VERSION_STRING.c_str()); + versionNode->InsertEndChild(versionText); + rootNode->InsertEndChild(versionNode); - TiXmlElement *pointSetNode = ToXML(static_cast(this->GetInput())); + auto *pointSetNode = ToXML(doc, static_cast(this->GetInput())); if (!pointSetNode) { mitkThrow() << "Serialization error during PointSet writing."; } - rootNode->LinkEndChild(pointSetNode); + rootNode->InsertEndChild(pointSetNode); // out << doc; // streaming of TinyXML write no new-lines, // rendering XML files unreadable (for humans) LocalFile f(this); - if (!doc.SaveFile(f.GetFileName())) + if (tinyxml2::XML_SUCCESS != doc.SaveFile(f.GetFileName().c_str())) { mitkThrow() << "Some error during point set writing."; } } mitk::PointSetWriterService *mitk::PointSetWriterService::Clone() const { return new PointSetWriterService(*this); } -TiXmlElement *mitk::PointSetWriterService::ToXML(const mitk::PointSet *pointSet) +tinyxml2::XMLElement *mitk::PointSetWriterService::ToXML(tinyxml2::XMLDocument& doc, const mitk::PointSet *pointSet) { // the following is rather bloated and could be expressed in more compact XML // (e.g. using attributes instead of tags for x/y/z). The current format is // kept to be compatible with the previous writer. - auto *pointSetElement = new TiXmlElement(XML_POINT_SET); + auto *pointSetElement = doc.NewElement(XML_POINT_SET.c_str()); unsigned int timecount = pointSet->GetTimeSteps(); for (unsigned int i = 0; i < timecount; i++) { - auto *timeSeriesElement = new TiXmlElement(XML_TIME_SERIES); - pointSetElement->LinkEndChild(timeSeriesElement); + auto *timeSeriesElement = doc.NewElement(XML_TIME_SERIES.c_str()); + pointSetElement->InsertEndChild(timeSeriesElement); - auto *timeSeriesIDElement = new TiXmlElement(XML_TIME_SERIES_ID); - timeSeriesElement->LinkEndChild(timeSeriesIDElement); - TiXmlText *timeSeriesIDText = new TiXmlText(ConvertToString(i)); - timeSeriesIDElement->LinkEndChild(timeSeriesIDText); + auto *timeSeriesIDElement = doc.NewElement(XML_TIME_SERIES_ID.c_str()); + timeSeriesElement->InsertEndChild(timeSeriesIDElement); + auto *timeSeriesIDText = doc.NewText(ConvertToString(i).c_str()); + timeSeriesIDElement->InsertEndChild(timeSeriesIDText); PointSet::PointsContainer *pointsContainer = pointSet->GetPointSet(i)->GetPoints(); PointSet::PointsContainer::Iterator it; auto *geometry = dynamic_cast(pointSet->GetGeometry(i)); if (geometry == nullptr) { MITK_WARN << "Writing a PointSet with something other that a Geometry3D. This is not foreseen and not handled."; // we'll continue anyway, this imitates previous behavior } else { - TiXmlElement *geometryElement = Geometry3DToXML::ToXML(geometry); - timeSeriesElement->LinkEndChild(geometryElement); + auto *geometryElement = Geometry3DToXML::ToXML(doc, geometry); + timeSeriesElement->InsertEndChild(geometryElement); } for (it = pointsContainer->Begin(); it != pointsContainer->End(); ++it) { - auto *pointElement = new TiXmlElement(XML_POINT); - timeSeriesElement->LinkEndChild(pointElement); + auto *pointElement = doc.NewElement(XML_POINT.c_str()); + timeSeriesElement->InsertEndChild(pointElement); - auto *pointIDElement = new TiXmlElement(XML_ID); - TiXmlText *pointIDText = new TiXmlText(ConvertToString(it->Index())); - pointIDElement->LinkEndChild(pointIDText); - pointElement->LinkEndChild(pointIDElement); + auto *pointIDElement = doc.NewElement(XML_ID.c_str()); + auto *pointIDText = doc.NewText(ConvertToString(it->Index()).c_str()); + pointIDElement->InsertEndChild(pointIDText); + pointElement->InsertEndChild(pointIDElement); mitk::PointSet::PointType point = it->Value(); - auto *pointSpecElement = new TiXmlElement(XML_SPEC); - TiXmlText *pointSpecText = new TiXmlText(ConvertToString(pointSet->GetSpecificationTypeInfo(it->Index(), i))); - pointSpecElement->LinkEndChild(pointSpecText); - pointElement->LinkEndChild(pointSpecElement); - - auto *pointXElement = new TiXmlElement(XML_X); - TiXmlText *pointXText = new TiXmlText(ConvertToString(point[0])); - pointXElement->LinkEndChild(pointXText); - pointElement->LinkEndChild(pointXElement); - - auto *pointYElement = new TiXmlElement(XML_Y); - TiXmlText *pointYText = new TiXmlText(ConvertToString(point[1])); - pointYElement->LinkEndChild(pointYText); - pointElement->LinkEndChild(pointYElement); - - auto *pointZElement = new TiXmlElement(XML_Z); - TiXmlText *pointZText = new TiXmlText(ConvertToString(point[2])); - pointZElement->LinkEndChild(pointZText); - pointElement->LinkEndChild(pointZElement); + auto *pointSpecElement = doc.NewElement(XML_SPEC.c_str()); + auto *pointSpecText = doc.NewText(ConvertToString(pointSet->GetSpecificationTypeInfo(it->Index(), i)).c_str()); + pointSpecElement->InsertEndChild(pointSpecText); + pointElement->InsertEndChild(pointSpecElement); + + auto *pointXElement = doc.NewElement(XML_X.c_str()); + auto *pointXText = doc.NewText(ConvertToString(point[0]).c_str()); + pointXElement->InsertEndChild(pointXText); + pointElement->InsertEndChild(pointXElement); + + auto *pointYElement = doc.NewElement(XML_Y.c_str()); + auto *pointYText = doc.NewText(ConvertToString(point[1]).c_str()); + pointYElement->InsertEndChild(pointYText); + pointElement->InsertEndChild(pointYElement); + + auto *pointZElement = doc.NewElement(XML_Z.c_str()); + auto *pointZText = doc.NewText(ConvertToString(point[2]).c_str()); + pointZElement->InsertEndChild(pointZText); + pointElement->InsertEndChild(pointZElement); } } return pointSetElement; } template std::string mitk::PointSetWriterService::ConvertToString(T value) { std::ostringstream o; std::locale I("C"); o.imbue(I); if (o << std::setprecision(12) << value) { return o.str(); } else { return "conversion error"; } } diff --git a/Modules/Core/src/IO/mitkPointSetWriterService.h b/Modules/Core/src/IO/mitkPointSetWriterService.h index b9b55d4aef..68aa0e99e7 100644 --- a/Modules/Core/src/IO/mitkPointSetWriterService.h +++ b/Modules/Core/src/IO/mitkPointSetWriterService.h @@ -1,71 +1,75 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_POINT_SET_WRITER_SERVICE__H_ #define _MITK_POINT_SET_WRITER_SERVICE__H_ #include #include -class TiXmlElement; +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; +} namespace mitk { class Geometry3D; /** * @internal * * @brief XML-based writer for mitk::PointSets * * XML-based writer for mitk::PointSet. Multiple PointSets can be written in * a single XML file by simply setting multiple inputs to the filter. * * @todo This class would merit a XML library for maintainability or a denser format for performance. * * @ingroup IO */ class PointSetWriterService : public AbstractFileWriter { public: PointSetWriterService(); ~PointSetWriterService() override; using AbstractFileWriter::Write; void Write() override; private: PointSetWriterService(const PointSetWriterService &other); mitk::PointSetWriterService *Clone() const override; template std::string ConvertToString(T value); - TiXmlElement *ToXML(const mitk::PointSet *pointSet); + tinyxml2::XMLElement *ToXML(tinyxml2::XMLDocument &doc, const mitk::PointSet *pointSet); static const std::string XML_POINT_SET; static const std::string XML_TIME_SERIES; static const std::string XML_TIME_SERIES_ID; static const std::string XML_POINT_SET_FILE; static const std::string XML_FILE_VERSION; static const std::string XML_POINT; static const std::string XML_SPEC; static const std::string XML_ID; static const std::string XML_X; static const std::string XML_Y; static const std::string XML_Z; static const std::string VERSION_STRING; }; } #endif diff --git a/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp index 6df438ad99..3b42888705 100644 --- a/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp +++ b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp @@ -1,162 +1,164 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkProportionalTimeGeometryToXML.h" #include "mitkGeometry3DToXML.h" -#include - #include -TiXmlElement *mitk::ProportionalTimeGeometryToXML::ToXML(const ProportionalTimeGeometry *timeGeom) +#include + +tinyxml2::XMLElement *mitk::ProportionalTimeGeometryToXML::ToXML(tinyxml2::XMLDocument& doc, const ProportionalTimeGeometry *timeGeom) { assert(timeGeom); - auto *timeGeomElem = new TiXmlElement("ProportionalTimeGeometry"); - timeGeomElem->SetAttribute("NumberOfTimeSteps", timeGeom->CountTimeSteps()); + auto *timeGeomElem = doc.NewElement("ProportionalTimeGeometry"); + timeGeomElem->SetAttribute("NumberOfTimeSteps", static_cast(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())); + timeGeomElem->SetAttribute("FirstTimePoint", boost::lexical_cast(timeGeom->GetFirstTimePoint()).c_str()); if (timeGeom->GetStepDuration() != std::numeric_limits::infinity()) - timeGeomElem->SetAttribute("StepDuration", boost::lexical_cast(timeGeom->GetStepDuration())); + timeGeomElem->SetAttribute("StepDuration", boost::lexical_cast(timeGeom->GetStepDuration()).c_str()); 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); + auto *geom3DElement = Geometry3DToXML::ToXML(doc, geom3D); + geom3DElement->SetAttribute("TimeStep", static_cast(t)); // mark order for us + timeGeomElem->InsertEndChild(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) +mitk::ProportionalTimeGeometry::Pointer mitk::ProportionalTimeGeometryToXML::FromXML(const tinyxml2::XMLElement *timeGeometryElement) { if (!timeGeometryElement) { MITK_ERROR << "Cannot deserialize ProportionalTimeGeometry from nullptr."; return nullptr; } int numberOfTimeSteps = 0; - if (TIXML_SUCCESS != timeGeometryElement->QueryIntAttribute("NumberOfTimeSteps", &numberOfTimeSteps)) + if (tinyxml2::XML_SUCCESS != timeGeometryElement->QueryIntAttribute("NumberOfTimeSteps", &numberOfTimeSteps)) { MITK_WARN << " found without NumberOfTimeSteps attribute. Counting..."; } // might be missing! TimePointType firstTimePoint; - std::string firstTimePoint_s; + const char* firstTimePoint_s = nullptr; TimePointType stepDuration; - std::string stepDuration_s; + const char* stepDuration_s = nullptr; try { - if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("FirstTimePoint", &firstTimePoint_s)) + firstTimePoint_s = timeGeometryElement->Attribute("FirstTimePoint"); + if (nullptr != firstTimePoint_s) { firstTimePoint = boost::lexical_cast(firstTimePoint_s); } else { firstTimePoint = -std::numeric_limits::max(); } - if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("StepDuration", &stepDuration_s)) + stepDuration_s = timeGeometryElement->Attribute("StepDuration"); + if (nullptr != stepDuration_s) { stepDuration = boost::lexical_cast(stepDuration_s); } else { stepDuration = std::numeric_limits::infinity(); } } 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; + for (auto *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)) + if (tinyxml2::XML_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/mitkProportionalTimeGeometryToXML.h b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.h index 5091a9a482..5ccd053619 100644 --- a/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.h +++ b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.h @@ -1,51 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkProportionalTimeGeometryToXML_h #define mitkProportionalTimeGeometryToXML_h -// MITK #include "mitkProportionalTimeGeometry.h" -class TiXmlElement; +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; +} namespace mitk { /** * @internal * * @brief Helper for ProportionalTimeGeometry related I/O classes. * * Creates TinyXML elements (blocks) that describe a ProportionalTimeGeometry. * Also offers a method to read such blocks and create a corresponding ProportionalTimeGeometry. * * @sa GeometryDataWriterService, GeometryDataReaderService, Geometry3DToXML * * @ingroup IO */ class ProportionalTimeGeometryToXML { public: /** * @brief Serialize given geometry to XML. */ - static TiXmlElement *ToXML(const ProportionalTimeGeometry *geometry); + static tinyxml2::XMLElement *ToXML(tinyxml2::XMLDocument& doc, const ProportionalTimeGeometry *geometry); /** * @brief Create a ProportionalTimeGeometry from XML. * Interprets only the format created by ToXML(). */ - static ProportionalTimeGeometry::Pointer FromXML(TiXmlElement *node); + static ProportionalTimeGeometry::Pointer FromXML(const tinyxml2::XMLElement *node); }; } #endif diff --git a/Modules/Core/test/CMakeLists.txt b/Modules/Core/test/CMakeLists.txt index d3d3321aed..dc8d4ee9b4 100644 --- a/Modules/Core/test/CMakeLists.txt +++ b/Modules/Core/test/CMakeLists.txt @@ -1,181 +1,181 @@ # The core tests need relaxed compiler flags... # TODO fix core tests to compile without these additional no-error flags if(MSVC_VERSION) # disable deprecated warnings (they would lead to errors) mitkFunctionCheckCAndCXXCompilerFlags("/wd4996" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) else() mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=deprecated-declarations" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() MITK_CREATE_MODULE_TESTS() if(TARGET ${TESTDRIVER}) - mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|ITKThresholding+ITKTestKernel VTK|TestingRendering tinyxml) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|IONRRD VTK|TestingRendering tinyxml2) mitkAddCustomModuleTest(mitkVolumeCalculatorTest_Png2D-bw mitkVolumeCalculatorTest ${MITK_DATA_DIR}/Png2D-bw.png ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkEventConfigTest_CreateObjectInDifferentWays mitkEventConfigTest ${MITK_SOURCE_DIR}/Modules/Core/test/resource/Interactions/StatemachineConfigTest.xml ) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.nrrd ) mitkAddCustomModuleTest(mitkPointSetReaderTest mitkPointSetReaderTest ${MITK_DATA_DIR}/PointSetReaderTestData.mps ) mitkAddCustomModuleTest(mitkImageTest_4DImageData mitkImageTest ${MITK_DATA_DIR}/US4DCyl.nrrd ) mitkAddCustomModuleTest(mitkImageTest_2D+tImageData mitkImageTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkImageTest_3DImageData mitkImageTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkImageEqualTest mitkImageEqualTest) mitkAddCustomModuleTest(mitkImageTest_brainImage mitkImageTest ${MITK_DATA_DIR}/brain.mhd ) mitkAddCustomModuleTest(mitkLevelWindowManagerTest mitkLevelWindowManagerTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkMultiComponentImageDataComparisonFilterTest mitkMultiComponentImageDataComparisonFilterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg ) mitkAddCustomModuleTest(mitkImageToItkTest mitkImageToItkTest ${MITK_DATA_DIR}/Pic3D.nrrd ) mitkAddCustomModuleTest(mitkImageSliceSelectorTest mitkImageSliceSelectorTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd ) mitkAddCustomModuleTest(mitkRotatedSlice4DTest mitkRotatedSlice4DTest ${MITK_DATA_DIR}/UltrasoundImages/4D_TEE_Data_MV.dcm ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/rgbaImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3d640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2DColorTest #test for color property (=blue) Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dColorBlue640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2DLevelWindowTest #test for levelwindow property (=blood) #Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dLevelWindowBlood640x480REF.png #corresponding reference #screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DSwivelTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dSwivel640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkPointSetVtkMapper2D_openMeAlone640x480 mitkPointSetVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAlone640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkPointSetVtkMapper2D_Pic3DPointSetForPic3D640x480 mitkPointSetVtkMapper2DImageTest ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/RenderingTestData/PointSetForPic3D.mps #input point set and image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Pic3DPointSetForPic3D640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkPointSetVtkMapper2D_openMeAloneGlyphType640x480 mitkPointSetVtkMapper2DGlyphTypeTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAloneGlyphType640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkPointSetVtkMapper2D_openMeAloneTransformed640x480 mitkPointSetVtkMapper2DTransformedPointsTest ${MITK_DATA_DIR}/RenderingTestData/openMeAlone.mps #input point set to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/openMeAloneTransformedPoints640x480REF.png #corresponding reference screenshot ) # Currently not working on windows because of a rendering timing issue # see bug 18083 for details if(NOT WIN32) mitkAddCustomModuleRenderingTest(mitkSurfaceDepthSortingTransparency_StanfordBunnySTL640x480 mitkSurfaceDepthSortingTest ${MITK_DATA_DIR}/RenderingTestData/Stanford_bunny.stl -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Stanford_bunnySTLDepthSorting640x480REF.png) endif() # BUG 18695 - tests deactivated, because win 32 bit continuous renders images slightly different. TODO! #Test reslice interpolation #note: nearest mode is already tested by swivel test #mitkAddCustomModuleRenderingTest(ResliceInterpolationIsLinear mitkImageVtkMapper2DResliceInterpolationPropertyTest # 1 #linear # ${MITK_DATA_DIR}/Pic3D.nrrd # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dRefLinear.png #corresponding reference screenshot LINEAR #) #mitkAddCustomModuleRenderingTest(ResliceInterpolationIsCubic mitkImageVtkMapper2DResliceInterpolationPropertyTest # 3 #cubic # ${MITK_DATA_DIR}/Pic3D.nrrd # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dRefCubic.png #corresponding reference screenshot CUBIC #) #End test reslice interpolation # Testing of the rendering of binary images #mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_binaryTestImage640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice # ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImage640x480REF.png #corresponding reference screenshot #) #mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2D_binaryTestImageWithRef640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice # ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage # -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImageWithRef640x480REF.png #corresponding reference screenshot #) # End of binary image tests mitkAddCustomModuleRenderingTest(mitkSurfaceVtkMapper3DTest_TextureProperty mitkSurfaceVtkMapper3DTest ${MITK_DATA_DIR}/RenderingTestData/earth.jpg -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedSphere640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-TransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2DOpacityTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DOpacityTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-OpacityTransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) ############################## DISABLED TESTS mitkAddCustomModuleRenderingTest(mitkImageVtkMapper2DLookupTableTest_Png2D-bw mitkImageVtkMapper2DLookupTableTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-LookupTableRGBImage640x480REF.png #corresponding reference screenshot ) #mitkAddCustomModuleRenderingTest(mitkImageTest_color2DImage mitkImageTest # ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg #) #mitkAddCustomModuleRenderingTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest # ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz #) mitkAddCustomModuleRenderingTest(mitkPlaneGeometryDataMapper2DTest mitkPlaneGeometryDataMapper2DTest ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/PlaneGeometryMapper640x480REF.png #corresponding reference screenshot ) endif() # TARGET ${TESTDRIVER} diff --git a/Modules/Core/test/mitkTinyXMLTest.cpp b/Modules/Core/test/mitkTinyXMLTest.cpp index ddd251e473..392ab4384d 100644 --- a/Modules/Core/test/mitkTinyXMLTest.cpp +++ b/Modules/Core/test/mitkTinyXMLTest.cpp @@ -1,159 +1,162 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // Testing #include "mitkTestFixture.h" #include // std includes #include #include -#include +#include // MITK includes #include "mitkStringProperty.h" #include // itksys #include // VTK includes #include // vnl includes #include class mitkTinyXMLTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkTinyXMLTestSuite); MITK_TEST(TestingFunctionSetupWorks_Success); MITK_TEST(TestingReadValueFromSetupDocument_Success); MITK_TEST(TestingReadOutValueWorks_Success); MITK_TEST(TestDoubleValueWriteOut_Success); MITK_TEST(TestDoubleValueWriteOutManyDecimalPlaces_Success); CPPUNIT_TEST_SUITE_END(); private: const std::string m_Filename = itksys::SystemTools::GetCurrentWorkingDirectory() + "/TinyXMLTest.txt"; const std::string m_ElementToStoreAttributeName = "DoubleTest"; const std::string m_AttributeToStoreName = "CommaValue"; - TiXmlDocument m_Document; - TiXmlElement *m_DoubleTest; + tinyxml2::XMLDocument m_Document; + tinyxml2::XMLElement *m_DoubleTest; double calcPrecision(const unsigned int requiredDecimalPlaces) { return pow(10.0, -1.0 * ((double)requiredDecimalPlaces)); } bool Setup(double valueToWrite) { + m_Document.Clear(); + m_DoubleTest = nullptr; + // 1. create simple document - auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc.... - m_Document.LinkEndChild(decl); + m_Document.InsertEndChild(m_Document.NewDeclaration()); - auto version = new TiXmlElement("Version"); + auto *version = m_Document.NewElement("Version"); version->SetAttribute("Writer", __FILE__); version->SetAttribute("CVSRevision", "$Revision: 17055 $"); version->SetAttribute("FileVersion", 1); - m_Document.LinkEndChild(version); + m_Document.InsertEndChild(version); // 2. store one element containing a double value with potentially many after comma digits. - auto vElement = new TiXmlElement(m_ElementToStoreAttributeName); - vElement->SetDoubleAttribute(m_AttributeToStoreName, valueToWrite); - m_Document.LinkEndChild(vElement); + auto *vElement = m_Document.NewElement(m_ElementToStoreAttributeName.c_str()); + vElement->SetAttribute(m_AttributeToStoreName.c_str(), valueToWrite); + m_Document.InsertEndChild(vElement); // 3. store in file. - return m_Document.SaveFile(m_Filename); + auto err = m_Document.SaveFile(m_Filename.c_str()); + return tinyxml2::XML_SUCCESS == err; } public: void setUp() override {} void tearDown() override {} void TestingFunctionSetupWorks_Success() { CPPUNIT_ASSERT_MESSAGE("Test if Setup correctly writes data to file", Setup(1.0)); } int readValueFromSetupDocument(double &readOutValue) { - if (!m_Document.LoadFile(m_Filename)) + if (tinyxml2::XML_SUCCESS != m_Document.LoadFile(m_Filename.c_str())) { CPPUNIT_ASSERT_MESSAGE("Test Setup failed, could not open file", false); - return TIXML_NO_ATTRIBUTE; + return tinyxml2::XML_NO_ATTRIBUTE; } else { - m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName); - return m_DoubleTest->QueryDoubleAttribute(m_AttributeToStoreName, &readOutValue); + m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName.c_str()); + return m_DoubleTest->QueryDoubleAttribute(m_AttributeToStoreName.c_str(), &readOutValue); } } void TestingReadValueFromSetupDocument_Success() { - if (!m_Document.LoadFile(m_Filename)) + if (tinyxml2::XML_SUCCESS != m_Document.LoadFile(m_Filename.c_str())) { - CPPUNIT_ASSERT_MESSAGE("Test Setup failed, could not open file", !m_Document.LoadFile(m_Filename)); + CPPUNIT_ASSERT_MESSAGE("Test Setup failed, could not open file", tinyxml2::XML_SUCCESS != m_Document.LoadFile(m_Filename.c_str())); } else { - m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName); + m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName.c_str()); CPPUNIT_ASSERT_MESSAGE("Test Setup could open file", m_DoubleTest != nullptr); } } /** * this first test ensures we can correctly readout values from the * TinyXMLDocument. */ void TestingReadOutValueWorks_Success() { double readValue; CPPUNIT_ASSERT_MESSAGE("checking if readout mechanism works.", - TIXML_SUCCESS == readValueFromSetupDocument(readValue)); + tinyxml2::XML_SUCCESS == readValueFromSetupDocument(readValue)); } void TestDoubleValueWriteOut_Success() { const double valueToWrite = -1.123456; const int validDigitsAfterComma = 6; // indicates the number of valid digits after comma of valueToWrite const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); double readValue; Setup(valueToWrite); readValueFromSetupDocument(readValue); CPPUNIT_ASSERT_MESSAGE("Testing if value valueToWrite equals readValue which was retrieved from TinyXML document", mitk::Equal(valueToWrite, readValue, neededPrecision)); } void TestDoubleValueWriteOutManyDecimalPlaces_Success() { const double valueToWrite = -1.12345678910111; const int validDigitsAfterComma = 14; // indicates the number of valid digits after comma of valueToWrite const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); double readValue; Setup(valueToWrite); readValueFromSetupDocument(readValue); CPPUNIT_ASSERT_MESSAGE("Testing if value valueToWrite equals readValue which was retrieved from TinyXML document", mitk::Equal(valueToWrite, readValue, neededPrecision)); } }; MITK_TEST_SUITE_REGISTRATION(mitkTinyXML) diff --git a/Modules/DICOM/CMakeLists.txt b/Modules/DICOM/CMakeLists.txt index 98d7de357c..ebff7f5798 100644 --- a/Modules/DICOM/CMakeLists.txt +++ b/Modules/DICOM/CMakeLists.txt @@ -1,9 +1,9 @@ MITK_CREATE_MODULE( DEPENDS MitkCore PACKAGE_DEPENDS - PUBLIC tinyxml GDCM - PRIVATE ITK|ITKIOImageBase+ITKIOGDCM DCMTK + PUBLIC GDCM tinyxml2 + PRIVATE DCMTK ITK|IOGDCM ) add_subdirectory(test) add_subdirectory(autoload/DICOMImageIO) diff --git a/Modules/DICOM/autoload/DICOMImageIO/CMakeLists.txt b/Modules/DICOM/autoload/DICOMImageIO/CMakeLists.txt index 53a0b7f3c2..147473ce52 100644 --- a/Modules/DICOM/autoload/DICOMImageIO/CMakeLists.txt +++ b/Modules/DICOM/autoload/DICOMImageIO/CMakeLists.txt @@ -1,6 +1,4 @@ MITK_CREATE_MODULE( DEPENDS MitkCore MitkDICOM - PACKAGE_DEPENDS - PRIVATE ITK|ITKIOGDCM+ITKIOImageBase AUTOLOAD_WITH MitkCore ) diff --git a/Modules/DICOM/include/mitkDICOMReaderConfigurator.h b/Modules/DICOM/include/mitkDICOMReaderConfigurator.h index e098ee4b85..00da6131c2 100644 --- a/Modules/DICOM/include/mitkDICOMReaderConfigurator.h +++ b/Modules/DICOM/include/mitkDICOMReaderConfigurator.h @@ -1,142 +1,145 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkDICOMReaderConfigurator_h #define mitkDICOMReaderConfigurator_h #include "mitkClassicDICOMSeriesReader.h" #include "mitkDICOMTagBasedSorter.h" -// to put into private implementation -#include "tinyxml.h" +namespace tinyxml2 +{ + class XMLDocument; + class XMLElement; +} namespace mitk { /** \ingroup DICOMModule \brief Too-simple factory to create DICOMFileReader%s. This class is able to instantiate and configure (where possible) DICOMFileReader%s from XML descriptions. \note This is a bad factory example, because the factory is not extensible and needs to know all the specific readers. A flexible implementation should be provided in a future version. In its current version, the XML input is meant to be structured like \verbatim \endverbatim The root-tag \c \ names the class to be instantiated, currently this can be one of - DICOMITKSeriesGDCMReader - ThreeDnTDICOMSeriesReader Both classes bring simple configuration flags with them and a description of how images are sorted prior to loading. Flag for DICOMITKSeriesGDCMReader:
fixTiltByShearing="true|false"
Determines whether a potential gantry tilt should be "fixed" by shearing the output image. Flag for ThreeDnTDICOMSeriesReader:
group3DnT="true|false"
Determines whether images at the same spatial position should be interpreted as 3D+t images. The tags \c \ and \c \ describe the basic loading strategy of both reader mentioned above: first images are divided into incompatible groups (\c \), and afterwards the images within each group are sorted by means of DICOMSortCriterion, which most commonly mentions a tag. Tag element and group are interpreted as the exadecimal numbers found all around the DICOM standard. The numbers can be prepended by a "0x" if this is preferred by the programmer (but they are taken as hexadecimal in all cases). \section DICOMReaderConfigurator_AboutTheFuture About the future evolution of this class This first version is hard coded for the current state of the implementation. If things should evolve in a way that needs us to splitt off readers for "old" versions, time should be taken to refactor this class. Basically, a serializer class should accompany each of the configurable classes. Such serializer classes should be registered and discovered via micro-services (to support extensions). A serializer should offer both methods to serialize a class and to desirialize it again. A "version" attribute at the top-level tag should be used to distinguish versions. Usually it should be enough to keep DE-serializers for all versions. Writers for the most recent version should be enough. */ class MITKDICOM_EXPORT DICOMReaderConfigurator : public itk::LightObject { public: mitkClassMacroItkParent( DICOMReaderConfigurator, itk::LightObject ); itkNewMacro( DICOMReaderConfigurator ); DICOMFileReader::Pointer CreateFromConfigFile(const std::string& filename) const; DICOMFileReader::Pointer CreateFromUTF8ConfigString(const std::string& xmlContents) const; std::string CreateConfigStringFromReader(DICOMFileReader::ConstPointer reader) const; protected: DICOMReaderConfigurator(); ~DICOMReaderConfigurator() override; private: - DICOMFileReader::Pointer CreateFromTiXmlDocument(TiXmlDocument& doc) const; - DICOMTag tagFromXMLElement(TiXmlElement*) const; - std::string requiredStringAttribute(TiXmlElement* xmlElement, const std::string& key) const; + DICOMFileReader::Pointer CreateFromXMLDocument(tinyxml2::XMLDocument& doc) const; + DICOMTag tagFromXMLElement(const tinyxml2::XMLElement*) const; + std::string requiredStringAttribute(const tinyxml2::XMLElement* xmlElement, const std::string& key) const; unsigned int hexStringToUInt(const std::string& s) const; - ThreeDnTDICOMSeriesReader::Pointer ConfigureThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement*) const; - DICOMITKSeriesGDCMReader::Pointer ConfigureDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement*) const; - void ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement* element) const; - void ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement* element) const; + ThreeDnTDICOMSeriesReader::Pointer ConfigureThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, const tinyxml2::XMLElement*) const; + DICOMITKSeriesGDCMReader::Pointer ConfigureDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, const tinyxml2::XMLElement*) const; + void ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, const tinyxml2::XMLElement* element) const; + void ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, const tinyxml2::XMLElement* element) const; + + DICOMSortCriterion::Pointer CreateDICOMSortByTag(const tinyxml2::XMLElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const; + DICOMSortCriterion::Pointer CreateSortByImagePositionPatient(const tinyxml2::XMLElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const; - DICOMSortCriterion::Pointer CreateDICOMSortByTag(TiXmlElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const; - DICOMSortCriterion::Pointer CreateSortByImagePositionPatient(TiXmlElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const; + mitk::DICOMTagBasedSorter::Pointer CreateDICOMTagBasedSorter(const tinyxml2::XMLElement* element) const; - mitk::DICOMTagBasedSorter::Pointer CreateDICOMTagBasedSorter(TiXmlElement* element) const; + tinyxml2::XMLElement* CreateConfigStringFromReader(tinyxml2::XMLDocument& doc, const DICOMITKSeriesGDCMReader* reader) const; + tinyxml2::XMLElement* CreateConfigStringFromReader(tinyxml2::XMLDocument& doc, const ThreeDnTDICOMSeriesReader* reader) const; + tinyxml2::XMLElement* CreateConfigStringFromReader(tinyxml2::XMLDocument& doc, const ClassicDICOMSeriesReader* reader) const; - TiXmlElement* CreateConfigStringFromReader(const DICOMITKSeriesGDCMReader* reader) const; - TiXmlElement* CreateConfigStringFromReader(const ThreeDnTDICOMSeriesReader* reader) const; - TiXmlElement* CreateConfigStringFromReader(const ClassicDICOMSeriesReader* reader) const; + tinyxml2::XMLElement* CreateConfigStringFromDICOMDatasetSorter(tinyxml2::XMLDocument& doc, const DICOMTagBasedSorter* sorter) const; - TiXmlElement* CreateConfigStringFromDICOMDatasetSorter(const DICOMTagBasedSorter* sorter) const; + tinyxml2::XMLElement* CreateConfigStringFromDICOMTag(tinyxml2::XMLDocument& doc, const DICOMTag& tag) const; - TiXmlElement* CreateConfigStringFromDICOMTag(const DICOMTag& tag) const; + tinyxml2::XMLElement* CreateDICOMFileReaderTag(tinyxml2::XMLDocument& doc, const DICOMFileReader* reader) const; - TiXmlElement* CreateDICOMFileReaderTag(const DICOMFileReader* reader) const; - const char* toString(bool) const; std::string toHexString(unsigned int i) const; /** Helper that queries an boolean xml attribute. If the attribute does not exist, the passed default value is used.*/ - bool QueryBooleanAttribute(const TiXmlElement* element, const char* attributeName, bool defaultValue) const; + bool QueryBooleanAttribute(const tinyxml2::XMLElement* element, const char* attributeName, bool defaultValue) const; }; } // namespace #endif // mitkDICOMReaderConfigurator_h diff --git a/Modules/DICOM/resource/configurations/3D/classicreader.xml b/Modules/DICOM/resource/configurations/3D/classicreader.xml index 7ed3332f6a..e5e063d39c 100644 --- a/Modules/DICOM/resource/configurations/3D/classicreader.xml +++ b/Modules/DICOM/resource/configurations/3D/classicreader.xml @@ -1,10 +1,10 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/imageposition.xml b/Modules/DICOM/resource/configurations/3D/imageposition.xml index c00d4cd8e2..09b55d3ecf 100644 --- a/Modules/DICOM/resource/configurations/3D/imageposition.xml +++ b/Modules/DICOM/resource/configurations/3D/imageposition.xml @@ -1,25 +1,25 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/imageposition_byacquisition.xml b/Modules/DICOM/resource/configurations/3D/imageposition_byacquisition.xml index 54b9f6377a..d145528099 100644 --- a/Modules/DICOM/resource/configurations/3D/imageposition_byacquisition.xml +++ b/Modules/DICOM/resource/configurations/3D/imageposition_byacquisition.xml @@ -1,26 +1,26 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/imagetime.xml b/Modules/DICOM/resource/configurations/3D/imagetime.xml index 83cdb1c1b0..62e97e455f 100644 --- a/Modules/DICOM/resource/configurations/3D/imagetime.xml +++ b/Modules/DICOM/resource/configurations/3D/imagetime.xml @@ -1,24 +1,24 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/instancenumber.xml b/Modules/DICOM/resource/configurations/3D/instancenumber.xml index f83b56e3c8..1fd86e4db6 100644 --- a/Modules/DICOM/resource/configurations/3D/instancenumber.xml +++ b/Modules/DICOM/resource/configurations/3D/instancenumber.xml @@ -1,24 +1,24 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/instancenumber_soft.xml b/Modules/DICOM/resource/configurations/3D/instancenumber_soft.xml index 1c2c660700..9cf61cbfcf 100644 --- a/Modules/DICOM/resource/configurations/3D/instancenumber_soft.xml +++ b/Modules/DICOM/resource/configurations/3D/instancenumber_soft.xml @@ -1,24 +1,24 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/simpleinstancenumber_soft.xml b/Modules/DICOM/resource/configurations/3D/simpleinstancenumber_soft.xml index 79c636e78b..eba6bbef60 100644 --- a/Modules/DICOM/resource/configurations/3D/simpleinstancenumber_soft.xml +++ b/Modules/DICOM/resource/configurations/3D/simpleinstancenumber_soft.xml @@ -1,25 +1,25 @@ - + diff --git a/Modules/DICOM/resource/configurations/3D/slicelocation.xml b/Modules/DICOM/resource/configurations/3D/slicelocation.xml index 967bb5af57..7ddb18d2f1 100644 --- a/Modules/DICOM/resource/configurations/3D/slicelocation.xml +++ b/Modules/DICOM/resource/configurations/3D/slicelocation.xml @@ -1,24 +1,24 @@ - + diff --git a/Modules/DICOM/resource/configurations/3DnT/classicreader.xml b/Modules/DICOM/resource/configurations/3DnT/classicreader.xml index 1a0ca7f09a..6d40321c7f 100644 --- a/Modules/DICOM/resource/configurations/3DnT/classicreader.xml +++ b/Modules/DICOM/resource/configurations/3DnT/classicreader.xml @@ -1,11 +1,11 @@ - + - \ No newline at end of file + diff --git a/Modules/DICOM/resource/configurations/3DnT/imageposition.xml b/Modules/DICOM/resource/configurations/3DnT/imageposition.xml index f8e1601952..a44d46cfc9 100644 --- a/Modules/DICOM/resource/configurations/3DnT/imageposition.xml +++ b/Modules/DICOM/resource/configurations/3DnT/imageposition.xml @@ -1,21 +1,21 @@ - + diff --git a/Modules/DICOM/resource/configurations/3DnT/imageposition_byacquisition.xml b/Modules/DICOM/resource/configurations/3DnT/imageposition_byacquisition.xml index 1a356abfb1..d6815044b6 100644 --- a/Modules/DICOM/resource/configurations/3DnT/imageposition_byacquisition.xml +++ b/Modules/DICOM/resource/configurations/3DnT/imageposition_byacquisition.xml @@ -1,19 +1,19 @@ - + - \ No newline at end of file + diff --git a/Modules/DICOM/resource/configurations/3DnT/imageposition_bytriggertime.xml b/Modules/DICOM/resource/configurations/3DnT/imageposition_bytriggertime.xml index f8f636255c..1a3f39fae4 100644 --- a/Modules/DICOM/resource/configurations/3DnT/imageposition_bytriggertime.xml +++ b/Modules/DICOM/resource/configurations/3DnT/imageposition_bytriggertime.xml @@ -1,19 +1,19 @@ - + - \ No newline at end of file + diff --git a/Modules/DICOM/src/mitkDICOMReaderConfigurator.cpp b/Modules/DICOM/src/mitkDICOMReaderConfigurator.cpp index 87e64e6c1c..68f7a4dccb 100644 --- a/Modules/DICOM/src/mitkDICOMReaderConfigurator.cpp +++ b/Modules/DICOM/src/mitkDICOMReaderConfigurator.cpp @@ -1,678 +1,673 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDICOMReaderConfigurator.h" #include "mitkDICOMSortByTag.h" #include "mitkSortByImagePositionPatient.h" +#include mitk::DICOMReaderConfigurator ::DICOMReaderConfigurator() { } mitk::DICOMReaderConfigurator ::~DICOMReaderConfigurator() { } mitk::DICOMFileReader::Pointer mitk::DICOMReaderConfigurator ::CreateFromConfigFile(const std::string& filename) const { - TiXmlDocument doc (filename); - if (doc.LoadFile()) + tinyxml2::XMLDocument doc; + if (tinyxml2::XML_SUCCESS == doc.LoadFile(filename.c_str())) { - return this->CreateFromTiXmlDocument( doc ); + return this->CreateFromXMLDocument( doc ); } else { MITK_ERROR << "Unable to load file at '" << filename <<"'"; return DICOMFileReader::Pointer(); } } mitk::DICOMFileReader::Pointer mitk::DICOMReaderConfigurator ::CreateFromUTF8ConfigString(const std::string& xmlContents) const { - TiXmlDocument doc; - doc.Parse(xmlContents.c_str(), nullptr, TIXML_ENCODING_UTF8); + tinyxml2::XMLDocument doc; + doc.Parse(xmlContents.c_str()); - return this->CreateFromTiXmlDocument( doc ); + return this->CreateFromXMLDocument( doc ); } mitk::DICOMFileReader::Pointer mitk::DICOMReaderConfigurator -::CreateFromTiXmlDocument(TiXmlDocument& doc) const +::CreateFromXMLDocument(tinyxml2::XMLDocument& doc) const { - TiXmlHandle root(doc.RootElement()); + tinyxml2::XMLHandle root(doc.RootElement()); - if (TiXmlElement* rootElement = root.ToElement()) + if (auto* rootElement = root.ToElement()) { if (strcmp(rootElement->Value(), "DICOMFileReader")) // :-( no std::string methods { MITK_ERROR << "File should contain a tag at top-level! Found '" << (rootElement->Value() ? std::string(rootElement->Value()) : std::string("!nothing!")) << "' instead"; return nullptr; } const char* classnameC = rootElement->Attribute("class"); if (!classnameC) { MITK_ERROR << "File should name a reader class in the class attribute: . Found nothing instead"; return nullptr; } int version(1); - if ( rootElement->QueryIntAttribute("version", &version) == TIXML_SUCCESS) + if ( rootElement->QueryIntAttribute("version", &version) == tinyxml2::XML_SUCCESS) { if (version == 1) { MITK_WARN << "Warning the given configuration is for DICOMFileReaders of version 1. " << "This old version may be interpreted differently. Reason: " << "The default values for the following xml settings have been changed: " << "FixTiltByShearing (false -> true); StrictSorting (true -> false); ExpectDistanceOne (true -> false)."; } else if (version >2) { MITK_WARN << "This reader is only capable of creating DICOMFileReaders of version 1 and 2. " << "Will not continue, because given configuration is meant for version " << version << "."; return nullptr; } } else { MITK_ERROR << "File should name the version of the reader class in the version attribute: ." << " Found nothing instead, assuming version 1!"; version = 1; } std::string classname(classnameC); double decimalPlacesForOrientation(mitk::DICOMITKSeriesGDCMReader::GetDefaultDecimalPlacesForOrientation()); bool useDecimalPlacesForOrientation(false); useDecimalPlacesForOrientation = - rootElement->QueryDoubleAttribute("decimalPlacesForOrientation", &decimalPlacesForOrientation) == TIXML_SUCCESS; // attribute present and a double value + rootElement->QueryDoubleAttribute("decimalPlacesForOrientation", &decimalPlacesForOrientation) == tinyxml2::XML_SUCCESS; // attribute present and a double value if (classname == "ClassicDICOMSeriesReader") { mitk::ClassicDICOMSeriesReader::Pointer reader = mitk::ClassicDICOMSeriesReader::New(); this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader.GetPointer(), rootElement); this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader.GetPointer(), rootElement); return reader.GetPointer(); } if (classname == "ThreeDnTDICOMSeriesReader") { mitk::ThreeDnTDICOMSeriesReader::Pointer reader; if (useDecimalPlacesForOrientation) reader = mitk::ThreeDnTDICOMSeriesReader::New(decimalPlacesForOrientation); else reader = mitk::ThreeDnTDICOMSeriesReader::New(); return ConfigureThreeDnTDICOMSeriesReader(reader, rootElement).GetPointer(); } else if (classname == "DICOMITKSeriesGDCMReader") { bool simpleVolumeImport = QueryBooleanAttribute(rootElement, "simpleVolumeImport", mitk::DICOMITKSeriesGDCMReader::GetDefaultSimpleVolumeImport()); mitk::DICOMITKSeriesGDCMReader::Pointer reader; if (useDecimalPlacesForOrientation) reader = mitk::DICOMITKSeriesGDCMReader::New( decimalPlacesForOrientation, simpleVolumeImport ); else reader = mitk::DICOMITKSeriesGDCMReader::New( mitk::DICOMITKSeriesGDCMReader::GetDefaultDecimalPlacesForOrientation(), simpleVolumeImport ); // simple volume import that ignores number of frames and inter slice distance return ConfigureDICOMITKSeriesGDCMReader(reader, rootElement).GetPointer(); } else { MITK_ERROR << "DICOMFileReader tag names unknown class '" << classname << "'"; return nullptr; } } else { MITK_ERROR << "Great confusion: no root element in XML document. Expecting a DICOMFileReader tag at top-level."; return nullptr; } } #define boolStringTrue(s) \ ( s == "true" || s == "on" || s == "1" \ || s == "TRUE" || s == "ON") bool mitk::DICOMReaderConfigurator -::QueryBooleanAttribute(const TiXmlElement* element, const char* attributeName, bool defaultValue) const +::QueryBooleanAttribute(const tinyxml2::XMLElement* element, const char* attributeName, bool defaultValue) const { bool value(defaultValue); - const char* valueC = element->Attribute(attributeName); - if (valueC) + const auto* valueC = element->Attribute(attributeName); + + if (nullptr != valueC) { - std::string valueS(valueC); + std::string valueS = valueC; value = boolStringTrue(valueS); } + return value; } void mitk::DICOMReaderConfigurator -::ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement* element) const +::ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, const tinyxml2::XMLElement* element) const { // add the "group3DnT" flag bool group3DnT = QueryBooleanAttribute(element, "group3DnT", ThreeDnTDICOMSeriesReader::GetDefaultGroup3DandT()); reader->SetGroup3DandT( group3DnT ); // add the "onlyCondenseSameSeries" flag bool onlyCondenseSameSeries = QueryBooleanAttribute(element, "onlyCondenseSameSeries", ThreeDnTDICOMSeriesReader::GetDefaultOnlyCondenseSameSeries()); reader->SetOnlyCondenseSameSeries(onlyCondenseSameSeries); } mitk::ThreeDnTDICOMSeriesReader::Pointer mitk::DICOMReaderConfigurator -::ConfigureThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, TiXmlElement* element) const +::ConfigureThreeDnTDICOMSeriesReader(ThreeDnTDICOMSeriesReader::Pointer reader, const tinyxml2::XMLElement* element) const { assert(element); // use all the base class configuration if (this->ConfigureDICOMITKSeriesGDCMReader( reader.GetPointer(), element ).IsNull()) { return nullptr; } this->ConfigureCommonPropertiesOfThreeDnTDICOMSeriesReader(reader,element); return reader; } void mitk::DICOMReaderConfigurator -::ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement* element) const +::ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, const tinyxml2::XMLElement* element) const { assert(element); const char* configLabelC = element->Attribute("label"); if (configLabelC) { std::string configLabel(configLabelC); reader->SetConfigurationLabel(configLabel); } const char* configDescriptionC = element->Attribute("description"); if (configDescriptionC) { reader->SetConfigurationDescription(configDescriptionC); } // "fixTiltByShearing" flag bool fixTiltByShearing = QueryBooleanAttribute(element, "fixTiltByShearing", DICOMITKSeriesGDCMReader::GetDefaultFixTiltByShearing()); reader->SetFixTiltByShearing( fixTiltByShearing ); } mitk::DICOMITKSeriesGDCMReader::Pointer mitk::DICOMReaderConfigurator -::ConfigureDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, TiXmlElement* element) const +::ConfigureDICOMITKSeriesGDCMReader(DICOMITKSeriesGDCMReader::Pointer reader, const tinyxml2::XMLElement* element) const { assert(element); this->ConfigureCommonPropertiesOfDICOMITKSeriesGDCMReader(reader, element); // "acceptTwoSlicesGroups" flag bool acceptTwoSlicesGroups = QueryBooleanAttribute(element, "acceptTwoSlicesGroups", true); reader->SetAcceptTwoSlicesGroups( acceptTwoSlicesGroups ); // "toleratedOriginError" attribute (double) bool toleratedOriginErrorIsAbsolute = QueryBooleanAttribute(element, "toleratedOriginErrorIsAbsolute", false); double toleratedOriginError(0.3); - if (element->QueryDoubleAttribute("toleratedOriginError", &toleratedOriginError) == TIXML_SUCCESS) // attribute present and a double value + if (element->QueryDoubleAttribute("toleratedOriginError", &toleratedOriginError) == tinyxml2::XML_SUCCESS) // attribute present and a double value { if (toleratedOriginErrorIsAbsolute) { reader->SetToleratedOriginOffset( toleratedOriginError ); } else { reader->SetToleratedOriginOffsetToAdaptive( toleratedOriginError ); } } // DICOMTagBasedSorters are the only thing we create at this point // TODO for-loop over all child elements of type DICOMTagBasedSorter, BUT actually a single sorter of this type is enough. - TiXmlElement* dElement = element->FirstChildElement("DICOMDatasetSorter"); + auto* dElement = element->FirstChildElement("DICOMDatasetSorter"); if (dElement) { const char* classnameC = dElement->Attribute("class"); if (!classnameC) { MITK_ERROR << "File should name a DICOMDatasetSorter class in the class attribute of . Found nothing instead"; return nullptr; } std::string classname(classnameC); if (classname == "DICOMTagBasedSorter") { DICOMTagBasedSorter::Pointer tagSorter = CreateDICOMTagBasedSorter(dElement); if (tagSorter.IsNotNull()) { reader->AddSortingElement( tagSorter ); } } else { MITK_ERROR << "DICOMDatasetSorter tag names unknown class '" << classname << "'"; return nullptr; } } return reader; } mitk::DICOMTagBasedSorter::Pointer mitk::DICOMReaderConfigurator -::CreateDICOMTagBasedSorter(TiXmlElement* element) const +::CreateDICOMTagBasedSorter(const tinyxml2::XMLElement* element) const { mitk::DICOMTagBasedSorter::Pointer tagSorter = mitk::DICOMTagBasedSorter::New(); // "strictSorting" parameter! bool strictSorting = QueryBooleanAttribute(element, "strictSorting", mitk::DICOMTagBasedSorter::GetDefaultStrictSorting()); tagSorter->SetStrictSorting(strictSorting); // "strictSorting" parameter! bool expectDistanceOne = QueryBooleanAttribute(element, "expectDistanceOne", mitk::DICOMTagBasedSorter::GetDefaultExpectDistanceOne()); tagSorter->SetExpectDistanceOne(expectDistanceOne); - TiXmlElement* dElement = element->FirstChildElement("Distinguishing"); + auto* dElement = element->FirstChildElement("Distinguishing"); if (dElement) { - for ( TiXmlElement* tChild = dElement->FirstChildElement(); + for ( auto* tChild = dElement->FirstChildElement(); tChild != nullptr; tChild = tChild->NextSiblingElement() ) { try { mitk::DICOMTag tag = tagFromXMLElement(tChild); int i(5); - if (tChild->QueryIntAttribute("cutDecimalPlaces", &i) == TIXML_SUCCESS) + if (tChild->QueryIntAttribute("cutDecimalPlaces", &i) == tinyxml2::XML_SUCCESS) { tagSorter->AddDistinguishingTag( tag, new mitk::DICOMTagBasedSorter::CutDecimalPlaces(i) ); } else { tagSorter->AddDistinguishingTag( tag ); } } catch(...) { return nullptr; } } } // "sorting tags" - TiXmlElement* sElement = element->FirstChildElement("Sorting"); + auto* sElement = element->FirstChildElement("Sorting"); if (sElement) { DICOMSortCriterion::Pointer previousCriterion; DICOMSortCriterion::Pointer currentCriterion; - for ( TiXmlNode* tChildNode = sElement->LastChild(); + for ( auto* tChildNode = sElement->LastChild(); tChildNode != nullptr; tChildNode = tChildNode->PreviousSibling() ) { - TiXmlElement* tChild = tChildNode->ToElement(); + auto* tChild = tChildNode->ToElement(); if (!tChild) continue; if (!strcmp(tChild->Value(), "Tag")) { try { currentCriterion = this->CreateDICOMSortByTag(tChild, previousCriterion); } catch(...) { std::stringstream ss; - ss << "Could not parse element at (input line " << tChild->Row() << ", col. " << tChild->Column() << ")!"; + ss << "Could not parse element at input line " << tChild->GetLineNum() << "!"; MITK_ERROR << ss.str(); return nullptr; } } else if (!strcmp(tChild->Value(), "ImagePositionPatient")) { try { currentCriterion = this->CreateSortByImagePositionPatient(tChild, previousCriterion); } catch(...) { std::stringstream ss; - ss << "Could not parse element at (input line " << tChild->Row() << ", col. " << tChild->Column() << ")!"; + ss << "Could not parse element at input line " << tChild->GetLineNum() << "!"; MITK_ERROR << ss.str(); return nullptr; } } else { MITK_ERROR << "File contain unknown tag <" << tChild->Value() << "> tag as child to ! Cannot interpret..."; } previousCriterion = currentCriterion; } tagSorter->SetSortCriterion( currentCriterion.GetPointer() ); } return tagSorter; } std::string mitk::DICOMReaderConfigurator -::requiredStringAttribute(TiXmlElement* xmlElement, const std::string& key) const +::requiredStringAttribute(const tinyxml2::XMLElement* xmlElement, const std::string& key) const { assert(xmlElement); const char* gC = xmlElement->Attribute(key.c_str()); if (gC) { std::string gS(gC); return gS; } else { std::stringstream ss; - ss << "Expected an attribute '" << key << "' at this position " - "(input line " << xmlElement->Row() << ", col. " << xmlElement->Column() << ")!"; + ss << "Expected an attribute '" << key << "' at " + "input line " << xmlElement->GetLineNum() << "!"; MITK_ERROR << ss.str(); throw std::invalid_argument( ss.str() ); } } unsigned int mitk::DICOMReaderConfigurator ::hexStringToUInt(const std::string& s) const { std::stringstream converter(s); unsigned int ui; converter >> std::hex >> ui; MITK_DEBUG << "Converted string '" << s << "' to unsigned int " << ui; return ui; } mitk::DICOMTag mitk::DICOMReaderConfigurator -::tagFromXMLElement(TiXmlElement* xmlElement) const +::tagFromXMLElement(const tinyxml2::XMLElement* xmlElement) const { assert(xmlElement); if (strcmp(xmlElement->Value(), "Tag")) // :-( no std::string methods { std::stringstream ss; - ss << "Expected a tag at this position " - "(input line " << xmlElement->Row() << ", col. " << xmlElement->Column() << ")!"; + ss << "Expected a tag at " + "input line " << xmlElement->GetLineNum() << "!"; MITK_ERROR << ss.str(); throw std::invalid_argument( ss.str() ); } std::string groupS = requiredStringAttribute(xmlElement, "group"); std::string elementS = requiredStringAttribute(xmlElement, "element"); try { // convert string to int (assuming string is in hex format with leading "0x" like "0x0020") unsigned int group = hexStringToUInt(groupS); unsigned int element = hexStringToUInt(elementS); return DICOMTag(group, element); } catch(...) { std::stringstream ss; ss << "Expected group and element values in to be hexadecimal with leading 0x, e.g. '0x0020'" - "(input line " << xmlElement->Row() << ", col. " << xmlElement->Column() << ")!"; + "(input line " << xmlElement->GetLineNum() << ")!"; MITK_ERROR << ss.str(); throw std::invalid_argument( ss.str() ); } } mitk::DICOMSortCriterion::Pointer mitk::DICOMReaderConfigurator -::CreateDICOMSortByTag(TiXmlElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const +::CreateDICOMSortByTag(const tinyxml2::XMLElement* xmlElement, DICOMSortCriterion::Pointer secondaryCriterion) const { mitk::DICOMTag tag = tagFromXMLElement(xmlElement); return DICOMSortByTag::New(tag, secondaryCriterion).GetPointer(); } mitk::DICOMSortCriterion::Pointer mitk::DICOMReaderConfigurator -::CreateSortByImagePositionPatient(TiXmlElement*, DICOMSortCriterion::Pointer secondaryCriterion) const +::CreateSortByImagePositionPatient(const tinyxml2::XMLElement*, DICOMSortCriterion::Pointer secondaryCriterion) const { return SortByImagePositionPatient::New(secondaryCriterion).GetPointer(); } std::string mitk::DICOMReaderConfigurator ::CreateConfigStringFromReader(DICOMFileReader::ConstPointer reader) const { // check possible sub-classes from the most-specific one up to the most generic one const DICOMFileReader* cPointer = reader; - TiXmlElement* root; + tinyxml2::XMLDocument document; + tinyxml2::XMLElement* root = nullptr; if (const auto* specificReader = dynamic_cast(cPointer)) { - root = this->CreateConfigStringFromReader(specificReader); + root = this->CreateConfigStringFromReader(document, specificReader); } else if (const auto* specificReader = dynamic_cast(cPointer)) { - root = this->CreateConfigStringFromReader(specificReader); + root = this->CreateConfigStringFromReader(document, specificReader); } else if (const auto* specificReader = dynamic_cast(cPointer)) { - root = this->CreateConfigStringFromReader(specificReader); + root = this->CreateConfigStringFromReader(document, specificReader); } else { MITK_WARN << "Unknown reader class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize."; return ""; // no serialization, what a pity } - if (root) + if (nullptr != root) { - TiXmlDocument document; - document.LinkEndChild( root ); + document.InsertEndChild( root ); - TiXmlPrinter printer; - printer.SetIndent( " " ); + tinyxml2::XMLPrinter printer; + document.Print(&printer); - document.Accept( &printer ); std::string xmltext = printer.CStr(); return xmltext; } else { MITK_WARN << "DICOMReaderConfigurator::CreateConfigStringFromReader() created empty serialization. Problem?"; return ""; } } -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateConfigStringFromReader(const DICOMITKSeriesGDCMReader* reader) const +::CreateConfigStringFromReader(tinyxml2::XMLDocument &doc, const DICOMITKSeriesGDCMReader* reader) const { - TiXmlElement* root = this->CreateDICOMFileReaderTag(reader); + auto* root = this->CreateDICOMFileReaderTag(doc, reader); assert(root); - root->SetAttribute("fixTiltByShearing", toString(reader->GetFixTiltByShearing())); - root->SetAttribute("acceptTwoSlicesGroups", toString(reader->GetAcceptTwoSlicesGroups())); - root->SetDoubleAttribute("toleratedOriginError", reader->GetToleratedOriginError()); - root->SetAttribute("toleratedOriginErrorIsAbsolute", toString(reader->IsToleratedOriginOffsetAbsolute())); - root->SetDoubleAttribute("decimalPlacesForOrientation", reader->GetDecimalPlacesForOrientation()); + root->SetAttribute("fixTiltByShearing", reader->GetFixTiltByShearing()); + root->SetAttribute("acceptTwoSlicesGroups", reader->GetAcceptTwoSlicesGroups()); + root->SetAttribute("toleratedOriginError", reader->GetToleratedOriginError()); + root->SetAttribute("toleratedOriginErrorIsAbsolute", reader->IsToleratedOriginOffsetAbsolute()); + root->SetAttribute("decimalPlacesForOrientation", reader->GetDecimalPlacesForOrientation()); // iterate DICOMDatasetSorter objects DICOMITKSeriesGDCMReader::ConstSorterList sorterList = reader->GetFreelyConfiguredSortingElements(); for(auto sorterIter = sorterList.begin(); sorterIter != sorterList.end(); ++sorterIter) { const DICOMDatasetSorter* sorter = *sorterIter; if (const auto* specificSorter = dynamic_cast(sorter)) { - TiXmlElement* sorterTag = this->CreateConfigStringFromDICOMDatasetSorter(specificSorter); - root->LinkEndChild(sorterTag); + auto* sorterTag = this->CreateConfigStringFromDICOMDatasetSorter(doc, specificSorter); + root->InsertEndChild(sorterTag); } else { MITK_WARN << "Unknown DICOMDatasetSorter class passed to DICOMReaderConfigurator::CreateConfigStringFromReader(). Cannot serialize."; return nullptr; } } return root; } -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateConfigStringFromDICOMDatasetSorter(const DICOMTagBasedSorter* sorter) const +::CreateConfigStringFromDICOMDatasetSorter(tinyxml2::XMLDocument &doc, const DICOMTagBasedSorter* sorter) const { assert(sorter); - auto sorterTag = new TiXmlElement("DICOMDatasetSorter"); + auto *sorterTag = doc.NewElement("DICOMDatasetSorter"); sorterTag->SetAttribute("class", sorter->GetNameOfClass()); - sorterTag->SetAttribute("strictSorting", toString(sorter->GetStrictSorting())); - sorterTag->SetAttribute("expectDistanceOne", toString(sorter->GetExpectDistanceOne())); + sorterTag->SetAttribute("strictSorting", sorter->GetStrictSorting()); + sorterTag->SetAttribute("expectDistanceOne", sorter->GetExpectDistanceOne()); - auto distinguishingTagsElement = new TiXmlElement("Distinguishing"); - sorterTag->LinkEndChild(distinguishingTagsElement); + auto *distinguishingTagsElement = doc.NewElement("Distinguishing"); + sorterTag->InsertEndChild(distinguishingTagsElement); mitk::DICOMTagList distinguishingTags = sorter->GetDistinguishingTags(); for (auto tagIter = distinguishingTags.begin(); tagIter != distinguishingTags.end(); ++tagIter) { - TiXmlElement* tag = this->CreateConfigStringFromDICOMTag(*tagIter); - distinguishingTagsElement->LinkEndChild(tag); + auto* tag = this->CreateConfigStringFromDICOMTag(doc, *tagIter); + distinguishingTagsElement->InsertEndChild(tag); const DICOMTagBasedSorter::TagValueProcessor* processor = sorter->GetTagValueProcessorForDistinguishingTag(*tagIter); if (const auto* specificProcessor = dynamic_cast(processor)) { - tag->SetDoubleAttribute("cutDecimalPlaces", specificProcessor->GetPrecision()); + tag->SetAttribute("cutDecimalPlaces", specificProcessor->GetPrecision()); } } - auto sortingElement = new TiXmlElement("Sorting"); - sorterTag->LinkEndChild(sortingElement); + auto *sortingElement = doc.NewElement("Sorting"); + sorterTag->InsertEndChild(sortingElement); mitk::DICOMSortCriterion::ConstPointer sortCriterion = sorter->GetSortCriterion(); while (sortCriterion.IsNotNull()) { std::string classname = sortCriterion->GetNameOfClass(); if (classname == "SortByImagePositionPatient") { - sortingElement->LinkEndChild( new TiXmlElement("ImagePositionPatient") ); // no parameters + sortingElement->InsertEndChild( doc.NewElement("ImagePositionPatient") ); // no parameters } else if (classname == "DICOMSortByTag") { DICOMTagList pseudoTagList = sortCriterion->GetTagsOfInterest(); if (pseudoTagList.size() == 1) { DICOMTag firstTag = pseudoTagList.front(); - TiXmlElement* tagElement = this->CreateConfigStringFromDICOMTag(firstTag); + auto* tagElement = this->CreateConfigStringFromDICOMTag(doc, firstTag); - sortingElement->LinkEndChild( tagElement ); + sortingElement->InsertEndChild( tagElement ); } else { MITK_ERROR << "Encountered SortByTag class with MULTIPLE tag in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize."; return nullptr; } } else { MITK_ERROR << "Encountered unknown class '" << classname << "' in CreateConfigStringFromDICOMDatasetSorter. Cannot serialize."; return nullptr; } sortCriterion = sortCriterion->GetSecondaryCriterion(); } return sorterTag; } -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateConfigStringFromDICOMTag(const DICOMTag& tag) const +::CreateConfigStringFromDICOMTag(tinyxml2::XMLDocument& doc, const DICOMTag& tag) const { - auto tagElement = new TiXmlElement("Tag"); // name group element + auto tagElement = doc.NewElement("Tag"); // name group element tagElement->SetAttribute("name", tag.GetName().c_str()); - tagElement->SetAttribute("group", toHexString(tag.GetGroup())); - tagElement->SetAttribute("element", toHexString(tag.GetElement())); + tagElement->SetAttribute("group", toHexString(tag.GetGroup()).c_str()); + tagElement->SetAttribute("element", toHexString(tag.GetElement()).c_str()); return tagElement; } std::string mitk::DICOMReaderConfigurator ::toHexString(unsigned int i) const { std::stringstream ss; ss << "0x" << std::setfill ('0') << std::setw(4) << std::hex << i; return ss.str(); } -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateConfigStringFromReader(const ThreeDnTDICOMSeriesReader* reader) const +::CreateConfigStringFromReader(tinyxml2::XMLDocument& doc, const ThreeDnTDICOMSeriesReader* reader) const { - TiXmlElement* root = this->CreateConfigStringFromReader(static_cast(reader)); + auto* root = this->CreateConfigStringFromReader(doc, static_cast(reader)); assert(root); - root->SetAttribute("group3DnT", toString(reader->GetGroup3DandT())); + root->SetAttribute("group3DnT", reader->GetGroup3DandT()); return root; } -const char* -mitk::DICOMReaderConfigurator -::toString(bool b) const -{ - return b ? "true" : "false"; -} - -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateConfigStringFromReader(const ClassicDICOMSeriesReader* reader) const +::CreateConfigStringFromReader(tinyxml2::XMLDocument& doc, const ClassicDICOMSeriesReader* reader) const { - return this->CreateDICOMFileReaderTag(reader); + return this->CreateDICOMFileReaderTag(doc, reader); } -TiXmlElement* +tinyxml2::XMLElement* mitk::DICOMReaderConfigurator -::CreateDICOMFileReaderTag(const DICOMFileReader* reader) const +::CreateDICOMFileReaderTag(tinyxml2::XMLDocument& doc, const DICOMFileReader* reader) const { - auto readerTag = new TiXmlElement("DICOMFileReader"); + auto readerTag = doc.NewElement("DICOMFileReader"); readerTag->SetAttribute("class", reader->GetNameOfClass()); readerTag->SetAttribute("label", reader->GetConfigurationLabel().c_str()); readerTag->SetAttribute("description", reader->GetConfigurationDescription().c_str()); readerTag->SetAttribute("version", "1"); return readerTag; } diff --git a/Modules/DICOMTesting/CMakeLists.txt b/Modules/DICOMTesting/CMakeLists.txt index d0d96f0e67..857f5a39a1 100644 --- a/Modules/DICOMTesting/CMakeLists.txt +++ b/Modules/DICOMTesting/CMakeLists.txt @@ -1,43 +1,43 @@ if(BUILD_TESTING) if(GDCM_DIR) # clear variables from prior files.cmake # Else CMake would use the content of these variables and would try to create tests (which are not present in DICOMTesting). set(MODULE_TESTS) set(MODULE_IMAGE_TESTS) set(MODULE_SURFACE_TESTS) set(MODULE_TESTIMAGE) set(MODULE_TESTSURFACE) set(MODULE_CUSTOM_TESTS) set(H_FILES) set(CPP_FILES) # now create a new module only for testing purposes MITK_CREATE_MODULE( DEPENDS MitkDICOM PACKAGE_DEPENDS - PRIVATE GDCM DCMTK ITK|ITKIOGDCM + PRIVATE GDCM DCMTK ITK|IOGDCM ) mitk_check_module_dependencies(MODULES MitkDICOMTesting MISSING_DEPENDENCIES_VAR _missing_deps) if(_missing_deps) message(STATUS "mitkDICOMTesting module helper applications won't be built. Missing: ${_missing_deps}") else(_missing_deps) # dumps out image information add_executable(DumpDICOMMitkImage src/DumpDICOMMitkImage.cpp) mitk_use_modules(TARGET DumpDICOMMitkImage MODULES MitkDICOMTesting) # compares dumped out image information against reference dump add_executable(VerifyDICOMMitkImageDump src/VerifyDICOMMitkImageDump.cpp) mitk_use_modules(TARGET VerifyDICOMMitkImageDump MODULES MitkDICOMTesting) set_property(TARGET DumpDICOMMitkImage VerifyDICOMMitkImageDump PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Tests") add_subdirectory(test) endif() endif() endif() diff --git a/Modules/DataTypesExt/CMakeLists.txt b/Modules/DataTypesExt/CMakeLists.txt index f9af619a57..841888032d 100644 --- a/Modules/DataTypesExt/CMakeLists.txt +++ b/Modules/DataTypesExt/CMakeLists.txt @@ -1,14 +1,6 @@ -set(_additional_libs) -if(USE_ITKZLIB) - list(APPEND _additional_libs itkzlib) -else() - list(APPEND _additional_libs z) -endif(USE_ITKZLIB) - -MITK_CREATE_MODULE(DEPENDS MitkCore - PACKAGE_DEPENDS PRIVATE ITK|ITKIOImageBase - ADDITIONAL_LIBS ${_additional_libs} - ) +mitk_create_module( + DEPENDS MitkCore + PACKAGE_DEPENDS PRIVATE ITK|ZLIB +) add_subdirectory(test) - diff --git a/Modules/IGT/CMakeLists.txt b/Modules/IGT/CMakeLists.txt index 760efba59f..51ae8db7fe 100644 --- a/Modules/IGT/CMakeLists.txt +++ b/Modules/IGT/CMakeLists.txt @@ -1,63 +1,61 @@ include(MITKIGTHardware.cmake) if(MITK_USE_MICRON_TRACKER) set(ADDITIONAL_INCLUDE_DIRS ${ADDITIONAL_INCLUDE_DIRS} ${MITK_MICRON_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_MICRON_TRACKER_LIB}) endif(MITK_USE_MICRON_TRACKER) if(MITK_USE_OPTITRACK_TRACKER) set(ADDITIONAL_INCLUDE_DIRS ${ADDITIONAL_INCLUDE_DIRS} ${MITK_OPTITRACK_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_OPTITRACK_TRACKER_LIB}) add_definitions( -DMITK_USE_OPTITRACK_TRACKER ) endif(MITK_USE_OPTITRACK_TRACKER) if(MITK_USE_MICROBIRD_TRACKER) set(ADDITIONAL_INCLUDE_DIRS ${ADDITIONAL_INCLUDE_DIRS} ${MITK_USE_MICROBIRD_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_USE_MICROBIRD_TRACKER_LIB}) endif(MITK_USE_MICROBIRD_TRACKER) if(MITK_USE_POLHEMUS_TRACKER) set(ADDITIONAL_INCLUDE_DIRS ${ADDITIONAL_INCLUDE_DIRS} ${MITK_POLHEMUS_TRACKER_INCLUDE_DIR}) set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} ${MITK_POLHEMUS_TRACKER_LIB}) endif(MITK_USE_POLHEMUS_TRACKER) MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC Algorithms Common DataManagement ExceptionHandling IO Rendering TrackingDevices TestingHelper PRIVATE ${ADDITIONAL_INCLUDE_DIRS} DEPENDS PUBLIC MitkImageStatistics MitkSceneSerialization MitkIGTBase MitkOpenIGTLink - PACKAGE_DEPENDS ITK|ITKRegistrationCommon tinyxml OpenIGTLink + PACKAGE_DEPENDS PRIVATE ITK|RegistrationCommon OpenIGTLink tinyxml2 ADDITIONAL_LIBS "${ADDITIONAL_LIBS}" ) if(MitkIGT_IS_ENABLED) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/ClaronMicron.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/IntuitiveDaVinci.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAurora.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAurora_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraCompactFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraPlanarFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraTabletopFG_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIAuroraTabletopFG_Prototype_Dome.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisOldModel.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisSpectra.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisSpectraExtendedPyramid.stl ) MITK_INSTALL(FILES ${MITK_SOURCE_DIR}/Modules/IGT/Resources/NDIPolarisVicra.stl ) endif() if(NOT MODULE_IS_ENABLED) message(STATUS "IGTTutorialStep1 won't be built. Missing: ${_RESULT}") else() ## create IGT config configure_file(mitkIGTConfig.h.in ${PROJECT_BINARY_DIR}/mitkIGTConfig.h @ONLY) -# add test programm for serial communication classADD_EXECUTABLE(SerialCommunicationTest IGTTrackingDevices/mitkSerialCommunicationTest.cpp)target_link_libraries(SerialCommunicationTest mitkIGT Mitk tinyxml PocoXML) - add_subdirectory(autoload/DeviceRegistry) add_subdirectory(Tutorial) add_subdirectory(Testing) endif() diff --git a/Modules/IGT/IO/mitkNavigationDataRecorderDeprecated.cpp b/Modules/IGT/IO/mitkNavigationDataRecorderDeprecated.cpp index c10728cf92..0f9609216a 100644 --- a/Modules/IGT/IO/mitkNavigationDataRecorderDeprecated.cpp +++ b/Modules/IGT/IO/mitkNavigationDataRecorderDeprecated.cpp @@ -1,362 +1,364 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkNavigationDataRecorderDeprecated.h" #include #include -#include +#include #include //headers for exceptions #include "mitkIGTException.h" #include "mitkIGTIOException.h" mitk::NavigationDataRecorderDeprecated::NavigationDataRecorderDeprecated() { //set default values m_NumberOfInputs = 0; m_RecordingMode = NormalFile; m_Recording = false; m_NumberOfRecordedFiles = 0; m_Stream = nullptr; m_FileName = ""; m_SystemTimeClock = RealTimeClock::New(); m_OutputFormat = mitk::NavigationDataRecorderDeprecated::xml; m_RecordCounter = 0; m_RecordCountLimit = -1; m_DoNotOverwriteFiles = false; m_StreamMustBeDeleted = false; //To get a start time mitk::IGTTimeStamp::GetInstance()->Start(this); } mitk::NavigationDataRecorderDeprecated::~NavigationDataRecorderDeprecated() { } void mitk::NavigationDataRecorderDeprecated::GenerateData() { } void mitk::NavigationDataRecorderDeprecated::AddNavigationData( const NavigationData* nd ) { // Process object is not const-correct so the const_cast is required here this->SetNthInput(m_NumberOfInputs, const_cast< mitk::NavigationData * >( nd ) ); m_NumberOfInputs++; this->Modified(); } void mitk::NavigationDataRecorderDeprecated::SetRecordingMode( RecordingMode mode ) { m_RecordingMode = mode; this->Modified(); } void mitk::NavigationDataRecorderDeprecated::Update() { if (m_Recording) { DataObjectPointerArray inputs = this->GetInputs(); //get all inputs mitk::NavigationData::TimeStampType timestamp=0.0; // timestamp for mitk time timestamp = mitk::IGTTimeStamp::GetInstance()->GetElapsed(); mitk::NavigationData::TimeStampType sysTimestamp = 0.0; // timestamp for system time sysTimestamp = m_SystemTimeClock->GetCurrentStamp(); // cast system time double value to stringstream to avoid low precision rounding std::ostringstream strs; strs.precision(15); // rounding precision for system time double value strs << sysTimestamp; std::string sysTimeStr = strs.str(); //if csv-mode: write csv header and timestamp at beginning if (m_OutputFormat == mitk::NavigationDataRecorderDeprecated::csv) { //write header only when it's the first line if (m_firstLine) { m_firstLine = false; *m_Stream << "TimeStamp"; for (unsigned int index = 0; index < inputs.size(); index++){ *m_Stream << ";Valid_Tool" << index << ";X_Tool" << index << ";Y_Tool" << index << ";Z_Tool" << index << ";QX_Tool" << index << ";QY_Tool" << index << ";QZ_Tool" << index << ";QR_Tool" << index;} *m_Stream << "\n"; } //write timestamp (always) *m_Stream << timestamp; } //write tool data for every tool for (unsigned int index = 0; index < inputs.size(); index++) { mitk::NavigationData* nd = dynamic_cast(inputs[index].GetPointer()); nd->Update(); // call update to propagate update to previous filters mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0, 0.0, 0.0, 0.0); mitk::NavigationData::CovarianceMatrixType matrix; bool hasPosition = true; bool hasOrientation = true; bool dataValid = false; position.Fill(0.0); matrix.SetIdentity(); position = nd->GetPosition(); orientation = nd->GetOrientation(); matrix = nd->GetCovErrorMatrix(); hasPosition = nd->GetHasPosition(); hasOrientation = nd->GetHasOrientation(); dataValid = nd->IsDataValid(); //use this one if you want the timestamps of the source //timestamp = nd->GetIGTTimeStamp(); //a timestamp is never < 0! this case happens only if you are using the timestamp of the nd object instead of getting a new one if (timestamp >= 0) { if (this->m_OutputFormat == mitk::NavigationDataRecorderDeprecated::xml) - { - auto elem = new TiXmlElement("NavigationData"); - - elem->SetDoubleAttribute("Time", timestamp); - elem->SetAttribute("SystemTime", sysTimeStr); // tag for system time - elem->SetDoubleAttribute("Tool", index); - elem->SetDoubleAttribute("X", position[0]); - elem->SetDoubleAttribute("Y", position[1]); - elem->SetDoubleAttribute("Z", position[2]); - - elem->SetDoubleAttribute("QX", orientation[0]); - elem->SetDoubleAttribute("QY", orientation[1]); - elem->SetDoubleAttribute("QZ", orientation[2]); - elem->SetDoubleAttribute("QR", orientation[3]); - - elem->SetDoubleAttribute("C00", matrix[0][0]); - elem->SetDoubleAttribute("C01", matrix[0][1]); - elem->SetDoubleAttribute("C02", matrix[0][2]); - elem->SetDoubleAttribute("C03", matrix[0][3]); - elem->SetDoubleAttribute("C04", matrix[0][4]); - elem->SetDoubleAttribute("C05", matrix[0][5]); - elem->SetDoubleAttribute("C10", matrix[1][0]); - elem->SetDoubleAttribute("C11", matrix[1][1]); - elem->SetDoubleAttribute("C12", matrix[1][2]); - elem->SetDoubleAttribute("C13", matrix[1][3]); - elem->SetDoubleAttribute("C14", matrix[1][4]); - elem->SetDoubleAttribute("C15", matrix[1][5]); + { + tinyxml2::XMLDocument doc; + auto *elem = doc.NewElement("NavigationData"); + + elem->SetAttribute("Time", timestamp); + elem->SetAttribute("SystemTime", sysTimeStr.c_str()); // tag for system time + elem->SetAttribute("Tool", index); + elem->SetAttribute("X", position[0]); + elem->SetAttribute("Y", position[1]); + elem->SetAttribute("Z", position[2]); + + elem->SetAttribute("QX", orientation[0]); + elem->SetAttribute("QY", orientation[1]); + elem->SetAttribute("QZ", orientation[2]); + elem->SetAttribute("QR", orientation[3]); + + elem->SetAttribute("C00", matrix[0][0]); + elem->SetAttribute("C01", matrix[0][1]); + elem->SetAttribute("C02", matrix[0][2]); + elem->SetAttribute("C03", matrix[0][3]); + elem->SetAttribute("C04", matrix[0][4]); + elem->SetAttribute("C05", matrix[0][5]); + elem->SetAttribute("C10", matrix[1][0]); + elem->SetAttribute("C11", matrix[1][1]); + elem->SetAttribute("C12", matrix[1][2]); + elem->SetAttribute("C13", matrix[1][3]); + elem->SetAttribute("C14", matrix[1][4]); + elem->SetAttribute("C15", matrix[1][5]); if (dataValid) elem->SetAttribute("Valid",1); else elem->SetAttribute("Valid",0); if (hasOrientation) elem->SetAttribute("hO",1); else elem->SetAttribute("hO",0); if (hasPosition) elem->SetAttribute("hP",1); else elem->SetAttribute("hP",0); // set additional attribute? auto it = m_AdditionalAttributes.find( nd ); if( it != m_AdditionalAttributes.end() ) { - elem->SetAttribute(it->second.first, it->second.second); + elem->SetAttribute(it->second.first.c_str(), it->second.second.c_str()); } - *m_Stream << " " << *elem << std::endl; + tinyxml2::XMLPrinter printer; + doc.Print(&printer); - delete elem; + *m_Stream << " " << printer.CStr() << std::endl; } else if (this->m_OutputFormat == mitk::NavigationDataRecorderDeprecated::csv) { *m_Stream << ";" << dataValid << ";" << position[0] << ";" << position[1] << ";" << position[2] << ";" << orientation[0] << ";" << orientation[1] << ";" << orientation[2] << ";" << orientation[3]; } } } if (this->m_OutputFormat == mitk::NavigationDataRecorderDeprecated::csv) { *m_Stream << "\n"; } } m_RecordCounter++; if ((m_RecordCountLimit<=m_RecordCounter)&&(m_RecordCountLimit != -1)) {StopRecording();} } void mitk::NavigationDataRecorderDeprecated::SetAdditionalAttribute(const NavigationData* nd, const std::string& attributeName , const std::string& attributeValue ) { auto it = m_AdditionalAttributes.find( nd ); if( it == m_AdditionalAttributes.end() ) m_AdditionalAttributes[nd] = std::pair(attributeName, attributeValue); else { it->second.first = attributeName; it->second.second = attributeValue; } } void mitk::NavigationDataRecorderDeprecated::RemoveAdditionalAttribute( const NavigationData* nd ) { auto it = m_AdditionalAttributes.find( nd ); if( it != m_AdditionalAttributes.end() ) m_AdditionalAttributes.erase(it); } void mitk::NavigationDataRecorderDeprecated::StartRecording() { if(!m_Recording) { if (m_Stream == nullptr) { std::stringstream ss; std::ostream* stream; //An existing extension will be cut and replaced with .xml std::string tmpPath = itksys::SystemTools::GetFilenamePath(m_FileName); m_FileName = itksys::SystemTools::GetFilenameWithoutExtension(m_FileName); std::string extension = ".xml"; if (m_OutputFormat == mitk::NavigationDataRecorderDeprecated::csv) extension = ".csv"; ss << tmpPath << "/" << m_FileName << "-" << m_NumberOfRecordedFiles << extension; if( m_DoNotOverwriteFiles ) { unsigned int index = m_NumberOfRecordedFiles+1; while( itksys::SystemTools::FileExists( ss.str().c_str() ) ) { ss.str(""); ss << tmpPath << "/" << m_FileName << "-" << index << extension; index++; } } switch(m_RecordingMode) { case Console: stream = &std::cout; break; case NormalFile: if (m_FileName == "") //Check if there is a file name and path { std::string message = "No file name or file path set."; MITK_ERROR << message; mitkThrowException(mitk::IGTException) << message; } else { stream = new std::ofstream(ss.str().c_str()); } break; case ZipFile: stream = &std::cout; MITK_WARN << "Sorry no ZipFile support yet"; break; default: stream = &std::cout; break; } m_Stream = stream; m_StreamMustBeDeleted = true; m_firstLine = true; m_RecordCounter = 0; StartRecording(stream); } } else if (m_Recording) { MITK_WARN << "Already recording please stop before start new recording session"; return; } } void mitk::NavigationDataRecorderDeprecated::StartRecording(std::ostream* stream) { if (m_Recording) { MITK_WARN << "Already recording please stop before start new recording session"; return; } m_Stream = stream; m_Stream->precision(10); //TODO store date and GMT time //cheking if the stream is good if (m_Stream->good()) { if (m_OutputFormat == mitk::NavigationDataRecorderDeprecated::xml) { *m_Stream << "" << std::endl; /**m_Stream << "" << std::endl;*/ // should be a generic version, meaning a member variable, which has the actual version *m_Stream << " " << "" << std::endl; } m_Recording = true; } else { m_Recording = false; mitkThrowException(mitk::IGTException)<<"The stream is not good"; } } void mitk::NavigationDataRecorderDeprecated::StopRecording() { if (!m_Recording) { std::cout << "You have to start a recording first" << std::endl; return; } if ((m_Stream) && (m_OutputFormat == mitk::NavigationDataRecorderDeprecated::xml)) { *m_Stream << "" << std::endl; } m_NumberOfRecordedFiles++; m_Recording = false; m_Stream->flush(); if (m_StreamMustBeDeleted) //stream must only be deleted if it was created inside this class { m_StreamMustBeDeleted = false; delete m_Stream; } m_Stream = nullptr; } diff --git a/Modules/IGTBase/autoload/IO/CMakeLists.txt b/Modules/IGTBase/autoload/IO/CMakeLists.txt index e6e391249c..cdda327e30 100644 --- a/Modules/IGTBase/autoload/IO/CMakeLists.txt +++ b/Modules/IGTBase/autoload/IO/CMakeLists.txt @@ -1,5 +1,5 @@ MITK_CREATE_MODULE(IGTIO DEPENDS MitkIGTBase - PACKAGE_DEPENDS tinyxml + PACKAGE_DEPENDS tinyxml2 AUTOLOAD_WITH MitkCore ) diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp index 24551b7f0a..7195fd995e 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp @@ -1,364 +1,214 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkNavigationDataReaderXML.h" #include #include // Third Party #include #include -#include +#include - -mitk::NavigationDataReaderXML::NavigationDataReaderXML() : AbstractFileReader( - mitk::IGTMimeTypes::NAVIGATIONDATASETXML_MIMETYPE(), - "MITK NavigationData Reader (XML)"), m_parentElement(nullptr), m_currentNode(nullptr) +namespace { - RegisterService(); -} + mitk::NavigationData::Pointer ReadNavigationData(const tinyxml2::XMLElement* ndElem) + { + if (nullptr == ndElem) + return nullptr; -mitk::NavigationDataReaderXML::~NavigationDataReaderXML() -{ -} + mitk::NavigationData::TimeStampType timeStamp = -1; -mitk::NavigationDataReaderXML::NavigationDataReaderXML(const mitk::NavigationDataReaderXML& other) : AbstractFileReader(other), m_parentElement(nullptr), m_currentNode(nullptr) -{ -} + ndElem->QueryDoubleAttribute("Time", &timeStamp); -mitk::NavigationDataReaderXML* mitk::NavigationDataReaderXML::Clone() const -{ - return new NavigationDataReaderXML(*this); -} + if (-1 == timeStamp) + return nullptr; + mitk::NavigationData::PositionType position; + position.Fill(0.0); -std::vector> mitk::NavigationDataReaderXML::DoRead() -{ - mitk::NavigationDataSet::Pointer dataset; - std::istream* in = GetInputStream(); - if (in == nullptr) - { - dataset = Read(GetInputLocation()); - } else { - dataset = Read(in); - } - std::vector result; - mitk::BaseData::Pointer base = dataset.GetPointer(); - result.push_back(base); - return result; -} + ndElem->QueryDoubleAttribute("X", &position[0]); + ndElem->QueryDoubleAttribute("Y", &position[1]); + ndElem->QueryDoubleAttribute("Z", &position[2]); + mitk::NavigationData::OrientationType orientation; + ndElem->QueryDoubleAttribute("QX", &orientation[0]); + ndElem->QueryDoubleAttribute("QY", &orientation[1]); + ndElem->QueryDoubleAttribute("QZ", &orientation[2]); + ndElem->QueryDoubleAttribute("QR", &orientation[3]); -mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::string fileName) -{ - //define own locale - mitk::LocaleSwitch localeSwitch("C"); + mitk::NavigationData::CovarianceMatrixType matrix; + matrix.SetIdentity(); - m_FileName = fileName; + ndElem->QueryDoubleAttribute("C00", &matrix[0][0]); + ndElem->QueryDoubleAttribute("C01", &matrix[0][1]); + ndElem->QueryDoubleAttribute("C02", &matrix[0][2]); + ndElem->QueryDoubleAttribute("C03", &matrix[0][3]); + ndElem->QueryDoubleAttribute("C04", &matrix[0][4]); + ndElem->QueryDoubleAttribute("C05", &matrix[0][5]); + ndElem->QueryDoubleAttribute("C10", &matrix[1][0]); + ndElem->QueryDoubleAttribute("C11", &matrix[1][1]); + ndElem->QueryDoubleAttribute("C12", &matrix[1][2]); + ndElem->QueryDoubleAttribute("C13", &matrix[1][3]); + ndElem->QueryDoubleAttribute("C14", &matrix[1][4]); + ndElem->QueryDoubleAttribute("C15", &matrix[1][5]); - TiXmlDocument document; - if (!document.LoadFile(fileName)) - { - mitkThrowException(mitk::IGTIOException) << "File '" << fileName << "' could not be loaded."; - } + int attrib = 0; + ndElem->QueryIntAttribute("Valid", &attrib); + bool isValid = 0 != attrib; - TiXmlElement* m_DataElem = document.FirstChildElement("Version"); - if (!m_DataElem) - { - // for backwards compatibility of version tag - m_DataElem = document.FirstChildElement("Data"); - if (!m_DataElem) - { - mitkThrowException(mitk::IGTIOException) << "Data element not found."; - } + attrib = 0; + ndElem->QueryIntAttribute("hP", &attrib); + bool hasPosition = 0 != attrib; - } + attrib = 0; + ndElem->QueryIntAttribute("hO", &attrib); + bool hasOrientation = 0 != attrib; - if (m_DataElem->QueryIntAttribute("Ver", &m_FileVersion) != TIXML_SUCCESS) - { - if (m_DataElem->QueryIntAttribute("version", &m_FileVersion) != TIXML_SUCCESS) - { - mitkThrowException(mitk::IGTIOException) << "Version not specified in XML file."; - } - } + auto navData = mitk::NavigationData::New(); - if (m_FileVersion != 1) - { - mitkThrowException(mitk::IGTIOException) << "File format version " << m_FileVersion << " is not supported."; - } + navData->SetIGTTimeStamp(timeStamp); + navData->SetPosition(position); + navData->SetOrientation(orientation); + navData->SetCovErrorMatrix(matrix); + navData->SetDataValid(isValid); + navData->SetHasPosition(hasPosition); + navData->SetHasOrientation(hasOrientation); - m_parentElement = document.FirstChildElement("Data"); - if (!m_parentElement) - { - mitkThrowException(mitk::IGTIOException) << "Data element not found."; + return navData; } - - m_parentElement->QueryIntAttribute("ToolCount", &m_NumberOfOutputs); - - mitk::NavigationDataSet::Pointer navigationDataSet = this->ReadNavigationDataSet(); - - return navigationDataSet; } -mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::istream* stream) +mitk::NavigationDataReaderXML::NavigationDataReaderXML() + : AbstractFileReader(IGTMimeTypes::NAVIGATIONDATASETXML_MIMETYPE(), "MITK NavigationData Reader (XML)") { - //define own locale - mitk::LocaleSwitch localeSwitch("C"); - - // first get the file version - m_FileVersion = this->GetFileVersion(stream); - - // check if we have a valid version: m_FileVersion has to be always bigger than 1 for playing - if (m_FileVersion < 1) - { - StreamInvalid("Playing not possible. Invalid file version!"); - return nullptr; - } + this->RegisterService(); +} - m_NumberOfOutputs = this->GetNumberOfNavigationDatas(stream); - if (m_NumberOfOutputs == 0) { return nullptr; } +mitk::NavigationDataReaderXML::~NavigationDataReaderXML() +{ +} - mitk::NavigationDataSet::Pointer dataSet = this->ReadNavigationDataSet(); +mitk::NavigationDataReaderXML::NavigationDataReaderXML(const mitk::NavigationDataReaderXML& other) + : AbstractFileReader(other) +{ +} - return dataSet; +mitk::NavigationDataReaderXML* mitk::NavigationDataReaderXML::Clone() const +{ + return new NavigationDataReaderXML(*this); } -mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::ReadNavigationDataSet() +std::vector> mitk::NavigationDataReaderXML::DoRead() { - mitk::NavigationDataSet::Pointer navigationDataSet = mitk::NavigationDataSet::New(m_NumberOfOutputs); - mitk::NavigationData::Pointer curNavigationData; + mitk::NavigationDataSet::Pointer dataset = nullptr == this->GetInputStream() + ? this->Read(this->GetInputLocation()) + : this->Read(*this->GetInputStream()); - do - { - std::vector navDatas(m_NumberOfOutputs); - for (int n = 0; n < m_NumberOfOutputs; ++n) - { - curNavigationData = this->ReadVersion1(); + std::vector result; + result.emplace_back(dataset.GetPointer()); - if (curNavigationData.IsNull()) - { - if (n != 0) - { - MITK_WARN("mitkNavigationDataReaderXML") - << "Different number of NavigationData objects for different tools. Ignoring last ones."; - } - break; - } - navDatas.at(n) = curNavigationData; - } + return result; +} - if (curNavigationData.IsNotNull()) - { - navigationDataSet->AddNavigationDatas(navDatas); - } - } - while (curNavigationData.IsNotNull()); +mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(const std::string& fileName) +{ + std::ifstream stream(fileName); + stream.imbue(std::locale::classic()); - return navigationDataSet; + return this->Read(stream); } -mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadVersion1() +mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::istream& stream) { - if ( !m_parentElement ) - { - mitkThrowException(mitk::IGTIOException) << "Reading XML is not possible. Parent element is not set."; - } + std::string string(std::istreambuf_iterator(stream), {}); + tinyxml2::XMLDocument doc; + + if (tinyxml2::XML_SUCCESS != doc.Parse(string.c_str())) + mitkThrowException(IGTIOException) << "Could not parse stream."; + + const auto* rootElem = doc.RootElement(); + decltype(rootElem) dataElem = nullptr; - TiXmlElement* elem; - m_currentNode = m_parentElement->IterateChildren(m_currentNode); + if (nullptr == rootElem) + return nullptr; - bool delElem; + int version = 0; + auto err = tinyxml2::XML_SUCCESS; + + std::string rootElemVal = rootElem->Value(); - if(m_currentNode) + if ("Version" == rootElemVal) { - elem = m_currentNode->ToElement(); - if(elem==nullptr) - { - mitkThrowException(mitk::IGTException) << "Cannot find element: Is this file damaged?"; - } - delElem = false; + err = rootElem->QueryIntAttribute("Ver", &version); + dataElem = rootElem->NextSiblingElement("Data"); } - - else + else if ("Data" == rootElemVal) { - elem = new TiXmlElement(""); - delElem = true; + err = rootElem->QueryIntAttribute("version", &version); + dataElem = rootElem; } + if (err != tinyxml2::XML_SUCCESS) + mitkThrowException(IGTIOException) << "Could not parse file format version."; - mitk::NavigationData::Pointer nd = this->ReadNavigationData(elem); + if (version != 1) + mitkThrowException(IGTIOException) << "File format version " << version << " is not supported."; - if(delElem) { delete elem; } + if (nullptr == dataElem) + mitkThrowException(IGTIOException) << "Data element not found."; - return nd; -} + int toolCount = 0; -mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadNavigationData(TiXmlElement* elem) -{ - if (elem == nullptr) {mitkThrow() << "Error: Element is nullptr!";} - - mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); + if (tinyxml2::XML_SUCCESS != dataElem->QueryIntAttribute("ToolCount", &toolCount)) + mitkThrowException(IGTIOException) << "ToolCount attribute missing from Data element."; - mitk::NavigationData::PositionType position; - mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0); - mitk::NavigationData::TimeStampType timestamp = -1; - mitk::NavigationData::CovarianceMatrixType matrix; + if (0 >= toolCount) + mitkThrowException(IGTIOException) << "Invalid ToolCount: " << toolCount << "."; - bool hasPosition = true; - bool hasOrientation = true; - bool dataValid = false; + auto navDataSet = NavigationDataSet::New(static_cast(toolCount)); + NavigationData::Pointer navData; - position.Fill(0.0); - matrix.SetIdentity(); + const auto* ndElem = dataElem->FirstChildElement(); - elem->QueryDoubleAttribute("Time",×tamp); - if (timestamp == -1) + if (nullptr != ndElem) { - return nullptr; //the calling method should check the return value if it is valid/not nullptr - } - - elem->QueryDoubleAttribute("X", &position[0]); - elem->QueryDoubleAttribute("Y", &position[1]); - elem->QueryDoubleAttribute("Z", &position[2]); - - elem->QueryDoubleAttribute("QX", &orientation[0]); - elem->QueryDoubleAttribute("QY", &orientation[1]); - elem->QueryDoubleAttribute("QZ", &orientation[2]); - elem->QueryDoubleAttribute("QR", &orientation[3]); - - elem->QueryDoubleAttribute("C00", &matrix[0][0]); - elem->QueryDoubleAttribute("C01", &matrix[0][1]); - elem->QueryDoubleAttribute("C02", &matrix[0][2]); - elem->QueryDoubleAttribute("C03", &matrix[0][3]); - elem->QueryDoubleAttribute("C04", &matrix[0][4]); - elem->QueryDoubleAttribute("C05", &matrix[0][5]); - elem->QueryDoubleAttribute("C10", &matrix[1][0]); - elem->QueryDoubleAttribute("C11", &matrix[1][1]); - elem->QueryDoubleAttribute("C12", &matrix[1][2]); - elem->QueryDoubleAttribute("C13", &matrix[1][3]); - elem->QueryDoubleAttribute("C14", &matrix[1][4]); - elem->QueryDoubleAttribute("C15", &matrix[1][5]); - - int tmpval = 0; - elem->QueryIntAttribute("Valid", &tmpval); - if (tmpval == 0) - dataValid = false; - else - dataValid = true; - - tmpval = 0; - elem->QueryIntAttribute("hO", &tmpval); - if (tmpval == 0) - hasOrientation = false; - else - hasOrientation = true; - - tmpval = 0; - elem->QueryIntAttribute("hP", &tmpval); - if (tmpval == 0) - hasPosition = false; - else - hasPosition = true; - - nd->SetIGTTimeStamp(timestamp); - nd->SetPosition(position); - nd->SetOrientation(orientation); - nd->SetCovErrorMatrix(matrix); - nd->SetDataValid(dataValid); - nd->SetHasOrientation(hasOrientation); - nd->SetHasPosition(hasPosition); - - - return nd; -} + do + { + std::vector navDatas(toolCount); -// -- deprecated | begin -unsigned int mitk::NavigationDataReaderXML::GetFileVersion(std::istream* stream) -{ - if (stream==nullptr) - { - MITK_ERROR << "No input stream set!"; - mitkThrowException(mitk::IGTIOException)<<"No input stream set!"; - } - if (!stream->good()) - { - MITK_ERROR << "Stream is not good!"; - mitkThrowException(mitk::IGTIOException)<<"Stream is not good!"; - } - int version = 1; + for (decltype(toolCount) i = 0; i < toolCount; ++i) + { + navData = ReadNavigationData(ndElem); - auto dec = new TiXmlDeclaration(); - *stream >> *dec; - if(strcmp(dec->Version(),"") == 0) - { - MITK_ERROR << "The input stream seems to have XML incompatible format"; - mitkThrowException(mitk::IGTIOException) << "The input stream seems to have XML incompatible format"; - } + if (navData.IsNull()) + { + if (0 != i) + MITK_WARN("mitkNavigationDataReaderXML") << "Different number of NavigationData objects for different tools. Ignoring last ones."; - m_parentElement = new TiXmlElement(""); - *stream >> *m_parentElement; //2nd line this is the file version + break; + } - std::string tempValue = m_parentElement->Value(); - if(tempValue != "Version") - { - if(tempValue == "Data"){ - m_parentElement->QueryIntAttribute("version",&version); + navDatas[i] = navData; + ndElem = ndElem->NextSiblingElement(); } - } - else - { - m_parentElement->QueryIntAttribute("Ver",&version); - } - if (version > 0) { return version; } - else { return 0; } -} + if (navData.IsNotNull()) + navDataSet->AddNavigationDatas(navDatas); -unsigned int mitk::NavigationDataReaderXML::GetNumberOfNavigationDatas(std::istream* stream) -{ - if (stream == nullptr) - { - MITK_ERROR << "No input stream set!"; - mitkThrowException(mitk::IGTException)<<"No input stream set!"; - } - if (!stream->good()) - { - MITK_ERROR << "Stream not good!"; - mitkThrowException(mitk::IGTException)<<"Stream not good!"; - } - - //If something has changed in a future version of the XML definition e.g. navigationcount or addional parameters - //catch this here with a select case block (see GenerateData() method) - - int numberOfTools = 0; - - std::string tempValue = m_parentElement->Value(); - if(tempValue == "Version"){ - *stream >> *m_parentElement; + } while (nullptr != ndElem && navData.IsNotNull()); } - m_parentElement->QueryIntAttribute("ToolCount",&numberOfTools); - - if (numberOfTools > 0) { return numberOfTools; } - return 0; -} - -void mitk::NavigationDataReaderXML::StreamInvalid(std::string message) -{ - m_StreamEnd = true; - m_ErrorMessage = message; - m_StreamValid = false; - mitkThrowException(mitk::IGTIOException) << "Invalid stream!"; + return navDataSet; } -// -- deprecated | end diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h index 8c6dc89b47..2209f661e6 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h @@ -1,106 +1,50 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ #define MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ #include #include #include // includes for exceptions #include #include -class TiXmlElement; -class TiXmlNode; - namespace mitk { class MITKIGTIO_EXPORT NavigationDataReaderXML : public AbstractFileReader { public: NavigationDataReaderXML(); ~NavigationDataReaderXML() override; using AbstractFileReader::Read; protected: std::vector> DoRead() override; NavigationDataReaderXML(const NavigationDataReaderXML& other); mitk::NavigationDataReaderXML* Clone() const override; - NavigationDataSet::Pointer ReadNavigationDataSet(); - - /** - * \brief This method reads one line of the XML document and returns the data as a NavigationData object - * If there is a new file version another method must be added which reads this data. - * @throw mitk::IGTException Throws an exceptions if file is damaged. - */ - mitk::NavigationData::Pointer ReadVersion1(); - mitk::NavigationData::Pointer ReadNavigationData(TiXmlElement* elem); - std::string m_FileName; - TiXmlElement* m_parentElement; - TiXmlNode* m_currentNode; - - int m_FileVersion; ///< indicates which XML encoding is used - int m_NumberOfOutputs; ///< stores the number of outputs known from the XML document - - // -- deprecated | begin - //std::istream* m_Stream; ///< stores a pointer to the input stream - bool m_StreamEnd; ///< stores if the input stream arrived at end - bool m_StreamValid; ///< stores if the input stream is valid or not - std::string m_ErrorMessage; ///< stores the error message if the stream is invalid - - /** - * \brief Creates a stream out of the filename given by the variable m_FileName. - * The stream is then set to m_Stream. - * - * @throw mitk::IGTIOException Throws an exception if file does not exist - * @throw mitk::IGTException Throws an exception if the stream is nullptr - */ - //void CreateStreamFromFilename(); - - /** - * \brief Returns the file version out of the XML document. - * @throw mitk::IGTException Throws an mitk::IGTException an exception if stream is nullptr or not good. - * @throw mitk::IGTIOException Throws an mitk::IGTIOException if the stream has an incompatible XML format. - */ - unsigned int GetFileVersion(std::istream* stream); - - /** - * \brief Returns the number of tracked tools out of the XML document. - * @throw Throws an exception if stream is nullptr. - * @throw Throws an exception if the input stream has an XML incompatible format. - */ - unsigned int GetNumberOfNavigationDatas(std::istream* stream); - - /** - * @brief This is a helping method which gives an error message and throws an exception with the given message. - * It can be used if a stream is found to be invalid. - * - * @throw mitk::IGTIOException Always throws an exception. - */ - void StreamInvalid(std::string message); ///< help method which sets the stream invalid and displays an error - // -- deprecated | end private: - NavigationDataSet::Pointer Read(std::istream* stream); - NavigationDataSet::Pointer Read(std::string fileName); + NavigationDataSet::Pointer Read(std::istream& stream); + NavigationDataSet::Pointer Read(const std::string& fileName); }; } // namespace mitk #endif // MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataSetWriterXML.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataSetWriterXML.cpp index 8816d1ab38..1256f4f8f0 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataSetWriterXML.cpp +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataSetWriterXML.cpp @@ -1,139 +1,141 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkNavigationDataSetWriterXML.h" #include #include // Third Party -#include +#include #include #include #include mitk::NavigationDataSetWriterXML::NavigationDataSetWriterXML() : AbstractFileWriter(NavigationDataSet::GetStaticNameOfClass(), mitk::IGTMimeTypes::NAVIGATIONDATASETXML_MIMETYPE(), "MITK NavigationDataSet Writer (XML)") { RegisterService(); } mitk::NavigationDataSetWriterXML::NavigationDataSetWriterXML(const mitk::NavigationDataSetWriterXML& other) : AbstractFileWriter(other) { } mitk::NavigationDataSetWriterXML::~NavigationDataSetWriterXML() { } mitk::NavigationDataSetWriterXML* mitk::NavigationDataSetWriterXML::Clone() const { return new NavigationDataSetWriterXML(*this); } void mitk::NavigationDataSetWriterXML::Write() { std::ostream* out = GetOutputStream(); if (out == nullptr) { out = new std::ofstream( GetOutputLocation().c_str() ); } mitk::NavigationDataSet::ConstPointer data = dynamic_cast (this->GetInput()); mitk::LocaleSwitch localeSwitch("C"); StreamHeader(out, data); StreamData(out, data); StreamFooter(out); // Cleanup out->flush(); delete out; } void mitk::NavigationDataSetWriterXML::StreamHeader (std::ostream* stream, mitk::NavigationDataSet::ConstPointer data) { stream->precision(10); //TODO store date and GMT time //checking if the stream is good if (stream->good()) { *stream << "" << std::endl; /**m_Stream << "" << std::endl;*/ // should be a generic version, meaning a member variable, which has the actual version *stream << " " << "GetNumberOfTools() << "\" version=\"1.0\">" << std::endl; } } void mitk::NavigationDataSetWriterXML::StreamData (std::ostream* stream, mitk::NavigationDataSet::ConstPointer data) { // For each time step in the Dataset for (auto it = data->Begin(); it != data->End(); it++) { for (std::size_t toolIndex = 0; toolIndex < it->size(); toolIndex++) { mitk::NavigationData::Pointer nd = it->at(toolIndex); - auto elem = new TiXmlElement("ND"); + tinyxml2::XMLDocument doc; + auto *elem = doc.NewElement("ND"); - elem->SetDoubleAttribute("Time", nd->GetIGTTimeStamp()); + elem->SetAttribute("Time", nd->GetIGTTimeStamp()); // elem->SetAttribute("SystemTime", sysTimeStr); // tag for system time - elem->SetDoubleAttribute("Tool", toolIndex); - elem->SetDoubleAttribute("X", nd->GetPosition()[0]); - elem->SetDoubleAttribute("Y", nd->GetPosition()[1]); - elem->SetDoubleAttribute("Z", nd->GetPosition()[2]); - - elem->SetDoubleAttribute("QX", nd->GetOrientation()[0]); - elem->SetDoubleAttribute("QY", nd->GetOrientation()[1]); - elem->SetDoubleAttribute("QZ", nd->GetOrientation()[2]); - elem->SetDoubleAttribute("QR", nd->GetOrientation()[3]); - - elem->SetDoubleAttribute("C00", nd->GetCovErrorMatrix()[0][0]); - elem->SetDoubleAttribute("C01", nd->GetCovErrorMatrix()[0][1]); - elem->SetDoubleAttribute("C02", nd->GetCovErrorMatrix()[0][2]); - elem->SetDoubleAttribute("C03", nd->GetCovErrorMatrix()[0][3]); - elem->SetDoubleAttribute("C04", nd->GetCovErrorMatrix()[0][4]); - elem->SetDoubleAttribute("C05", nd->GetCovErrorMatrix()[0][5]); - elem->SetDoubleAttribute("C10", nd->GetCovErrorMatrix()[1][0]); - elem->SetDoubleAttribute("C11", nd->GetCovErrorMatrix()[1][1]); - elem->SetDoubleAttribute("C12", nd->GetCovErrorMatrix()[1][2]); - elem->SetDoubleAttribute("C13", nd->GetCovErrorMatrix()[1][3]); - elem->SetDoubleAttribute("C14", nd->GetCovErrorMatrix()[1][4]); - elem->SetDoubleAttribute("C15", nd->GetCovErrorMatrix()[1][5]); + elem->SetAttribute("Tool", static_cast(toolIndex)); + elem->SetAttribute("X", nd->GetPosition()[0]); + elem->SetAttribute("Y", nd->GetPosition()[1]); + elem->SetAttribute("Z", nd->GetPosition()[2]); + + elem->SetAttribute("QX", nd->GetOrientation()[0]); + elem->SetAttribute("QY", nd->GetOrientation()[1]); + elem->SetAttribute("QZ", nd->GetOrientation()[2]); + elem->SetAttribute("QR", nd->GetOrientation()[3]); + + elem->SetAttribute("C00", nd->GetCovErrorMatrix()[0][0]); + elem->SetAttribute("C01", nd->GetCovErrorMatrix()[0][1]); + elem->SetAttribute("C02", nd->GetCovErrorMatrix()[0][2]); + elem->SetAttribute("C03", nd->GetCovErrorMatrix()[0][3]); + elem->SetAttribute("C04", nd->GetCovErrorMatrix()[0][4]); + elem->SetAttribute("C05", nd->GetCovErrorMatrix()[0][5]); + elem->SetAttribute("C10", nd->GetCovErrorMatrix()[1][0]); + elem->SetAttribute("C11", nd->GetCovErrorMatrix()[1][1]); + elem->SetAttribute("C12", nd->GetCovErrorMatrix()[1][2]); + elem->SetAttribute("C13", nd->GetCovErrorMatrix()[1][3]); + elem->SetAttribute("C14", nd->GetCovErrorMatrix()[1][4]); + elem->SetAttribute("C15", nd->GetCovErrorMatrix()[1][5]); if (nd->IsDataValid()) elem->SetAttribute("Valid",1); else elem->SetAttribute("Valid",0); if (nd->GetHasOrientation()) elem->SetAttribute("hO",1); else elem->SetAttribute("hO",0); if (nd->GetHasPosition()) elem->SetAttribute("hP",1); else elem->SetAttribute("hP",0); - *stream << " " << *elem << std::endl; + tinyxml2::XMLPrinter printer; + doc.Print(&printer); - delete elem; + *stream << " " << printer.CStr() << std::endl; } } } void mitk::NavigationDataSetWriterXML::StreamFooter (std::ostream* stream) { *stream << "" << std::endl; } diff --git a/Modules/IOExt/CMakeLists.txt b/Modules/IOExt/CMakeLists.txt index 61b51b291e..7084badf96 100644 --- a/Modules/IOExt/CMakeLists.txt +++ b/Modules/IOExt/CMakeLists.txt @@ -1,4 +1,4 @@ MITK_CREATE_MODULE(DEPENDS MitkDataTypesExt MitkMapperExt MitkSceneSerialization MitkLegacyIO - PACKAGE_DEPENDS PRIVATE ITK|ITKIOImageBase VTK|IOPLY+IOExport+IOParallelXML + PACKAGE_DEPENDS PRIVATE VTK|IOPLY+IOExport+IOParallelXML AUTOLOAD_WITH MitkCore ) diff --git a/Modules/ImageExtraction/CMakeLists.txt b/Modules/ImageExtraction/CMakeLists.txt index ad9d099dda..f522d94f78 100644 --- a/Modules/ImageExtraction/CMakeLists.txt +++ b/Modules/ImageExtraction/CMakeLists.txt @@ -1,10 +1,9 @@ MITK_CREATE_MODULE( DEPENDS MitkAlgorithmsExt - PACKAGE_DEPENDS PRIVATE ITK|ITKIOImageBase ) if(BUILD_TESTING) add_subdirectory(Testing) endif(BUILD_TESTING) diff --git a/Modules/ImageStatistics/CMakeLists.txt b/Modules/ImageStatistics/CMakeLists.txt index 532b38bdf4..1cf692bc6f 100644 --- a/Modules/ImageStatistics/CMakeLists.txt +++ b/Modules/ImageStatistics/CMakeLists.txt @@ -1,10 +1,8 @@ -MITK_CREATE_MODULE( +mitk_create_module( DEPENDS MitkImageExtraction MitkPlanarFigure MitkMultilabel - PACKAGE_DEPENDS - PUBLIC ITK|ITKIOXML - PRIVATE ITK|ITKVTK+ITKConvolution VTK|IOImage + PACKAGE_DEPENDS PRIVATE ITK|VTK VTK|IOImage ) if(BUILD_TESTING) add_subdirectory(Testing) endif() diff --git a/Modules/ImageStatistics/Testing/CMakeLists.txt b/Modules/ImageStatistics/Testing/CMakeLists.txt index 5eca89a43e..834d6d6592 100644 --- a/Modules/ImageStatistics/Testing/CMakeLists.txt +++ b/Modules/ImageStatistics/Testing/CMakeLists.txt @@ -1,34 +1,38 @@ MITK_CREATE_MODULE_TESTS() +if(TARGET ${TESTDRIVER}) + mitk_use_modules(TARGET ${TESTDRIVER} PACKAGES ITK|IOXML) +endif() + # mitkAddCustomModuleTest(mitkRoiMeasurementsTests mitkRoiMeasurementsTest ${MITK_DATA_DIR}/ImageStatisticsTestData/) file(GLOB allHotSpotTests RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/Data/Hotspot" "${CMAKE_CURRENT_SOURCE_DIR}/Data/Hotspot/*.xml") foreach(testcase ${allHotSpotTests}) string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" testcaseName ${testcase}) mitkAddCustomModuleTest(mitkImageStatisticsHotspotTest_${testcaseName} mitkImageStatisticsHotspotTest ${CMAKE_CURRENT_SOURCE_DIR}/Data/Hotspot/${testcase}) endforeach() # # The following lines may be activated to generate new test cases for mitkImageStatisticsHotspotTest. # Test cases are generated by mitkMultiGaussianTest. All .xml files in Data/TestGeneration/Input will # be processed and transformed into new .xml files containing statistics in Data/TestGeneration/Output. # if (false) set(testInputDir ${CMAKE_CURRENT_SOURCE_DIR}/Data/TestGeneration/Input) set(testOutputDir ${CMAKE_CURRENT_SOURCE_DIR}/Data/TestGeneration/Output) file(GLOB testcasesToGenerate RELATIVE "${testInputDir}" "${testInputDir}/*.xml") if (NOT EXISTS ${testOutputDir}) file(MAKE_DIRECTORY ${testOutputDir}) endif() foreach(testinput ${testcasesToGenerate}) string(REGEX REPLACE "[^a-zA-Z0-9_]\\+" "_" testcaseName ${testinput}) string(REGEX REPLACE "\\.xml" "" testoutput ${testinput}) message("Generate hotspot test case '${testinput}'. Output in '${testoutput}.xml' and '${testoutput}.nrrd'") mitkAddCustomModuleTest(mitkMultiGaussianTest_${testcaseName} mitkMultiGaussianTest ${testOutputDir}/${testoutput} ${testInputDir}/${testinput}) endforeach() endif() diff --git a/Modules/ImageStatistics/mitkPlanarFigureMaskGenerator.h b/Modules/ImageStatistics/mitkPlanarFigureMaskGenerator.h index c724cd6e81..0e61304fef 100644 --- a/Modules/ImageStatistics/mitkPlanarFigureMaskGenerator.h +++ b/Modules/ImageStatistics/mitkPlanarFigureMaskGenerator.h @@ -1,149 +1,145 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKPLANARFIGUREMASKGENERATOR #define MITKPLANARFIGUREMASKGENERATOR #include #include -#include -#include #include #include #include -#include -#include #include namespace mitk { /** * \class PlanarFigureMaskGenerator * \brief Derived from MaskGenerator. This class is used to convert a mitk::PlanarFigure into a binary image mask */ class MITKIMAGESTATISTICS_EXPORT PlanarFigureMaskGenerator : public MaskGenerator { public: /** Standard Self typedef */ typedef PlanarFigureMaskGenerator Self; typedef MaskGenerator Superclass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); /** Runtime information support. */ itkTypeMacro(PlanarFigureMaskGenerator, MaskGenerator); /** * @brief GetMask Computes and returns the mask * @return mitk::Image::Pointer of the generated mask */ mitk::Image::Pointer GetMask() override; void SetPlanarFigure(mitk::PlanarFigure::Pointer planarFigure); mitk::Image::ConstPointer GetReferenceImage() override; /** * @brief SetTimeStep is used to set the time step for which the mask is to be generated * @param timeStep */ void SetTimeStep(unsigned int timeStep) override; itkGetConstMacro(PlanarFigureAxis, unsigned int); itkGetConstMacro(PlanarFigureSlice, unsigned int); /** Helper function that indicates if a passed planar geometry is tilted regarding a given geometry and its main axis. *@pre If either planarGeometry or geometry is nullptr it will return false.*/ static bool CheckPlanarFigureIsNotTilted(const PlaneGeometry* planarGeometry, const BaseGeometry *geometry); protected: PlanarFigureMaskGenerator() : Superclass(), m_ReferenceImage(nullptr), m_PlanarFigureAxis(0), m_InternalMaskUpdateTime(0), m_PlanarFigureSlice(0) { m_InternalMask = mitk::Image::New(); } private: void CalculateMask(); template void InternalCalculateMaskFromPlanarFigure(const itk::Image *image, unsigned int axis); template void InternalCalculateMaskFromOpenPlanarFigure(const itk::Image *image, unsigned int axis); mitk::Image::ConstPointer extract2DImageSlice(unsigned int axis, unsigned int slice); /** Helper function that deduces if the passed vector is equal to one of the primary axis of the geometry.*/ static bool GetPrincipalAxis(const BaseGeometry *geometry, Vector3D vector, unsigned int &axis); /** Connection from ITK to VTK */ template void ConnectPipelines(ITK_Exporter exporter, vtkSmartPointer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } /** Connection from VTK to ITK */ template void ConnectPipelines(vtkSmartPointer exporter, ITK_Importer importer) { importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); importer->SetSpacingCallback(exporter->GetSpacingCallback()); importer->SetOriginCallback(exporter->GetOriginCallback()); importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); importer->SetCallbackUserData(exporter->GetCallbackUserData()); } bool IsUpdateRequired() const; mitk::PlanarFigure::Pointer m_PlanarFigure; itk::Image::Pointer m_InternalITKImageMask2D; mitk::Image::ConstPointer m_InternalTimeSliceImage; mitk::Image::ConstPointer m_ReferenceImage; unsigned int m_PlanarFigureAxis; unsigned long m_InternalMaskUpdateTime; unsigned int m_PlanarFigureSlice; }; } // namespace mitk #endif // MITKPLANARFIGUREMASKGENERATOR diff --git a/Modules/LegacyIO/CMakeLists.txt b/Modules/LegacyIO/CMakeLists.txt index d9debfbd64..6a2376d3af 100644 --- a/Modules/LegacyIO/CMakeLists.txt +++ b/Modules/LegacyIO/CMakeLists.txt @@ -1,8 +1,8 @@ mitkFunctionCheckCompilerFlags("/wd4996" CMAKE_CXX_FLAGS) mitkFunctionCheckCompilerFlags("-Wno-deprecated-declarations" CMAKE_CXX_FLAGS) MITK_CREATE_MODULE( DEPENDS MitkCore - PACKAGE_DEPENDS PRIVATE ITK|ITKIOGDCM+ITKIORAW tinyxml + PACKAGE_DEPENDS tinyxml2 DEPRECATED_SINCE 2014.10 ) diff --git a/Modules/LegacyIO/mitkPointSetReader.cpp b/Modules/LegacyIO/mitkPointSetReader.cpp index 7222c061e5..f33d2cc3f8 100644 --- a/Modules/LegacyIO/mitkPointSetReader.cpp +++ b/Modules/LegacyIO/mitkPointSetReader.cpp @@ -1,195 +1,195 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPointSetReader.h" #include #include #include +#include mitk::PointSetReader::PointSetReader() { m_Success = false; } mitk::PointSetReader::~PointSetReader() { } void mitk::PointSetReader::GenerateData() { // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); m_Success = false; if (m_FileName == "") { itkWarningMacro(<< "Sorry, filename has not been set!"); return; } if (!this->CanReadFile(m_FileName.c_str())) { itkWarningMacro(<< "Sorry, can't read file " << m_FileName << "!"); return; } try { - TiXmlDocument doc(m_FileName.c_str()); - bool loadOkay = doc.LoadFile(); - if (loadOkay) + tinyxml2::XMLDocument doc; + if (tinyxml2::XML_SUCCESS == doc.LoadFile(m_FileName.c_str())) { - TiXmlHandle docHandle(&doc); + tinyxml2::XMLHandle docHandle(&doc); unsigned int pointSetCounter(0); - for (TiXmlElement *currentPointSetElement = + for (auto *currentPointSetElement = docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement(); currentPointSetElement != nullptr; currentPointSetElement = currentPointSetElement->NextSiblingElement()) { mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); if (currentPointSetElement->FirstChildElement("time_series") != nullptr) { - for (TiXmlElement *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); + for (auto *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series"); currentTimeSeries != nullptr; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); - TiXmlElement *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); + auto *currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); currentTimeStep = atoi(currentTimeSeriesID->GetText()); newPointSet = this->ReadPoint(newPointSet, currentTimeSeries, currentTimeStep); } } else { newPointSet = this->ReadPoint(newPointSet, currentPointSetElement, 0); } this->SetNthOutput(pointSetCounter, newPointSet); pointSetCounter++; } } else { MITK_WARN << "XML parser error!"; } } catch (...) { MITK_ERROR << "Cannot read point set."; m_Success = false; } m_Success = true; } mitk::PointSet::Pointer mitk::PointSetReader::ReadPoint(mitk::PointSet::Pointer newPointSet, - TiXmlElement *currentTimeSeries, + const tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep) { if (currentTimeSeries->FirstChildElement("point") != nullptr) { - for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); + for (auto *currentPoint = currentTimeSeries->FirstChildElement("point"); currentPoint != nullptr; currentPoint = currentPoint->NextSiblingElement()) { unsigned int id(0); mitk::PointSpecificationType spec((mitk::PointSpecificationType)0); double x(0.0); double y(0.0); double z(0.0); id = atoi(currentPoint->FirstChildElement("id")->GetText()); if (currentPoint->FirstChildElement("specification") != nullptr) { spec = (mitk::PointSpecificationType)atoi(currentPoint->FirstChildElement("specification")->GetText()); } x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newPointSet->SetPoint(id, point, spec, currentTimeStep); } } else { if (currentTimeStep != newPointSet->GetTimeSteps() + 1) { newPointSet->Expand(currentTimeStep + 1); // expand time step series with empty time step } } return newPointSet; } void mitk::PointSetReader::GenerateOutputInformation() { } int mitk::PointSetReader::CanReadFile(const char *name) { std::ifstream in(name); bool isGood = in.good(); in.close(); return isGood; } bool mitk::PointSetReader::CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern) { // First check the extension if (filename == "") { // MITK_INFO<<"No filename specified."<GetNumberOfOutputs(); this->SetNumberOfIndexedOutputs(num); for (unsigned int i = prevNum; i < num; ++i) { this->SetNthOutput(i, this->MakeOutput(i).GetPointer()); } } bool mitk::PointSetReader::GetSuccess() const { return m_Success; } diff --git a/Modules/LegacyIO/mitkPointSetReader.h b/Modules/LegacyIO/mitkPointSetReader.h index eb4cc27c51..9ea21cd980 100644 --- a/Modules/LegacyIO/mitkPointSetReader.h +++ b/Modules/LegacyIO/mitkPointSetReader.h @@ -1,141 +1,145 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_POINT_SET_READER__H_ #define _MITK_POINT_SET_READER__H_ #include #include #include #include #include -#include #include +namespace tinyxml2 +{ + class XMLElement; +} + namespace mitk { /** * @brief reads xml representations of mitk::PointSets from a file * * Reader for xml files containing one or multiple xml represenations of * mitk::PointSets. If multiple mitk::PointSets are stored in one file, * these are assigned to multiple outputs of the filter. The number of point * sets which have be read can be retrieven by a call to GetNumberOfOutputs() * after the pipeline update(). * The reader is able to read the old 3D Pointsets without the "specification" and "timeseries" tags and the new 4D * Pointsets. * @note loading point sets from multiple files according to a given file pattern * is not yet supported! * * @ingroup MitkLegacyIOModule * * @deprecatedSince{2014_10} Use mitk::IOUtils or mitk::FileReaderRegistry instead. */ class MITKLEGACYIO_EXPORT PointSetReader : public PointSetSource, public FileReader { public: mitkClassMacro(PointSetReader, FileReader); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /** * @brief Sets the filename of the file to be read * @param _arg the filename of the point set xml-file */ itkSetStringMacro(FileName); /** * @brief Returns the filename of the point set xml-file. * @returns the filename of the point set xml-file. */ itkGetStringMacro(FileName); /** * @warning multiple load not (yet) supported */ itkSetStringMacro(FilePrefix); /** * @warning multiple load not (yet) supported */ itkGetStringMacro(FilePrefix); /** * @warning multiple load not (yet) supported */ itkSetStringMacro(FilePattern); /** * @warning multiple load not (yet) supported */ itkGetStringMacro(FilePattern); static bool CanReadFile(const std::string filename, const std::string filePrefix, const std::string filePattern); /** * @returns whether the last read attempt was successful or not. */ bool GetSuccess() const; protected: /** * Constructor */ PointSetReader(); /** * Virtual destructor */ ~PointSetReader() override; /** * Actually reads the point sets from the given file */ void GenerateData() override; virtual mitk::PointSet::Pointer ReadPoint(mitk::PointSet::Pointer newPointSet, - TiXmlElement *currentTimeSeries, + const tinyxml2::XMLElement *currentTimeSeries, unsigned int currentTimeStep); /** * Does nothing in the current implementation */ void GenerateOutputInformation() override; /** * Resizes the output-objects according to the given number. * @param num the new number of output objects. */ virtual void ResizeOutputs(const unsigned int &num); /** * Checks if the given file has appropriate * read access. * @returns true if the file exists and may be read * or false otherwise. */ virtual int CanReadFile(const char *name); std::string m_FileName; std::string m_FilePrefix; std::string m_FilePattern; bool m_Success; }; } #endif diff --git a/Modules/MapperExt/CMakeLists.txt b/Modules/MapperExt/CMakeLists.txt index ca202f89be..e437f52956 100644 --- a/Modules/MapperExt/CMakeLists.txt +++ b/Modules/MapperExt/CMakeLists.txt @@ -1,14 +1,10 @@ mitk_create_module( DEPENDS MitkDataTypesExt MitkLegacyGL - PACKAGE_DEPENDS PRIVATE VTK|CommonComputationalGeometry+CommonSystem+RenderingVolumeOpenGL2 + PACKAGE_DEPENDS PUBLIC OpenMP PRIVATE VTK|CommonComputationalGeometry+CommonSystem+RenderingVolumeOpenGL2 ) if(TARGET ${MODULE_TARGET}) - if(MITK_USE_OpenMP) - target_link_libraries(${MODULE_TARGET} PUBLIC OpenMP::OpenMP_CXX) - endif() - if(BUILD_TESTING) add_subdirectory(test) endif() endif() diff --git a/Modules/MatchPointRegistration/autoload/IO/CMakeLists.txt b/Modules/MatchPointRegistration/autoload/IO/CMakeLists.txt index 0881f2493b..4df0d899e9 100644 --- a/Modules/MatchPointRegistration/autoload/IO/CMakeLists.txt +++ b/Modules/MatchPointRegistration/autoload/IO/CMakeLists.txt @@ -1,7 +1,7 @@ -MITK_CREATE_MODULE(MatchPointRegistrationIO +mitk_create_module(MatchPointRegistrationIO DEPENDS PUBLIC MitkMatchPointRegistration MitkSceneSerializationBase PACKAGE_DEPENDS - PRIVATE ITK MatchPoint + PRIVATE MatchPoint AUTOLOAD_WITH MitkCore ) diff --git a/Modules/MatchPointRegistration/cmdapps/CMakeLists.txt b/Modules/MatchPointRegistration/cmdapps/CMakeLists.txt index f02ab70bc2..272923372e 100644 --- a/Modules/MatchPointRegistration/cmdapps/CMakeLists.txt +++ b/Modules/MatchPointRegistration/cmdapps/CMakeLists.txt @@ -1,33 +1,32 @@ option(BUILD_MatchPointCmdApps "Build commandline tools for the MatchPoint module" OFF) if(BUILD_MatchPointCmdApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of CmdApps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( cmdapps StitchImagesMiniApp^^ ) foreach(cmdapp ${cmdapps}) # extract cmd name and dependencies string(REPLACE "^^" "\\;" cmdapp_info ${cmdapp}) set(cmdapp_info_list ${cmdapp_info}) list(GET cmdapp_info_list 0 appname) list(GET cmdapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkMatchPointRegistration ${dependencies_list} - PACKAGE_DEPENDS ITK ) endforeach() endif(BUILD_MatchPointCmdApps OR MITK_BUILD_ALL_APPS) diff --git a/Modules/MatchPointRegistration/include/itkStitchImageFilter.tpp b/Modules/MatchPointRegistration/include/itkStitchImageFilter.tpp index 1ec8334ada..5e8e7529c9 100644 --- a/Modules/MatchPointRegistration/include/itkStitchImageFilter.tpp +++ b/Modules/MatchPointRegistration/include/itkStitchImageFilter.tpp @@ -1,639 +1,639 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef itkStitchImageFilter_hxx #define itkStitchImageFilter_hxx #include "itkStitchImageFilter.h" #include "itkObjectFactory.h" #include "itkIdentityTransform.h" #include "itkProgressReporter.h" #include "itkImageRegionIteratorWithIndex.h" #include "itkImageScanlineIterator.h" #include "itkSpecialCoordinatesImage.h" #include "itkDefaultConvertPixelTraits.h" #include "itkSimpleDataObjectDecorator.h" #include namespace itk { template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::StitchImageFilter() : m_OutputSpacing( 1.0 ), m_OutputOrigin( 0.0 ), m_UseReferenceImage( false ), m_StitchStrategy(StitchStrategy::Mean) { m_Size.Fill( 0 ); m_OutputStartIndex.Fill( 0 ); m_OutputDirection.SetIdentity(); // Pipeline input configuration // implicit input index set: // #1 "ReferenceImage" optional Self::AddOptionalInputName("ReferenceImage"); m_DefaultPixelValue = NumericTraits::ZeroValue( m_DefaultPixelValue ); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetInput(const InputImageType* image) { this->SetInput(0, image, itk::IdentityTransform< TTransformPrecisionType, ImageDimension>::New().GetPointer(), LinearInterpolatorType::New().GetPointer()); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetInput(unsigned int index, const InputImageType* image) { this->SetInput(index, image, itk::IdentityTransform< TTransformPrecisionType, ImageDimension>::New().GetPointer(), LinearInterpolatorType::New().GetPointer()); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetInput(unsigned int index, const InputImageType* image, const TransformType* transform) { this->SetInput(index, image, transform, LinearInterpolatorType::New().GetPointer()); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetInput(unsigned int index, const InputImageType* image, const TransformType* transform, InterpolatorType* interpolator) { Superclass::SetInput(index, image); m_Interpolators[image] = interpolator; this->SetTransform(index, transform); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetTransform(unsigned int index, const TransformType* transform) { const auto transformName = this->GetTransformInputName(index); typedef SimpleDataObjectDecorator< TransformPointerType > DecoratorType; const DecoratorType* oldInput = itkDynamicCastInDebugMode< const DecoratorType* >(this->ProcessObject::GetInput(transformName)); if (!oldInput || oldInput->Get() != transform) { typename DecoratorType::Pointer newInput = DecoratorType::New(); // Process object is not const-correct so the const_cast is required here newInput->Set(const_cast(transform)); this->ProcessObject::SetInput(transformName, newInput); } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > const typename StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >::TransformType* StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GetTransform(unsigned int index) const { typedef SimpleDataObjectDecorator< TransformPointerType > DecoratorType; const DecoratorType* input = itkDynamicCastInDebugMode< const DecoratorType* >(this->ProcessObject::GetInput(this->GetTransformInputName(index))); if (nullptr != input) { return input->Get(); } return nullptr; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > const typename StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType >::InterpolatorType* StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GetInterpolator(unsigned int index) const { auto input = this->GetInput(index); if (m_Interpolators.find(input) != std::end(m_Interpolators)) { return m_Interpolators[input]; } return nullptr; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetOutputSpacing(const double *spacing) { SpacingType s; for(unsigned int i = 0; i < TOutputImage::ImageDimension; ++i) { s[i] = static_cast< typename SpacingType::ValueType >(spacing[i]); } this->SetOutputSpacing(s); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetOutputOrigin(const double *origin) { OriginPointType p(origin); this->SetOutputOrigin(p); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::SetOutputParametersFromImage(const ImageBaseType *image) { this->SetOutputOrigin ( image->GetOrigin() ); this->SetOutputSpacing ( image->GetSpacing() ); this->SetOutputDirection ( image->GetDirection() ); this->SetOutputStartIndex ( image->GetLargestPossibleRegion().GetIndex() ); this->SetSize ( image->GetLargestPossibleRegion().GetSize() ); } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::BeforeThreadedGenerateData() { this->EnsureInterpolators(); this->EnsureTransforms(); for (const auto& interpolator : m_Interpolators) { interpolator.second->SetInputImage(interpolator.first); } unsigned int nComponents = DefaultConvertPixelTraits::GetNumberOfComponents( m_DefaultPixelValue ); if (nComponents == 0) { PixelComponentType zeroComponent - = NumericTraits::ZeroValue( zeroComponent ); + = NumericTraits::ZeroValue(); nComponents = this->GetInput()->GetNumberOfComponentsPerPixel(); NumericTraits::SetLength(m_DefaultPixelValue, nComponents ); for (unsigned int n=0; n void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::AfterThreadedGenerateData() { // Disconnect input image from the interpolator for (auto& interpolator : m_Interpolators) { interpolator.second->SetInputImage(ITK_NULLPTR); } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId) { if( outputRegionForThread.GetNumberOfPixels() == 0 ) { return; } // Get the output pointers OutputImageType* outputPtr = this->GetOutput(); // Get this input pointers InputImageVectorType inputs = this->GetInputs(); TransformMapType transforms = this->GetTransforms(); std::map lowerIndices; std::map upperIndices; for (const auto& input : inputs) { const auto largestRegion = input->GetLargestPossibleRegion(); lowerIndices[input] = largestRegion.GetIndex(); upperIndices[input] = largestRegion.GetUpperIndex(); } // Create an iterator that will walk the output region for this thread. typedef ImageRegionIteratorWithIndex< OutputImageType > OutputIterator; OutputIterator outIt(outputPtr, outputRegionForThread); // Define a few indices that will be used to translate from an input pixel // to an output pixel PointType outputPoint; // Coordinates of current output pixel PointType inputPoint; // Coordinates of current input pixel ContinuousInputIndexType inputIndex; // Support for progress methods/callbacks ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); // Min/max values of the output pixel type AND these values // represented as the output type of the interpolator const PixelComponentType minValue = NumericTraits< PixelComponentType >::NonpositiveMin(); const PixelComponentType maxValue = NumericTraits< PixelComponentType >::max(); typedef typename InterpolatorType::OutputType OutputType; const ComponentType minOutputValue = static_cast(minValue); const ComponentType maxOutputValue = static_cast(maxValue); // Walk the output region outIt.GoToBegin(); while (!outIt.IsAtEnd()) { // Determine the index of the current output pixel outputPtr->TransformIndexToPhysicalPoint(outIt.GetIndex(), outputPoint); std::vector pixvals; std::vector pixDistance; for (const auto& input : inputs) { // Compute corresponding input pixel position inputPoint = transforms[input]->TransformPoint(outputPoint); const bool isInsideInput = input->TransformPhysicalPointToContinuousIndex(inputPoint, inputIndex); // Evaluate input at right position and copy to the output if (m_Interpolators[input]->IsInsideBuffer(inputIndex) && isInsideInput) { OutputType value = m_Interpolators[input]->EvaluateAtContinuousIndex(inputIndex); pixvals.emplace_back(this->CastPixelWithBoundsChecking(value, minOutputValue, maxOutputValue)); ContinuousInputIndexType indexDistance; const auto spacing = input->GetSpacing(); double minBorderDistance = std::numeric_limits::max(); for (unsigned int i = 0; i < ImageDimension; ++i) { minBorderDistance = std::min(minBorderDistance, std::min(std::abs(lowerIndices[input][i] - inputIndex[i]) * spacing[i], std::abs(upperIndices[input][i] - inputIndex[i]) * spacing[i])); } pixDistance.emplace_back(minBorderDistance); } } if (!pixvals.empty()) { //at least one input provided a value if (StitchStrategy::Mean == m_StitchStrategy) { double sum = std::accumulate(pixvals.begin(), pixvals.end(), 0.0); outIt.Set(sum / pixvals.size()); } else { auto finding = std::max_element(pixDistance.begin(), pixDistance.end()); outIt.Set(pixvals[std::distance(pixDistance.begin(), finding)]); } } else { outIt.Set(m_DefaultPixelValue); // default background value } progress.CompletedPixel(); ++outIt; } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > typename StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::PixelType StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::CastPixelWithBoundsChecking(const InterpolatorOutputType value, const ComponentType minComponent, const ComponentType maxComponent ) const { const unsigned int nComponents = InterpolatorConvertType::GetNumberOfComponents(value); PixelType outputValue; NumericTraits::SetLength( outputValue, nComponents ); for (unsigned int n = 0; n < nComponents; n++) { ComponentType component = InterpolatorConvertType::GetNthComponent( n, value ); if ( component < minComponent ) { PixelConvertType::SetNthComponent( n, outputValue, static_cast( minComponent ) ); } else if ( component > maxComponent ) { PixelConvertType::SetNthComponent( n, outputValue, static_cast( maxComponent ) ); } else { PixelConvertType::SetNthComponent(n, outputValue, static_cast( component ) ); } } return outputValue; } template typename StitchImageFilter::InputImageVectorType StitchImageFilter ::GetInputs() { InputImageVectorType inputs; for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); ++i) { auto input = this->GetInput(i); if (nullptr != input) { inputs.push_back(input); } } return inputs; } template typename StitchImageFilter::TransformMapType StitchImageFilter ::GetTransforms() { TransformMapType transforms; for (unsigned int i = 0; i < this->GetNumberOfIndexedInputs(); ++i) { auto input = this->GetInput(i); auto transform = this->GetTransform(i); transforms[input] = transform; } return transforms; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GenerateInputRequestedRegion() { // Call the superclass' implementation of this method Superclass::GenerateInputRequestedRegion(); if ( !this->GetInput() ) { return; } // Get pointers to the input auto inputs = this->GetInputs(); for (auto& input : inputs) { InputImagePointer inputPtr = const_cast(input); // Determining the actual input region is non-trivial, especially // when we cannot assume anything about the transform being used. // So we do the easy thing and request the entire input image. // inputPtr->SetRequestedRegionToLargestPossibleRegion(); } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GenerateOutputInformation() { // Call the superclass' implementation of this method Superclass::GenerateOutputInformation(); // Get pointers to the input and output OutputImageType *outputPtr = this->GetOutput(); if ( !outputPtr ) { return; } const ReferenceImageBaseType *referenceImage = this->GetReferenceImage(); // Set the size of the output region if ( m_UseReferenceImage && referenceImage ) { outputPtr->SetLargestPossibleRegion( referenceImage->GetLargestPossibleRegion() ); } else { typename TOutputImage::RegionType outputLargestPossibleRegion; outputLargestPossibleRegion.SetSize(m_Size); outputLargestPossibleRegion.SetIndex(m_OutputStartIndex); outputPtr->SetLargestPossibleRegion(outputLargestPossibleRegion); } // Set spacing and origin if ( m_UseReferenceImage && referenceImage ) { outputPtr->SetSpacing( referenceImage->GetSpacing() ); outputPtr->SetOrigin( referenceImage->GetOrigin() ); outputPtr->SetDirection( referenceImage->GetDirection() ); } else { outputPtr->SetSpacing(m_OutputSpacing); outputPtr->SetOrigin(m_OutputOrigin); outputPtr->SetDirection(m_OutputDirection); } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > ModifiedTimeType StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GetMTime(void) const { ModifiedTimeType latestTime = Object::GetMTime(); for (const auto& interpolator : m_Interpolators) { if (interpolator.second.GetPointer()) { if (latestTime < interpolator.second->GetMTime()) { latestTime = interpolator.second->GetMTime(); } } } return latestTime; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); os << indent << "DefaultPixelValue: " << static_cast< typename NumericTraits< PixelType >::PrintType > ( m_DefaultPixelValue ) << std::endl; os << indent << "Size: " << m_Size << std::endl; os << indent << "OutputStartIndex: " << m_OutputStartIndex << std::endl; os << indent << "OutputSpacing: " << m_OutputSpacing << std::endl; os << indent << "OutputOrigin: " << m_OutputOrigin << std::endl; os << indent << "OutputDirection: " << m_OutputDirection << std::endl; for (const auto& interpolator : m_Interpolators) { os << indent << "Interpolator: " << interpolator.second.GetPointer() << std::endl; } os << indent << "UseReferenceImage: " << ( m_UseReferenceImage ? "On" : "Off" ) << std::endl; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::EnsureTransforms() { const auto inputCount = this->GetNumberOfIndexedInputs(); for (unsigned int i = 0; i < inputCount; ++i) { auto input = this->GetInput(i); if (nullptr == input) { itkExceptionMacro(<< "Nth input image is not set (n: " << i << ")."); } auto transform = this->GetTransform(i); if (nullptr == transform) { this->SetTransform(i, itk::IdentityTransform< TTransformPrecisionType, ImageDimension>::New().GetPointer()); } } } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > void StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::EnsureInterpolators() { const auto inputCount = this->GetNumberOfIndexedInputs(); InterpolatorMapType newInterpolatorMap; for (unsigned int i = 0; i < inputCount; ++i) { auto input = this->GetInput(i); if (nullptr == input) { itkExceptionMacro(<< "Nth input image is not set (n: " << i << ")."); } if (m_Interpolators[input].IsNull()) { newInterpolatorMap[input] = LinearInterpolatorType::New().GetPointer(); } else { newInterpolatorMap[input] = m_Interpolators[input]; } } m_Interpolators = newInterpolatorMap; } template< typename TInputImage, typename TOutputImage, typename TInterpolatorPrecisionType, typename TTransformPrecisionType > std::string StitchImageFilter< TInputImage, TOutputImage, TInterpolatorPrecisionType, TTransformPrecisionType > ::GetTransformInputName(unsigned int index) { return "transform_" + std::to_string(index); } } // end namespace itk #endif diff --git a/Modules/ModelFit/CMakeLists.txt b/Modules/ModelFit/CMakeLists.txt index 6ddd33235a..673e5e128c 100644 --- a/Modules/ModelFit/CMakeLists.txt +++ b/Modules/ModelFit/CMakeLists.txt @@ -1,19 +1,18 @@ -MITK_CREATE_MODULE(ModelFit +mitk_create_module(ModelFit INCLUDE_DIRS PUBLIC ${MITK_BINARY_DIR} PRIVATE src/Common src/Functors src/Models src/TestingHelper DEPENDS PUBLIC MitkCore MitkSceneSerializationBase PRIVATE MitkMultilabel PACKAGE_DEPENDS - PUBLIC ITK|ITKOptimizers - PRIVATE Boost + PUBLIC ITK|Optimizers ) if(BUILD_TESTING) - ADD_SUBDIRECTORY(test) -endif(BUILD_TESTING) + add_subdirectory(test) +endif() -ADD_SUBDIRECTORY(autoload/IO) -ADD_SUBDIRECTORY(autoload/Models) -ADD_SUBDIRECTORY(cmdapps) +add_subdirectory(autoload/IO) +add_subdirectory(autoload/Models) +add_subdirectory(cmdapps) diff --git a/Modules/ModelFit/cmdapps/CMakeLists.txt b/Modules/ModelFit/cmdapps/CMakeLists.txt index cda6e31973..9ba9628919 100644 --- a/Modules/ModelFit/cmdapps/CMakeLists.txt +++ b/Modules/ModelFit/cmdapps/CMakeLists.txt @@ -1,35 +1,34 @@ option(BUILD_ModelFitMiniApps "Build commandline tools for the ModelFit module" OFF) if(BUILD_ModelFitMiniApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( miniapps GenericFittingMiniApp^^ PixelDumpMiniApp^^ Fuse3Dto4DImageMiniApp^^ ) foreach(miniapp ${miniapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${miniapp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkModelFit ${dependencies_list} - PACKAGE_DEPENDS ITK ) endforeach() endif(BUILD_ModelFitMiniApps OR MITK_BUILD_ALL_APPS) diff --git a/Modules/ModelFit/include/mitkScalarListLookupTablePropertySerializer.h b/Modules/ModelFit/include/mitkScalarListLookupTablePropertySerializer.h index b3db0deccc..d26f60e0d1 100644 --- a/Modules/ModelFit/include/mitkScalarListLookupTablePropertySerializer.h +++ b/Modules/ModelFit/include/mitkScalarListLookupTablePropertySerializer.h @@ -1,55 +1,55 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkScalarListLookupTablePropertySerializer_h #define mitkScalarListLookupTablePropertySerializer_h #include "mitkBasePropertySerializer.h" #include "mitkBaseProperty.h" #include "MitkModelFitExports.h" namespace mitk { /** * @brief Serializer for the ScalarListLookupTableProperty so it can be written and read from * file. */ class ScalarListLookupTablePropertySerializer : public BasePropertySerializer { public: mitkClassMacro(ScalarListLookupTablePropertySerializer, BasePropertySerializer); itkNewMacro(Self); - TiXmlElement* Serialize() override; - BaseProperty::Pointer Deserialize(TiXmlElement* element) override; + tinyxml2::XMLElement* Serialize(tinyxml2::XMLDocument& doc) override; + BaseProperty::Pointer Deserialize(const tinyxml2::XMLElement* element) override; protected: ScalarListLookupTablePropertySerializer() {} ~ScalarListLookupTablePropertySerializer() override {} }; namespace PropertyPersistenceSerialization { /** Serialization of a ScalarListLookupTableProperty into a XML string.*/ MITKMODELFIT_EXPORT ::std::string serializeScalarListLookupTablePropertyToXML(const mitk::BaseProperty *prop); } namespace PropertyPersistenceDeserialization { /**Deserialize a passed XML string into a ScalarListLookupTableProperty.*/ MITKMODELFIT_EXPORT mitk::BaseProperty::Pointer deserializeXMLToScalarListLookupTableProperty(const std::string &value); } } #endif // mitkScalarListLookupTablePropertySerializer_h diff --git a/Modules/ModelFit/src/Common/mitkScalarListLookupTablePropertySerializer.cpp b/Modules/ModelFit/src/Common/mitkScalarListLookupTablePropertySerializer.cpp index 751a407cce..e54b48d683 100644 --- a/Modules/ModelFit/src/Common/mitkScalarListLookupTablePropertySerializer.cpp +++ b/Modules/ModelFit/src/Common/mitkScalarListLookupTablePropertySerializer.cpp @@ -1,127 +1,129 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkScalarListLookupTableProperty.h" #include "mitkScalarListLookupTablePropertySerializer.h" +#include - -TiXmlElement* mitk::ScalarListLookupTablePropertySerializer::Serialize() +tinyxml2::XMLElement* mitk::ScalarListLookupTablePropertySerializer::Serialize(tinyxml2::XMLDocument& doc) { - const ScalarListLookupTableProperty* prop = - dynamic_cast(m_Property.GetPointer()); - - if (prop == nullptr) - { - MITK_ERROR << "Serialization: Property is NULL"; - return nullptr; - } - - ScalarListLookupTable lut = prop->GetValue(); - const ScalarListLookupTable::LookupTableType& map = lut.GetLookupTable(); - - TiXmlElement* mapElement = new TiXmlElement("ScalarListLookupTable"); - - for (ScalarListLookupTable::LookupTableType::const_iterator mapIter = map.begin(); - mapIter != map.end(); ++mapIter) - { - const ScalarListLookupTable::ValueType& list = mapIter->second; - TiXmlElement* listElement = new TiXmlElement("List"); - listElement->SetAttribute("name", mapIter->first); - - for (ScalarListLookupTable::ValueType::const_iterator listIter = list.begin(); - listIter != list.end(); ++listIter) - { - TiXmlElement* valueElement = new TiXmlElement("Element"); - valueElement->SetDoubleAttribute("value", *listIter); - listElement->LinkEndChild(valueElement); - } - - mapElement->LinkEndChild(listElement); - } - - return mapElement; + const ScalarListLookupTableProperty* prop = + dynamic_cast(m_Property.GetPointer()); + + if (prop == nullptr) + { + MITK_ERROR << "Serialization: Property is NULL"; + return nullptr; + } + + ScalarListLookupTable lut = prop->GetValue(); + const ScalarListLookupTable::LookupTableType& map = lut.GetLookupTable(); + + auto* mapElement = doc.NewElement("ScalarListLookupTable"); + + for (ScalarListLookupTable::LookupTableType::const_iterator mapIter = map.begin(); + mapIter != map.end(); ++mapIter) + { + const ScalarListLookupTable::ValueType& list = mapIter->second; + auto* listElement = doc.NewElement("List"); + listElement->SetAttribute("name", mapIter->first.c_str()); + + for (ScalarListLookupTable::ValueType::const_iterator listIter = list.begin(); + listIter != list.end(); ++listIter) + { + auto* valueElement = doc.NewElement("Element"); + valueElement->SetAttribute("value", *listIter); + listElement->InsertEndChild(valueElement); + } + + mapElement->InsertEndChild(listElement); + } + + return mapElement; } mitk::BaseProperty::Pointer -mitk::ScalarListLookupTablePropertySerializer::Deserialize(TiXmlElement* element) +mitk::ScalarListLookupTablePropertySerializer::Deserialize(const tinyxml2::XMLElement* element) { - if (!element) - { - MITK_ERROR << "Deserialization: Element is NULL"; - return nullptr; - } - - ScalarListLookupTable lut; - - for (TiXmlElement* listElement = element->FirstChildElement("List"); - listElement != nullptr; listElement = listElement->NextSiblingElement("List")) - { - std::string name; - - if (listElement->Attribute("name") != nullptr) - { - name = listElement->Attribute("name"); - } - else - { - MITK_ERROR << "Deserialization: No element with attribute 'name' found"; - return nullptr; - } - - ScalarListLookupTable::ValueType list; - - for (TiXmlElement* valueElement = listElement->FirstChildElement("Element"); - valueElement != nullptr; - valueElement = valueElement->NextSiblingElement("Element")) - { - double value; - - if (valueElement->QueryDoubleAttribute("value", &value) == TIXML_WRONG_TYPE) - { - MITK_ERROR << "Deserialization: No element with attribute 'value' found"; - return nullptr; - } - - list.push_back(value); - } - - lut.SetTableValue(name, list); - } - - return ScalarListLookupTableProperty::New(lut).GetPointer(); + if (!element) + { + MITK_ERROR << "Deserialization: Element is NULL"; + return nullptr; + } + + ScalarListLookupTable lut; + + for (auto* listElement = element->FirstChildElement("List"); + listElement != nullptr; listElement = listElement->NextSiblingElement("List")) + { + std::string name; + + if (listElement->Attribute("name") != nullptr) + { + name = listElement->Attribute("name"); + } + else + { + MITK_ERROR << "Deserialization: No element with attribute 'name' found"; + return nullptr; + } + + ScalarListLookupTable::ValueType list; + + for (auto* valueElement = listElement->FirstChildElement("Element"); + valueElement != nullptr; + valueElement = valueElement->NextSiblingElement("Element")) + { + double value; + + if (valueElement->QueryDoubleAttribute("value", &value) != tinyxml2::XML_SUCCESS) + { + MITK_ERROR << "Deserialization: No element with attribute 'value' found"; + return nullptr; + } + + list.push_back(value); + } + + lut.SetTableValue(name, list); + } + + return ScalarListLookupTableProperty::New(lut).GetPointer(); } MITK_REGISTER_SERIALIZER(ScalarListLookupTablePropertySerializer); ::std::string mitk::PropertyPersistenceSerialization::serializeScalarListLookupTablePropertyToXML( const mitk::BaseProperty *prop) { mitk::ScalarListLookupTablePropertySerializer::Pointer lutSerializer = mitk::ScalarListLookupTablePropertySerializer::New(); lutSerializer->SetProperty(prop); - auto xmlLut = lutSerializer->Serialize(); - TiXmlPrinter printer; - xmlLut->Accept(&printer); - printer.SetStreamPrinting(); - return printer.Str(); + tinyxml2::XMLDocument doc; + lutSerializer->Serialize(doc); + + tinyxml2::XMLPrinter printer; + doc.Print(&printer); + + return printer.CStr(); } mitk::BaseProperty::Pointer mitk::PropertyPersistenceDeserialization::deserializeXMLToScalarListLookupTableProperty( const std::string &value) { mitk::ScalarListLookupTablePropertySerializer::Pointer lutSerializer = mitk::ScalarListLookupTablePropertySerializer::New(); - TiXmlDocument doc; + tinyxml2::XMLDocument doc; doc.Parse(value.c_str()); return lutSerializer->Deserialize(doc.RootElement()); } diff --git a/Modules/ModelFitUI/CMakeLists.txt b/Modules/ModelFitUI/CMakeLists.txt index 0e03ef28e4..a5c118715b 100644 --- a/Modules/ModelFitUI/CMakeLists.txt +++ b/Modules/ModelFitUI/CMakeLists.txt @@ -1,5 +1,5 @@ MITK_CREATE_MODULE(ModelFitUI INCLUDE_DIRS Common Qmitk DEPENDS MitkModelFit MitkQtWidgets MitkQtWidgetsExt - PACKAGE_DEPENDS Qt5|Core CTK|CTKWidgets Boost + PACKAGE_DEPENDS CTK|CTKWidgets ) diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index e9a5d07801..c36c213269 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,85 +1,81 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine CoreCmdApps AppUtil LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOM DICOMQI DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel Chart ImageStatistics ContourModel SurfaceInterpolation Segmentation QtWidgets QtWidgetsExt ImageStatisticsUI SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI - PhotoacousticsHardware - PhotoacousticsAlgorithms - PhotoacousticsLib US USUI DICOMUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI RT RTUI IOExt XNAT TubeGraph - BiophotonicsHardware BoundingShape RenderWindowManager RenderWindowManagerUI SemanticRelations SemanticRelationsUI CEST BasicImageProcessing ModelFit ModelFitUI Pharmacokinetics PharmacokineticsUI DICOMPM REST RESTService DICOMweb ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/Multilabel/CMakeLists.txt b/Modules/Multilabel/CMakeLists.txt index 24ed1c1596..51a2a06fd3 100644 --- a/Modules/Multilabel/CMakeLists.txt +++ b/Modules/Multilabel/CMakeLists.txt @@ -1,10 +1,10 @@ -MITK_CREATE_MODULE( +mitk_create_module( DEPENDS MitkCore MitkAlgorithmsExt MitkSceneSerializationBase MitkDICOMQI - PACKAGE_DEPENDS PRIVATE ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD ) add_subdirectory(autoload/IO) add_subdirectory(autoload/DICOMSegIO) + if(BUILD_TESTING) add_subdirectory(Testing) endif() diff --git a/Modules/Multilabel/autoload/IO/CMakeLists.txt b/Modules/Multilabel/autoload/IO/CMakeLists.txt index 9a0856eff7..a61aebf0db 100644 --- a/Modules/Multilabel/autoload/IO/CMakeLists.txt +++ b/Modules/Multilabel/autoload/IO/CMakeLists.txt @@ -1,6 +1,5 @@ -MITK_CREATE_MODULE( MultilabelIO +mitk_create_module(MultilabelIO DEPENDS PUBLIC MitkMultilabel MitkSceneSerialization - PACKAGE_DEPENDS - PRIVATE ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD + PACKAGE_DEPENDS PRIVATE ITK|IONRRD AUTOLOAD_WITH MitkCore ) diff --git a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp index 0e041818c9..981ea9cf30 100644 --- a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp +++ b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp @@ -1,652 +1,648 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkLabelSetImageWriter__cpp #define __mitkLabelSetImageWriter__cpp #include "mitkLabelSetImageIO.h" #include "mitkBasePropertySerializer.h" #include "mitkIOMimeTypes.h" #include "mitkImageAccessByItk.h" #include "mitkLabelSetIOHelper.h" #include "mitkLabelSetImageConverter.h" #include #include #include #include #include #include // itk #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" +#include + namespace mitk { const char* const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type"; const char* const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints"; const char* const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type"; const char* const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints"; const char* const PROPERTY_KEY_UID = "org_mitk_uid"; LabelSetImageIO::LabelSetImageIO() : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::NRRD_MIMETYPE(), "MITK Multilabel Image") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel LabelSetImageIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const auto *input = static_cast(this->GetInput()); if (input) return Supported; else return Unsupported; } void LabelSetImageIO::Write() { ValidateOutputLocation(); auto input = dynamic_cast(this->GetInput()); mitk::LocaleSwitch localeSwitch("C"); mitk::Image::Pointer inputVector = mitk::ConvertLabelSetImageToImage(input); // image write if (inputVector.IsNull()) { mitkThrow() << "Cannot write non-image data"; } itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New(); // Clone the image geometry, because we might have to change it // for writing purposes BaseGeometry::Pointer geometry = inputVector->GetGeometry()->Clone(); // Check if geometry information will be lost if (inputVector->GetDimension() == 2 && !geometry->Is2DConvertable()) { MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might " "consider using Convert2Dto3DImageFilter before saving."; // set matrix to identity mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); mitk::Vector3D spacing = geometry->GetSpacing(); mitk::Point3D origin = geometry->GetOrigin(); geometry->SetIndexToWorldTransform(affTrans); geometry->SetSpacing(spacing); geometry->SetOrigin(origin); } LocalFile localFile(this); const std::string path = localFile.GetFileName(); MITK_INFO << "Writing image: " << path << std::endl; try { // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. const unsigned int dimension = inputVector->GetDimension(); const unsigned int *const dimensions = inputVector->GetDimensions(); const mitk::PixelType pixelType = inputVector->GetPixelType(); const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); const mitk::Point3D mitkOrigin = geometry->GetOrigin(); // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, // though they are not supported in MITK itk::Vector spacing4D; spacing4D[0] = mitkSpacing[0]; spacing4D[1] = mitkSpacing[1]; spacing4D[2] = mitkSpacing[2]; spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here itk::Vector origin4D; origin4D[0] = mitkOrigin[0]; origin4D[1] = mitkOrigin[1]; origin4D[2] = mitkOrigin[2]; origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here // Set the necessary information for imageIO nrrdImageIo->SetNumberOfDimensions(dimension); nrrdImageIo->SetPixelType(pixelType.GetPixelType()); nrrdImageIo->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? static_cast(pixelType.GetComponentType()) : itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); nrrdImageIo->SetNumberOfComponents(pixelType.GetNumberOfComponents()); itk::ImageIORegion ioRegion(dimension); for (unsigned int i = 0; i < dimension; i++) { nrrdImageIo->SetDimensions(i, dimensions[i]); nrrdImageIo->SetSpacing(i, spacing4D[i]); nrrdImageIo->SetOrigin(i, origin4D[i]); mitk::Vector3D mitkDirection; mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); itk::Vector direction4D; direction4D[0] = mitkDirection[0]; direction4D[1] = mitkDirection[1]; direction4D[2] = mitkDirection[2]; // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. if (i == 3) { direction4D[3] = 1; // homogenous component } else { direction4D[3] = 0; } vnl_vector axisDirection(dimension); for (unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction4D[j] / spacing4D[i]; } nrrdImageIo->SetDirection(i, axisDirection); ioRegion.SetSize(i, inputVector->GetLargestPossibleRegion().GetSize(i)); ioRegion.SetIndex(i, inputVector->GetLargestPossibleRegion().GetIndex(i)); } // use compression if available nrrdImageIo->UseCompressionOn(); nrrdImageIo->SetIORegion(ioRegion); nrrdImageIo->SetFileName(path); // label set specific meta data char keybuffer[512]; char valbuffer[512]; sprintf(keybuffer, "modality"); sprintf(valbuffer, "org.mitk.image.multilabel"); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); sprintf(keybuffer, "layers"); sprintf(valbuffer, "%1d", input->GetNumberOfLayers()); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); for (unsigned int layerIdx = 0; layerIdx < input->GetNumberOfLayers(); layerIdx++) { sprintf(keybuffer, "layer_%03u", layerIdx); // layer idx sprintf(valbuffer, "%1u", input->GetNumberOfLabels(layerIdx)); // number of labels for the layer itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); auto iter = input->GetLabelSet(layerIdx)->IteratorConstBegin(); unsigned int count(0); while (iter != input->GetLabelSet(layerIdx)->IteratorConstEnd()) { - std::unique_ptr document; - document.reset(new TiXmlDocument()); - - auto *decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc.... - document->LinkEndChild(decl); - TiXmlElement *labelElem = mitk::LabelSetIOHelper::GetLabelAsTiXmlElement(iter->second); - document->LinkEndChild(labelElem); - TiXmlPrinter printer; - printer.SetIndent(""); - printer.SetLineBreak(""); - - document->Accept(&printer); + tinyxml2::XMLDocument document; + document.InsertEndChild(document.NewDeclaration()); + auto *labelElem = mitk::LabelSetIOHelper::GetLabelAsXMLElement(document, iter->second); + document.InsertEndChild(labelElem); + tinyxml2::XMLPrinter printer; + document.Print(&printer); sprintf(keybuffer, "org.mitk.label_%03u_%05u", layerIdx, count); itk::EncapsulateMetaData( - nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), printer.Str()); + nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), printer.CStr()); ++iter; ++count; } } // end label set specific meta data // Handle time geometry const auto* arbitraryTG = dynamic_cast(input->GetTimeGeometry()); if (arbitraryTG) { itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TYPE, ArbitraryTimeGeometry::GetStaticNameOfClass()); auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG); nrrdImageIo->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints); } // Handle properties mitk::PropertyList::Pointer imagePropertyList = input->GetPropertyList(); for (const auto& property : *imagePropertyList->GetMap()) { mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true); if (infoList.empty()) { continue; } std::string value = infoList.front()->GetSerializationFunction()(property.second); if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING) { continue; } std::string key = infoList.front()->GetKey(); itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), key, value); } // Handle UID itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), PROPERTY_KEY_UID, input->GetUID()); ImageReadAccessor imageAccess(inputVector); nrrdImageIo->Write(imageAccess.GetData()); } catch (const std::exception &e) { mitkThrow() << e.what(); } // end image write } IFileIO::ConfidenceLevel LabelSetImageIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; const std::string fileName = this->GetLocalFileName(); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(fileName); io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary(); std::string value(""); itk::ExposeMetaData(imgMetaDataDictionary, "modality", value); if (value.compare("org.mitk.image.multilabel") == 0) { return Supported; } else return Unsupported; } std::vector LabelSetImageIO::DoRead() { mitk::LocaleSwitch localeSwitch("C"); // begin regular image loading, adapted from mitkItkImageIO itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New(); Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; const std::string path = this->GetLocalFileName(); MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << std::endl; // Check to see if we can read the file given the name or prefix if (path.empty()) { mitkThrow() << "Empty filename in mitk::ItkImageIO "; } // Got to allocate space for the image. Determine the characteristics of // the image. nrrdImageIO->SetFileName(path); nrrdImageIO->ReadImageInformation(); unsigned int ndim = nrrdImageIO->GetNumberOfDimensions(); if (ndim < MINDIM || ndim > MAXDIM) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion(ndim); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[MAXDIM]; dimensions[0] = 0; dimensions[1] = 0; dimensions[2] = 0; dimensions[3] = 0; ScalarType spacing[MAXDIM]; spacing[0] = 1.0f; spacing[1] = 1.0f; spacing[2] = 1.0f; spacing[3] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for (i = 0; i < ndim; ++i) { ioStart[i] = 0; ioSize[i] = nrrdImageIO->GetDimensions(i); if (i < MAXDIM) { dimensions[i] = nrrdImageIO->GetDimensions(i); spacing[i] = nrrdImageIO->GetSpacing(i); if (spacing[i] <= 0) spacing[i] = 1.0f; } if (i < 3) { origin[i] = nrrdImageIO->GetOrigin(i); } } ioRegion.SetSize(ioSize); ioRegion.SetIndex(ioStart); MITK_INFO << "ioRegion: " << ioRegion << std::endl; nrrdImageIO->SetIORegion(ioRegion); void *buffer = new unsigned char[nrrdImageIO->GetImageSizeInBytes()]; nrrdImageIO->Read(buffer); image->Initialize(MakePixelType(nrrdImageIO), ndim, dimensions); image->SetImportChannel(buffer, 0, Image::ManageMemory); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim); for (i = 0; i < itkDimMax3; ++i) for (j = 0; j < itkDimMax3; ++j) matrix[i][j] = nrrdImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false); MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true); // re-initialize TimeGeometry const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary(); TimeGeometry::Pointer timeGeometry; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE)) { // also check for the name because of backwards compatibility. Past code version stored with the name and not with // the key itk::MetaDataObject::ConstPointer timeGeometryTypeData; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE)) { timeGeometryTypeData = dynamic_cast*>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE)); } else { timeGeometryTypeData = dynamic_cast*>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE)); } if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass()) { MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass(); typedef std::vector TimePointVector; TimePointVector timePoints; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)); } else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)); } if (timePoints.empty()) { MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback"; } else if (timePoints.size() - 1 != image->GetDimension(3)) { MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension (" << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback"; } else { ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New(); TimePointVector::const_iterator pos = timePoints.begin(); auto prePos = pos++; for (; pos != timePoints.end(); ++prePos, ++pos) { arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos); } timeGeometry = arbitraryTimeGeometry; } } } if (timeGeometry.IsNull()) { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass(); ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); timeGeometry = propTimeGeometry; } image->SetTimeGeometry(timeGeometry); buffer = nullptr; MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents(); // end regular image loading LabelSetImage::Pointer output = ConvertImageToLabelSetImage(image); // get labels and add them as properties to the image char keybuffer[256]; unsigned int numberOfLayers = GetIntByKey(dictionary, "layers"); std::string _xmlStr; mitk::Label::Pointer label; for (unsigned int layerIdx = 0; layerIdx < numberOfLayers; layerIdx++) { sprintf(keybuffer, "layer_%03u", layerIdx); int numberOfLabels = GetIntByKey(dictionary, keybuffer); mitk::LabelSet::Pointer labelSet = mitk::LabelSet::New(); for (int labelIdx = 0; labelIdx < numberOfLabels; labelIdx++) { - TiXmlDocument doc; + tinyxml2::XMLDocument doc; sprintf(keybuffer, "label_%03u_%05d", layerIdx, labelIdx); _xmlStr = GetStringByKey(dictionary, keybuffer); - doc.Parse(_xmlStr.c_str()); + doc.Parse(_xmlStr.c_str(), _xmlStr.size()); - TiXmlElement *labelElem = doc.FirstChildElement("Label"); + auto *labelElem = doc.FirstChildElement("Label"); if (labelElem == nullptr) mitkThrow() << "Error parsing NRRD header for mitk::LabelSetImage IO"; - label = mitk::LabelSetIOHelper::LoadLabelFromTiXmlDocument(labelElem); + label = mitk::LabelSetIOHelper::LoadLabelFromXMLDocument(labelElem); if (label->GetValue() == 0) // set exterior label is needed to hold exterior information output->SetExteriorLabel(label); labelSet->AddLabel(label); labelSet->SetLayer(layerIdx); } output->AddLabelSetToLayer(layerIdx, labelSet); } for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { const std::string& key = iter->first; std::string assumedPropertyName = key; std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.'); std::string mimeTypeName = GetMimeType()->GetName(); // Check if there is already a info for the key and our mime type. mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key); auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer& x) { return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName; }; auto finding = std::find_if(infoList.begin(), infoList.end(), predicate); if (finding == infoList.end()) { auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer& x) { return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; finding = std::find_if(infoList.begin(), infoList.end(), predicateWild); } PropertyPersistenceInfo::ConstPointer info; if (finding != infoList.end()) { assumedPropertyName = (*finding)->GetName(); info = *finding; } else { // we have not found anything suitable so we generate our own info auto newInfo = PropertyPersistenceInfo::New(); newInfo->SetNameAndKey(assumedPropertyName, key); newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); info = newInfo; } std::string value = dynamic_cast*>(iter->second.GetPointer())->GetMetaDataObjectValue(); mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value); output->SetProperty(assumedPropertyName.c_str(), loadedProp); // Read properties should be persisted unless they are default properties // which are written anyway bool isDefaultKey = false; for (const auto& defaultKey : m_DefaultMetaDataKeys) { if (defaultKey.length() <= assumedPropertyName.length()) { // does the start match the default key if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos) { isDefaultKey = true; break; } } } if (!isDefaultKey) { propPersistenceService->AddInfo(info); } } } // Handle UID if (dictionary.HasKey(PROPERTY_KEY_UID)) { itk::MetaDataObject::ConstPointer uidData = dynamic_cast*>(dictionary.Get(PROPERTY_KEY_UID)); if (uidData.IsNotNull()) { mitk::UIDManipulator uidManipulator(output); uidManipulator.SetUID(uidData->GetMetaDataObjectValue()); } } MITK_INFO << "...finished!"; std::vector result; result.push_back(output.GetPointer()); return result; } int LabelSetImageIO::GetIntByKey(const itk::MetaDataDictionary &dic, const std::string &str) { std::vector imgMetaKeys = dic.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString(""); for (; itKey != imgMetaKeys.end(); itKey++) { itk::ExposeMetaData(dic, *itKey, metaString); if (itKey->find(str.c_str()) != std::string::npos) { return atoi(metaString.c_str()); } } return 0; } std::string LabelSetImageIO::GetStringByKey(const itk::MetaDataDictionary &dic, const std::string &str) { std::vector imgMetaKeys = dic.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString(""); for (; itKey != imgMetaKeys.end(); itKey++) { itk::ExposeMetaData(dic, *itKey, metaString); if (itKey->find(str.c_str()) != std::string::npos) { return metaString; } } return metaString; } LabelSetImageIO *LabelSetImageIO::IOClone() const { return new LabelSetImageIO(*this); } void LabelSetImageIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); this->m_DefaultMetaDataKeys.push_back("label_"); this->m_DefaultMetaDataKeys.push_back("layer_"); } } // namespace #endif //__mitkLabelSetImageWriter__cpp diff --git a/Modules/Multilabel/mitkLabel.cpp b/Modules/Multilabel/mitkLabel.cpp index b7952a6ef9..f2b6df44c5 100644 --- a/Modules/Multilabel/mitkLabel.cpp +++ b/Modules/Multilabel/mitkLabel.cpp @@ -1,299 +1,298 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkLabel.h" #include "itkProcessObject.h" -#include "tinyxml.h" #include #include #include #include const mitk::Label::PixelType mitk::Label::MAX_LABEL_VALUE = std::numeric_limits::max(); mitk::Label::Label() : PropertyList() { if (GetProperty("locked") == nullptr) SetLocked(true); if (GetProperty("visible") == nullptr) SetVisible(true); if (GetProperty("opacity") == nullptr) SetOpacity(0.6); if (GetProperty("center.coordinates") == nullptr) { mitk::Point3D pnt; pnt.SetElement(0, 0); pnt.SetElement(1, 0); pnt.SetElement(2, 0); SetCenterOfMassCoordinates(pnt); } if (GetProperty("center.index") == nullptr) { mitk::Point3D pnt; pnt.SetElement(0, 0); pnt.SetElement(1, 0); pnt.SetElement(2, 0); SetCenterOfMassIndex(pnt); } if (GetProperty("color") == nullptr) { mitk::Color col; col.Set(0, 0, 0); SetColor(col); } if (GetProperty("name") == nullptr) SetName("noName!"); if (GetProperty("value") == nullptr) SetValue(0); if (GetProperty("layer") == nullptr) SetLayer(0); DICOMSegmentationPropertyHelper::SetDICOMSegmentProperties(this); } mitk::Label::Label(const Label &other) : PropertyList(other) // copyconstructer of property List handles the coping action { auto *map = this->GetMap(); auto it = map->begin(); auto end = map->end(); for (; it != end; ++it) { itk::SimpleMemberCommand