diff --git a/.gitignore b/.gitignore index 6dc15fe70e..d2c2b36283 100644 --- a/.gitignore +++ b/.gitignore @@ -1,79 +1,86 @@ CMakeLists.txt.user* .clang_complete .clangd .autosave *.stackdump ########## Git related # Patches and similar *.patch *.diff *.rej *.orig !Utilities/qtsingleapplication/*.patch !CMakeExternals/*.patch ########## IDE specific ## Office ~$* ## vim Session.vim *.swp *.swo .vimrc ## Emacs \#*\# /.emacs.desktop /.emacs.desktop.lock .elc auto-save-list tramp .\#* ## Eclipse .cproject .project .settings/ +## PyCharm +.idea/ + +## Python +*.pyc +__pycache__/ + # Org-mode .org-id-locations *_archive # Visual Studio / VS Code .vs/ out/ CMakeSettings.json ########## OS specific ## Windows files to ignore # Windows image file caches Thumbs.db ehthumbs.db # Folder config file Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ ## OSX specific .DS_Store .AppleDouble .LSOverride Icon # Thumbnails ._* # Files that might appear on external disk .Spotlight-V100 .Trashes ## Linux *~ diff --git a/CMake/mitkLanguageOptions.cmake b/CMake/mitkLanguageOptions.cmake deleted file mode 100644 index 50284ce611..0000000000 --- a/CMake/mitkLanguageOptions.cmake +++ /dev/null @@ -1,72 +0,0 @@ -# -# This module finds the languages supported by MITK, and -# present the option to enable support. -# - -# -# This script is based on SimpleITK scripts. -# - -option(WRAP_DEFAULT "The default initial value for wrapping a language when it is detected on the system." OFF) -mark_as_advanced(WRAP_DEFAULT) - -# -# Macro to set "_QUIET" and "_QUIET_LIBRARY" based on the first -# argument being defined and true, to either REQUIRED or QUIET. -# -macro(set_QUIET var) - if ( DEFINED ${var} AND ${var} ) - set( _QUIET "REQUIRED" ) - else() - set( _QUIET "QUIET" ) - endif() - if ( SITK_UNDEFINED_SYMBOLS_ALLOWED ) - set( _QUIET_LIBRARY "QUIET" ) - else() - set( _QUIET_LIBRARY ${_QUIET} ) - endif() -endmacro() - -# -# Setup the option for each language -# - -#----------------------------------------------------------- -# Python - -set_QUIET( WRAP_PYTHON ) -find_package ( PythonInterp ${_QUIET}) -if ( PYTHONINTERP_FOUND ) - find_package ( PythonLibs ${PYTHON_VERSION_STRING} EXACT ${_QUIET_LIBRARY} ) -else () - find_package ( PythonLibs ${_QUIET_LIBRARY} ) -endif() - -if ( PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND - AND (PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING) ) - set( WRAP_PYTHON_DEFAULT ${WRAP_DEFAULT} ) -else() - set( WRAP_PYTHON_DEFAULT OFF ) -endif() - -option( WRAP_PYTHON "Wrap Python" ${WRAP_PYTHON_DEFAULT} ) - -if ( WRAP_PYTHON AND PYTHON_VERSION_STRING VERSION_LESS 2.7 ) - message( WARNING "Python version less than 2.7: \"${PYTHON_VERSION_STRING}\"." ) -endif() - -if ( WRAP_PYTHON ) - list( APPEND SITK_LANGUAGES_VARS - PYTHON_DEBUG_LIBRARY - PYTHON_EXECUTABLE - PYTHON_LIBRARY - PYTHON_INCLUDE_DIR - ) -# Debian "jessie" has this additional variable required to match -# python versions. - if(PYTHON_INCLUDE_DIR2) - list( APPEND SITK_LANGUAGES_VARS - PYTHON_INCLUDE_DIR2 - ) - endif() -endif () diff --git a/CMake/mitkSwigAddLibraryDependencies.cmake b/CMake/mitkSwigAddLibraryDependencies.cmake deleted file mode 100644 index bdcf1bffa9..0000000000 --- a/CMake/mitkSwigAddLibraryDependencies.cmake +++ /dev/null @@ -1,30 +0,0 @@ -#! This CMake macro adds the necessary library and incllude -#! directories to a swig-project. -#! -#! params: -#! swig_module : Name of the SWIG module, for example pyMITK -#! library_names : Semicolon separated list of the libraries that are included, for example "MitkCore;mbilog" -#! - - -# function inspired by -# https://stackoverflow.com/questions/37205274/swig-and-cmake-make-use-of-information-provided-by-target-include-directories -# This function tells cmake which additional dependencies are existing -# especially with respect to the linker dependencies. -function(mitkSwigAddLibraryDependencies swig_module library_names) - foreach(library_name ${library_names}) - # Adding each library as a linker dependency: - swig_link_libraries(${swig_module} ${library_name}) - # Extracting all include directories from each given project and - # then including these directories to the newly created swig project. - get_property(LIBRARY_INCLUDES - TARGET ${library_name} - PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - # Checking each given librarie to include all includes from this library. - - endforeach() - - # In addition include python dependencies: - include_directories( ${PYTHON_INCLUDE_DIR}) - -endfunction() diff --git a/CMake/mitkSwigPrepareFiles.cmake b/CMake/mitkSwigPrepareFiles.cmake index 7e74d24aff..94f4b33ca6 100644 --- a/CMake/mitkSwigPrepareFiles.cmake +++ b/CMake/mitkSwigPrepareFiles.cmake @@ -1,56 +1,56 @@ # This function is used to prepare all includes and files -# that are necessary for a general swig project. -function(mitkSwigPrepareFiles swig_module swig_file library_names) - # Ensure that the input file is parsed as a c++ file. This is done via - # an additional source file property. +# that are necessary for a general swig project. +function(mitkSwigPrepareFiles swig_module swig_file) + # Ensure that the input file is parsed as a c++ file. This is done via + # an additional source file property. set_source_files_properties ( ${swig_file} PROPERTIES CPLUSPLUS ON ) - - # This variable is used to add additional parameters to SWIG. + + # This variable is used to add additional parameters to SWIG. # Using a list is necessary in order to be able to pass multiple parameters - # which are given as optional parameters to the input file. + # which are given as optional parameters to the input file. set(ADDITIONAL_TMP_SWIG_INCLUDES "") - foreach(library_name ${library_names}) + foreach(library_name ${ARGN}) # Extracting all include directories from each given project and - # then including these directories to the newly created swig project. - get_property(LIBRARY_INCLUDES + # then including these directories to the newly created swig project. + get_property(LIBRARY_INCLUDES TARGET ${library_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES) - # Adding each include path as an additional swig parameter using + # Adding each include path as an additional swig parameter using # the swig-option "-I": - foreach(INCLUDE_PATH ${LIBRARY_INCLUDES}) + foreach(INCLUDE_PATH ${LIBRARY_INCLUDES} ${ITK_INCLUDE_DIRS}) list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -I${INCLUDE_PATH} ) file(GLOB_RECURSE header_files "${INCLUDE_PATH}/*.h") list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${header_files}) # export variable to parent scope set(SWIG_MODULE_${swig_module}_EXTRA_DEPS ${SWIG_MODULE_${swig_module}_EXTRA_DEPS} PARENT_SCOPE) endforeach() endforeach() - + # Add the Common Folder to the include system of SWIG list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -I${MITK_WRAPPING_COMMON_DIR} ) # This is necessary, because SWIG hard-codeds the integer size. See # https://github.com/swig/swig/issues/568 if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") list(APPEND ADDITIONAL_TMP_SWIG_INCLUDES -DSWIGWORDSIZE64) endif() # Set the additional parameters to the input project file: set_property(SOURCE ${swig_file} PROPERTY SWIG_FLAGS ${ADDITIONAL_TMP_SWIG_INCLUDES} ) # In addition include python dependencies: - include_directories( ${PYTHON_INCLUDE_DIR}) - list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${PYTHON_INCLUDE_DIR}) + include_directories( ${Python3_INCLUDE_DIRS}) + list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${Python3_INCLUDE_DIRS}) # Add additional include paths, for example to the common files: list(APPEND SWIG_MODULE_${swig_module}_EXTRA_DEPS ${SWIG_EXTRA_DEPS}) set(SWIG_MODULE_${swig_module}_EXTRA_DEPS ${SWIG_MODULE_${swig_module}_EXTRA_DEPS} PARENT_SCOPE) endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index aaecc5a94a..e112e97467 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1385 +1,1401 @@ #[[ When increasing the minimum required version, check if Boost_ADDITIONAL_VERSIONS in CMake/PackageDepends/MITK_Boost_Config.cmake can be removed. See the first long comment in CMakeExternals/Boost.cmake for details. ]] 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() #----------------------------------------------------------------------------- # Policies #----------------------------------------------------------------------------- #[[ 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 2022.10.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() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 17) 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++ flag for targets. # However, compile flag checks also need to be done with -std=c++. # The MITK_CXX_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++${MITK_CXX_STANDARD}" MITK_CXX${MITK_CXX_STANDARD}_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) mark_as_advanced( MITK_XVFB_TESTING MITK_FAST_TESTING MITK_BUILD_ALL_APPS ) #----------------------------------------------------------------------------- # 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 2022) list(APPEND _compilers "msvc2019" "msvc2017") # Binary compatible elseif (CMAKE_MATCH_0 EQUAL 2019) list(APPEND _compilers "msvc2017") # Binary compatible 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 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) 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(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() + link_directories(${Python3_LIBRARY_DIRS}) 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(mitkFunctionAddManifest) 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 #----------------------------------------------------------------------------- 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) #----------------------------------------------------------------------------- if(OpenSSL_FOUND AND WIN32) set(MITK_OPENSSL_SSL_DLL "" CACHE FILEPATH "") set(MITK_OPENSSL_CRYPTO_DLL "" CACHE FILEPATH "") if(MITK_OPENSSL_SSL_DLL AND EXISTS "${MITK_OPENSSL_SSL_DLL}" AND MITK_OPENSSL_CRYPTO_DLL AND EXISTS "${MITK_OPENSSL_CRYPTO_DLL}") foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) execute_process(COMMAND "${CMAKE_COMMAND}" -E make_directory "${MITK_BINARY_DIR}/bin/${config_type}") configure_file("${MITK_OPENSSL_SSL_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) configure_file("${MITK_OPENSSL_CRYPTO_DLL}" "${MITK_BINARY_DIR}/bin/${config_type}/" COPYONLY) endforeach() MITK_INSTALL(FILES "${MITK_OPENSSL_SSL_DLL}" "${MITK_OPENSSL_CRYPTO_DLL}" ) endif() endif() # 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) # As of Windows 10 Version 1903 (May 2019 Update), applications can use the UTF-8 code page if(WIN32) option(MITK_UTF8 "Use UTF-8 code page in MITK applications on Windows" ON) mark_as_advanced(MITK_UTF8) endif() 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_CXX${MITK_CXX_STANDARD}_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} -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-deprecated-copy -Wno-array-bounds -Wno-cast-function-type -Wno-maybe-uninitialized -Wno-error=stringop-overread -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.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) 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() endif() if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() if(MITK_USE_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) +set(MITK_WRAP_PYTHON_ENABLED OFF) +if(MITK_USE_SWIG AND MITK_USE_Python3) + find_package(SWIG 4.0.2 COMPONENTS python) + + if(SWIG_FOUND) + option(MITK_WRAP_PYTHON "" ON) + + if(MITK_WRAP_PYTHON) + set(MITK_WRAP_PYTHON_ENABLED ON) + endif() + else() + message(SEND_ERROR "SWIG not found!") + endif() +endif() + 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 #----------------------------------------------------------------------------- set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS) set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS) foreach(MITK_EXTENSION_DIR ${MITK_DIR_PLUS_EXTENSION_DIRS}) set(MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS "${MITK_DOXYGEN_ADDITIONAL_INPUT_DIRS} \"${MITK_EXTENSION_DIR}\"") set(MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS "${MITK_DOXYGEN_ADDITIONAL_IMAGE_PATHS} \"${MITK_EXTENSION_DIR}\"") endforeach() 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/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox index ca06401761..5cca91ab3e 100644 --- a/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/MITKModuleManualsList.dox @@ -1,17 +1,18 @@ /** \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 mitkPython_Overview \li \subpage RESTModule \li \subpage GeneratingDeviceModulesPage \li \subpage USModulePage + \li \subpage DeepLearningSegmentationModule */ diff --git a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox index 1891d949b6..d9b1fc41f5 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Toolkit/ModuleManuals/MITKModuleManualsList.dox @@ -1,35 +1,36 @@ /** \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 mitkPython_Overview
  • \ref RESTModule
  • \ref GeneratingDeviceModulesPage
  • \ref USModulePage +
  • \ref DeepLearningSegmentationModule
\subpage MITKModuleManualsListPageAdditionalInformation Additional Information on Certain Modules
  • \ref PlanarPropertiesPage
\subpage MITKMigrationGuides Migration Guides
  • \ref GeometryMigration
  • \ref InteractionMigration
  • \ref OverlayMigration
*/ diff --git a/Examples/Plugins/PluginList.cmake b/Examples/Plugins/PluginList.cmake index b9d0c5d492..1f986c8b36 100644 --- a/Examples/Plugins/PluginList.cmake +++ b/Examples/Plugins/PluginList.cmake @@ -1,25 +1,26 @@ # Plug-ins must be ordered according to their dependencies set(MITK_EXAMPLE_PLUGINS org.mitk.example.gui.minimalapplication:ON org.mitk.example.gui.customviewer:ON org.mitk.example.gui.customviewer.views:ON org.mitk.example.gui.multipleperspectives:ON org.mitk.example.gui.selectionserviceqt:ON org.mitk.example.gui.selectionservicemitk:ON org.mitk.example.gui.selectionservicemitk.views:ON org.mitk.example.gui.extensionpointdefinition:ON org.mitk.example.gui.extensionpointcontribution:ON org.mitk.example.gui.regiongrowing:ON org.mitk.example.gui.pcaexample:ON org.mitk.example.gui.imaging:ON + org.mitk.example.gui.pythonexample:ON ) if(MITK_USE_OpenCV) list(APPEND MITK_EXAMPLE_PLUGINS org.mitk.example.gui.opencv:ON) else() list(APPEND MITK_EXAMPLE_PLUGINS org.mitk.example.gui.opencv:OFF) endif() diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/CMakeLists.txt b/Examples/Plugins/org.mitk.example.gui.pythonexample/CMakeLists.txt new file mode 100644 index 0000000000..8bb09bbf5d --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_example_gui_pythonexample) + +mitk_create_plugin( + EXPORT_DIRECTIVE PYTHONEXAMPLE_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkPython +) diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/files.cmake b/Examples/Plugins/org.mitk.example.gui.pythonexample/files.cmake new file mode 100644 index 0000000000..f6f9f8fdbd --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/files.cmake @@ -0,0 +1,44 @@ +set(SRC_CPP_FILES + +) + +set(INTERNAL_CPP_FILES + org_mitk_example_gui_pythonexample_Activator.cpp + PythonExample.cpp + PythonWorker.cpp +) + +set(UI_FILES + src/internal/PythonExampleControls.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_example_gui_pythonexample_Activator.h + src/internal/PythonExample.h + src/internal/PythonWorker.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/icon.xpm + plugin.xml +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/manifest_headers.cmake b/Examples/Plugins/org.mitk.example.gui.pythonexample/manifest_headers.cmake new file mode 100644 index 0000000000..1c8c1b2bfd --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "Python Example") +set(Plugin-Version "0.1") +set(Plugin-Vendor "German Cancer Research Center (DKFZ)") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/plugin.xml b/Examples/Plugins/org.mitk.example.gui.pythonexample/plugin.xml new file mode 100644 index 0000000000..2669e08e5e --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/hello.py b/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/hello.py new file mode 100644 index 0000000000..d79cdc10c7 --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/hello.py @@ -0,0 +1,8 @@ +import time + +inc = 1 +while inc<=3: + print(inc) + inc+=1 + time.sleep(5) +print("Done") \ No newline at end of file diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/icon.xpm b/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/icon.xpm new file mode 100644 index 0000000000..9057c20bc6 --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/resources/icon.xpm @@ -0,0 +1,21 @@ +/* XPM */ +static const char * icon_xpm[] = { +"16 16 2 1", +" c #FF0000", +". c #000000", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.cpp b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.cpp new file mode 100644 index 0000000000..1f33f693fc --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.cpp @@ -0,0 +1,89 @@ +/*============================================================================ + +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"org_mitk_example_gui_pythonexample_Activator.h" +// Blueberry +#include +#include + +// Qmitk +#include "PythonExample.h" + +// Qt +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + + +US_INITIALIZE_MODULE + + +const std::string PythonExample::VIEW_ID = "org.mitk.views.pythonexample"; + +PythonExample::~PythonExample() +{ + if (m_PythonThread->isRunning()) + { + m_PythonThread->quit(); + } +} + +void PythonExample::SetFocus() +{ + m_Controls.buttonRunPythonCode->setFocus(); +} + +void PythonExample::CreateQtPartControl(QWidget *parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + connect(m_Controls.buttonRunPythonCode, &QPushButton::clicked, this, &PythonExample::OnRunPythonCode); + m_Controls.labelCodeRunning->setVisible(false); + m_PythonThread = new QThread; + m_Worker = new PythonWorker; + m_Worker->moveToThread(m_PythonThread); + connect(m_PythonThread, &QThread::finished, m_Worker, &QObject::deleteLater); + connect(this, &PythonExample::Operate, m_Worker, &PythonWorker::DoWork); + connect(m_Worker, &PythonWorker::Finished, this, &PythonExample::ExecutionFinished); + connect(m_Worker, &PythonWorker::Failed, this, &PythonExample::ExecutionFailed); +} + +void PythonExample::OnRunPythonCode() +{ + MITK_INFO << "[Start] Run Python Code"; + m_Controls.labelCodeRunning->setVisible(true); + m_Controls.buttonRunPythonCode->setEnabled(false); + m_PythonThread->start(); + emit Operate(); +} + +void PythonExample::ExecutionFinished() +{ + QMessageBox::information(nullptr, "Finished python execution", "Execution of python code finished successfully."); + m_Controls.labelCodeRunning->setVisible(false); + m_Controls.buttonRunPythonCode->setEnabled(true); +} + +void PythonExample::ExecutionFailed() +{ + QMessageBox::warning(nullptr, "Error in running python", "There was an error running the Python Code."); + m_Controls.labelCodeRunning->setVisible(false); + m_Controls.buttonRunPythonCode->setEnabled(true); +} diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.h b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.h new file mode 100644 index 0000000000..5437850da7 --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExample.h @@ -0,0 +1,71 @@ +/*============================================================================ + +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 PythonExample_h +#define PythonExample_h + +#include + +#include + +#include "PythonWorker.h" + +#include "ui_PythonExampleControls.h" +#include +#include +#include + +/** + \brief PythonExample + + \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + + \sa QmitkAbstractView + \ingroup ${plugin_target}_internal +*/ +class PythonExample : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + static const std::string VIEW_ID; + ~PythonExample(); + +signals: + void Operate(); + +protected: + virtual void CreateQtPartControl(QWidget *parent) override; + + virtual void SetFocus() override; + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + //virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, + // const QList &nodes) override; + + /// \brief Called when the user clicks the GUI button + void OnRunPythonCode(); + + void ExecutionFinished(); + + void ExecutionFailed(); + + QThread* m_PythonThread; + PythonWorker *m_Worker; + + Ui::PythonExampleControls m_Controls; +}; + +#endif // PythonExample_h diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExampleControls.ui b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExampleControls.ui new file mode 100644 index 0000000000..346c4ebb04 --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonExampleControls.ui @@ -0,0 +1,61 @@ + + + PythonExampleControls + + + + 0 + 0 + 222 + 161 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + Do image processing + + + RunPythonCode + + + + + + + <html><head/><body><p><span style=" color:#ff0000;">Python Code running...</span></p></body></html> + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 220 + + + + + + + + + + diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.cpp b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.cpp new file mode 100644 index 0000000000..5b2bdc6f7d --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.cpp @@ -0,0 +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. + +============================================================================*/ +#include"PythonWorker.h" +#include +#include +#include +#include +#include +#include +#include +#include + +void PythonWorker::DoWork() +{ + MITK_INFO << "Here"; + auto *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + mitk::IPythonService::ForceLoadModule(); + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + std::string pythonFileName = "hello.py"; + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( + pythonFileName.c_str(), "Examples/Plugins/org.mitk.example.gui.pythonexample/resources"); + m_PythonService->ExecuteScript(fileName); + emit Finished(); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + emit Failed(); + } + } + else + { + MITK_ERROR << "No Service reference found"; + } +} diff --git a/Modules/Python/mitkIPythonService.cpp b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.h similarity index 65% copy from Modules/Python/mitkIPythonService.cpp copy to Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.h index e52b7bb25e..e9d8dbfc07 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/PythonWorker.h @@ -1,25 +1,28 @@ /*============================================================================ 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 PythonWorker_h +#define PythonWorker_h -#include "mitkIPythonService.h" +#include -mitk::IPythonService::~IPythonService() +class PythonWorker : public QObject { -} + Q_OBJECT +public slots: + void DoWork(); -std::string mitk::IPythonService::ForceLoadModule() -{ - std::string ret = "Load python module"; - MITK_INFO << ret; - return ret; -} +signals: + void Finished(); + void Failed(); +}; +#endif \ No newline at end of file diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.cpp b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.cpp new file mode 100644 index 0000000000..482933622b --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.cpp @@ -0,0 +1,29 @@ +/*============================================================================ + +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 "org_mitk_example_gui_pythonexample_Activator.h" +#include "PythonExample.h" + +namespace mitk +{ + ctkPluginContext *org_mitk_example_gui_pythonexample_Activator::m_Context = nullptr; + void org_mitk_example_gui_pythonexample_Activator::start(ctkPluginContext *context) + { + m_Context = context; + BERRY_REGISTER_EXTENSION_CLASS(PythonExample, context) + } + + void org_mitk_example_gui_pythonexample_Activator::stop(ctkPluginContext *context) { Q_UNUSED(context) } + + ctkPluginContext *org_mitk_example_gui_pythonexample_Activator::GetContext() { return m_Context; } +} diff --git a/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.h b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.h new file mode 100644 index 0000000000..76f6717243 --- /dev/null +++ b/Examples/Plugins/org.mitk.example.gui.pythonexample/src/internal/org_mitk_example_gui_pythonexample_Activator.h @@ -0,0 +1,38 @@ +/*============================================================================ + +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 org_mitk_example_gui_pythonexample_Activator_h +#define org_mitk_example_gui_pythonexample_Activator_h + +#include + +namespace mitk +{ + class org_mitk_example_gui_pythonexample_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_example_gui_pythonexample") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext *context); + void stop(ctkPluginContext *context); + static ctkPluginContext *GetContext(); + + private: + static ctkPluginContext *m_Context; + + }; // org_mitk_example_gui_pythonexample_Activator +} + +#endif // org_mitk_example_gui_pythonexample_Activator_h diff --git a/Modules/DeepLearningSegmentation/CMakeLists.txt b/Modules/DeepLearningSegmentation/CMakeLists.txt new file mode 100644 index 0000000000..20590056cc --- /dev/null +++ b/Modules/DeepLearningSegmentation/CMakeLists.txt @@ -0,0 +1,3 @@ +mitk_create_module(DeepLearningSegmentation + DEPENDS MitkSegmentationUI MitkPython +) \ No newline at end of file diff --git a/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp new file mode 100644 index 0000000000..38d24375cf --- /dev/null +++ b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.cpp @@ -0,0 +1,379 @@ +/*============================================================================ + +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 "DeepLearningSegmentationTool.h" +#include +#include +#include +#include +#include +#include + +mitk::DeepLearningSegmentationTool::DeepLearningSegmentationTool(std::string toolName, + std::string iconName, + std::string pythonFolder, + std::string inputImageVarName, + std::string pythonFileName, + std::string outputImageVarName, + ImageType imageType, + bool multilabel) +{ + m_ToolName = toolName; + m_IconName = iconName; + m_PythonProjectPath = "Modules/DeepLearningSegmentation/"+pythonFolder; + m_InputImageVarName = inputImageVarName; + m_PythonFileName = pythonFileName; + m_OutputImageVarName = outputImageVarName; + m_ImageType = imageType; + m_MultilabelSegmentation = multilabel; + m_SegmentationRunning = false; +} + +mitk::DeepLearningSegmentationTool::~DeepLearningSegmentationTool() { +} + +us::ModuleResource mitk::DeepLearningSegmentationTool::GetIconResource() const +{ + auto moduleContext = us::GetModuleContext(); + auto module = moduleContext->GetModule(); + auto resource = module->GetResource(m_IconName); + return resource; +} + +const char *mitk::DeepLearningSegmentationTool::GetName() const +{ + return m_ToolName.c_str(); +} + +const char **mitk::DeepLearningSegmentationTool::GetXPM() const +{ + return nullptr; +} + +void mitk::DeepLearningSegmentationTool::Activated() +{ + Superclass::Activated(); +} + +void mitk::DeepLearningSegmentationTool::Deactivated() +{ + Superclass::Deactivated(); +} + +mitk::LabelSetImage::Pointer mitk::DeepLearningSegmentationTool::DoSegmentation(std::string networkPath) +{ + m_SegmentationRunning = true; + //get the input Image + mitk::Image::Pointer input; + try + { + input = GetInputImage(); + } + catch(mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow(); + } + + //Get the python microservice + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + // set path to the Python code which should be executed + try + { + std::vector pathVector; + pathVector.push_back(m_PythonProjectPath); + m_PythonService->AddRelativeSearchDirs(pathVector); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in setting the path to the Python code which should be executed"; + m_SegmentationRunning = false; + return nullptr; + } + // set the path to the trained network + try + { + std::string pathCommand = "network_path = '" + networkPath+"'"; + m_PythonService->Execute(pathCommand); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in setting the network path"; + m_SegmentationRunning = false; + return nullptr; + } + + //set the input image + try + { + if (m_ImageType==DeepLearningSegmentationTool::SimpleITKImage) + { + m_PythonService->CopyToPythonAsSimpleItkImage(input, m_InputImageVarName); + } + else if (m_ImageType==DeepLearningSegmentationTool::MITKImage) + { + m_PythonService->CopyMITKImageToPython(input, m_InputImageVarName); + } + else + { + mitkThrow() << "Unknown image type"; + } + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error setting the input image"; + m_SegmentationRunning = false; + return nullptr; + } + + // execute Segmentation + try + { + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( + m_PythonFileName.c_str(), m_PythonProjectPath.c_str()); + m_PythonService->ExecuteScript(fileName); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in executing python code"; + m_SegmentationRunning = false; + return nullptr; + } + + // get result + try + { + mitk::Image::Pointer outputImage; + if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) + { + outputImage = m_PythonService->CopySimpleItkImageFromPython(m_OutputImageVarName); + } + else if (m_ImageType == DeepLearningSegmentationTool::MITKImage) + { + outputImage = m_PythonService->CopyMITKImageFromPython(m_OutputImageVarName); + } + else + { + mitkThrow() << "Unknown image type"; + } + mitk::LabelSetImage::Pointer resultImage = mitk::LabelSetImage::New(); + resultImage->InitializeByLabeledImage(outputImage); + resultImage->SetGeometry(input->GetGeometry()); + m_SegmentationRunning = false; + outputImage->SetGeometry(input->GetGeometry()); + return resultImage; + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in getting the result"; + m_SegmentationRunning = false; + return nullptr; + } + } + else + { + mitkThrow() << "No service reference found"; + } + m_SegmentationRunning = false; + return nullptr; +} + +std::vector mitk::DeepLearningSegmentationTool::DoMultilabelSegmentation(std::string networkPath) +{ + + std::vector result; + m_SegmentationRunning = true; + // get the input Image + mitk::Image::Pointer input; + try + { + input = GetInputImage(); + } + catch (mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow(); + } + + // Get the python microservice + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + // set path to the Python code which should be executed + try + { + std::vector pathVector; + pathVector.push_back(m_PythonProjectPath); + m_PythonService->AddRelativeSearchDirs(pathVector); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in setting the path to the Python code which should be executed"; + m_SegmentationRunning = false; + return result; + } + // set the path to the trained network + try + { + std::string pathCommand = "network_path = '" + networkPath + "'"; + m_PythonService->Execute(pathCommand); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in setting the network path"; + m_SegmentationRunning = false; + return result; + } + + // set the input image + try + { + if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) + { + m_PythonService->CopyToPythonAsSimpleItkImage(input, m_InputImageVarName); + } + else if (m_ImageType == DeepLearningSegmentationTool::MITKImage) + { + m_PythonService->CopyMITKImageToPython(input, m_InputImageVarName); + } + else + { + mitkThrow() << "Unknown image type"; + } + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error setting the input image"; + m_SegmentationRunning = false; + return result; + } + + // execute Segmentation + try + { + std::string fileName = + mitk::StandardFileLocations::GetInstance()->FindFile(m_PythonFileName.c_str(), m_PythonProjectPath.c_str()); + m_PythonService->ExecuteScript(fileName); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in executing python code"; + m_SegmentationRunning = false; + return result; + } + + // get result + try + { + std::vector outputImages; + //if (m_ImageType == DeepLearningSegmentationTool::SimpleITKImage) + //{ + // outputImage = m_PythonService->CopySimpleItkImageFromPython(m_OutputImageVarName); + //} + if (m_ImageType == DeepLearningSegmentationTool::MITKImage) + { + outputImages = m_PythonService->CopyListOfMITKImagesFromPython(m_OutputImageVarName); + } + else + { + mitkThrow() << "Unknown image type"; + } + + for (mitk::Image::Pointer image : outputImages) + { + mitk::LabelSetImage::Pointer resultImage = mitk::LabelSetImage::New(); + resultImage->InitializeByLabeledImage(image); + resultImage->SetGeometry(input->GetGeometry()); + m_SegmentationRunning = false; + resultImage->SetGeometry(input->GetGeometry()); + result.push_back(resultImage); + } + return result; + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + mitkThrow() << "Error in getting the result"; + m_SegmentationRunning = false; + return result; + } + } + else + { + mitkThrow() << "No service reference found"; + } + m_SegmentationRunning = false; + return result; +} + + +mitk::DataStorage *mitk::DeepLearningSegmentationTool::GetDataStorage() +{ + return GetToolManager()->GetDataStorage(); + GetToolManager()->GetReferenceData(0); +} + +mitk::DataNode *mitk::DeepLearningSegmentationTool::GetReferenceData() +{ + return GetToolManager()->GetReferenceData(0); +} + +mitk::Image::Pointer mitk::DeepLearningSegmentationTool::GetInputImage() + { + mitk::DataNode::Pointer referenceData = GetToolManager()->GetReferenceData(0); + mitk::Image::Pointer input = dynamic_cast(referenceData->GetData()); + if (input.IsNull()) + { + mitkThrow(); + } + //unsigned int timestep = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->GetPos(); + //mitk::Image::ConstPointer input = Get3DImage(input, timestep); + if (input.IsNull()) + { + mitkThrow(); + } + + return input; + } + +bool mitk::DeepLearningSegmentationTool::IsSegmentationRunning() +{ + return m_SegmentationRunning; +} + +bool mitk::DeepLearningSegmentationTool::IsMultilabelSegmentation() +{ + return m_MultilabelSegmentation; +} diff --git a/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.h b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.h new file mode 100644 index 0000000000..13a4b7f648 --- /dev/null +++ b/Modules/DeepLearningSegmentation/DeepLearningSegmentationTool.h @@ -0,0 +1,131 @@ +/*============================================================================ + +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 DeepLearningSegmentationTool_h +#define DeepLearningSegmentationTool_h + +#include +#include + +namespace us { +class ModuleResource; +} + +namespace mitk +{ + /** + * @class DeepLearningSegmentationTool + * @brief This is the base class for all Deep Learning Based Segmentations + */ + class MITKDEEPLEARNINGSEGMENTATION_EXPORT DeepLearningSegmentationTool : public mitk::AutoSegmentationTool + { + public: + enum ImageType + { + SimpleITKImage, + MITKImage + }; + /** + * @brief Getter for the icon of the module which is displayed in the Segmentation Plugin. + * @return icon of the segmentation method + */ + us::ModuleResource GetIconResource() const override; + + //bool CanHandle(mitk::BaseData *referenceData) const override; + + /** + * @brief Getter for the name of the module which is displayed in the Segmentation Plugin. + * @return name of the segmentation method + */ + const char *GetName() const override; + const char **GetXPM() const override; + + /** + * @brief Constructor + * + * @param pythonFolder the folder of the python code, should lie in "Modules/DeepLearningsegmentation" + * @param inputImageVarName the python variable name of the input image to segment + * @param pythonFileName the file name of the python script to execute. This is the entry point for the segmentation + * @param outputImageVarName the python variable name of the output image (segmentation) + */ + DeepLearningSegmentationTool(std::string toolName, + std::string iconName, + std::string pythonFolder, + std::string inputImageVarName, + std::string pythonFileName, + std::string outputImageVarName, + ImageType imageType, + bool multilabel = false); + ~DeepLearningSegmentationTool() override; + + void Activated() override; + void Deactivated() override; + + /** + * @brief Executes the segmentation by running python code + * + * @throw mitk::Exception if something went wrong during a python call, python service is not found, or no input image is found + * @param networkPath the path to the trained network for segmentation + * @return the segmentation result as label set image + */ + mitk::LabelSetImage::Pointer DoSegmentation(std::string networkPath); + /** + * @brief Executes the multilabel segmentation by running python code + * + * @throw mitk::Exception if something went wrong during a python call, python service is not found, or no input + * image is found + * @param networkPath the path to the trained network for segmentation + * @return the segmentation result as vector of label set image + */ + std::vector DoMultilabelSegmentation(std::string networkPath); + /** + * @brief Get the input image for the semgentation which is currently selected in the Segmentation Plugin + * + * @throw mitk::Exception if the input is null + * @return input image for segmentation + */ + mitk::Image::Pointer GetInputImage(); + /** + * @brief Getter for m_SegmentaionRunning, to determine, if a segmentation is currently executed + * @return m_SegmentaionRunning + */ + bool IsSegmentationRunning(); + + /** + * @brief Getter for the data storage from the tool manager + * @return data storage + */ + mitk::DataStorage* GetDataStorage(); + /** + * @brief Getter for the reference data from the tool manager + * @return reference data + */ + mitk::DataNode *GetReferenceData(); + + bool IsMultilabelSegmentation(); + + protected: + std::string m_PythonProjectPath; + std::string m_InputImageVarName; + std::string m_PythonFileName; + std::string m_OutputImageVarName; + + private: + std::string m_IconName; + std::string m_ToolName; + bool m_SegmentationRunning; + ImageType m_ImageType; + bool m_MultilabelSegmentation; + }; +} // namespace mitk + +#endif diff --git a/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox b/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox new file mode 100644 index 0000000000..22f96c72e2 --- /dev/null +++ b/Modules/DeepLearningSegmentation/documentation/DeveloperManual/DeepLearningSegmentation.dox @@ -0,0 +1,195 @@ +/** + +\page DeepLearningSegmentationModule Deep-Learning-Segmentation Module + +\tableofcontents + +\section DLSeg_brief Description +The MITK Deep-Learning-Segmentation Module enables developers to integrate their deep learning methods which should be developed in python in MITK. +The following guide should give an overview of the steps which have to be done to integrate a new deep learning method in MITK. + +\subsection DLSeg_MITKPrerequisites MITK Prerequisites +To use the Deep-Learning-Segmentation Module you need to build MITK with Python enabled (MITK_USE_PYTHON3 on in CMake configurations). Furthermore, SWIG has to be enabled (MITK_USE_SWIG). + +\subsection DLSeg_TypicalWorkflow A typical deep learning workflow +This guide assumes a certain workflow for the segmentation. This includes: + +
    +
  1. There is an entry script which starts the segmentation process. From this script, all required variables (image to segment, path to the trained network,...) have to be passed to the called methods, if needed. +
  2. The image for segmentation is a MITK or SimpleITK image. +
  3. The segmentation itself is also a MITK or SimpleITK image. +
  4. The trained network is passed as a string. +
  5. There are no more parameters required for segmentation. +
+ +\note segmentations with slightly different workflow could also be intergrated. For this, some methods have to be overwritten. A procedure for segmentations with additional parameters (point 5 above not fulfilled) is described later on. + +In the following sections, a tool called "My Segmentation" is integrated. The names in the code examples have to be adopted to the method you want to integrate. +The deep learning interface consists of two parts: The module MITKDeepLearningSegmentation, where the algorithm itself is implemented and the plugin org.mitk.deeplearningsegmentation, where the GUI interaction is implemented. + +\section DLSeg_Module Implementation in the module + +In the first step, all required parts in the module folder DeepLearningSegmentation are implemented. For this, the following steps are necessary: + +
    +
  1. Create a folder which contains the python code for segmentation. This folder might be called "my_seg_tool_algorithm" for instance. It contains the whole python repository which is needed for segmentation. + \warning There shouldn't be any larger files in the folder like results from experiments or the trained network. This would increase the size of the MITK repository too much and can lead to problems when pushing. +
  2. Put the icon of the tool as svg file in the resource folder. +
  3. Create a tool class. For this, you need to create a header file (MySegTool3D.h) and a cpp file (MySegTool3D.cpp). A typical structure for this files is shown in the following section. The files should be named with the syntax SegTool3D. +
  4. Edit the files.cmake file. You need to add the following files: +
      +
    • Add the cpp file MySegTool3D.cpp to the CPP_FILES +
    • Add the svg file to the RESOURCE_FILES +
    +
+ +\subsection DLSeg_ToolClass Typical structure of the tool class + +The header file of the tool class typically has the following structure: + +\code{.h} +#ifndef MySegTool3DGUI_h +#define MySegTool3DGUI_h +#include +#include"DeepLearningSegmentationGUI.h" +#include"MySegTool3D.h" +namespace Ui { +class MySegTool3DGUI; +} +class DEEPLEARNINGSEGMENTATION_EXPORT MySegTool3DGUI : public DeepLearningSegmentationGUI{ + Q_OBJECT +public: + mitkClassMacro(MySegTool3DGUI, QmitkToolGUI) + itkFactorylessNewMacro(Self) +protected slots: + void OnNewToolAssociated(mitk::Tool *); +}; +#endif // MySegTool3DGUI_h + +\endcode + +The cpp file of the tool class typically has the following structure: + +\code{.cpp} +#include "MySegTool3D.h" +namespace mitk{ + MITK_TOOL_MACRO(MITKDEEPLEARNINGSEGMENTATION_EXPORT, MySegTool3D, "My Segmentation tool"); +} + +mitk::MySegTool3D::MySegTool3D() + : DeepLearningSegmentationTool("My Segmentation", "icon_seg.svg", "my_seg_tool_algorithm", "input_image", "segment.py", "output_image", DeepLearningSegmentationTool::MITKImage, false){ +} + +mitk::MySegTool3D::~MySegTool3D() { +} +\endcode + +In the tool class, only some macros are defined and the implementation of the construcor with some arguments is necessary. +This arguments are: + +
    +
  • The name of the tool, which should be displayed in the workbench (e.g. "My Segmentation") +
  • The file name of the icon, which should be visible in the workbench (e.g. "icon_seg.svg") +
  • The name of the folder, in which the python code for execution lies (e.g. "my_seg_tool_algorithm"). This folder has to be in the module folder of the MITKDeepLearningSegmentation moudle. +
  • The variable name of the input image on python side (e.g. "input_image") +
  • The file name of the python script that is the entry point for the segmentation (e.g. "segment.py") +
  • The variable name of the output segmentation on python side (e.g. "output_image") +
  • The type of the images on python side (e.g. "DeepLearningSegmentationTool::MITKImage") +
  • (Optional) a boolean if the segmentation has multiple segments. The default value is false, which means a segmentation with only one segment. +
+ +\section DLSeg_Plugin Implementation in the plugin + +In the second step, the necesarry parts in the plugin folder org.mitk.deeplearningsegmentation are implemented. Therefore, you should execute the following steps: + +
    +
  1. Create a tool GUI class. For this, you need to create a header file (MySegTool3DGUI.h) and a cpp file (MySegTool3DGUI.cpp). A typical structure for this files is shown in the following section. The files should be named with the syntax SegTool3DGUI. +
  2. Edit the files.cmake file. You need to add the following files: +
      +
    • Add the cpp file MySegTool3DGUI.cpp to the INTERNAL_CPP_FILES +
    • Add src/internal/MySegTool3DGUI.h to the MOC_H_FILES +
    +
+ +\subsection DLSeg_ToolGUIClass Typical structure of the tool GUI class + +The header file of the tool GUI class typically has the following structure: + +\code{.h} +#ifndef MySegTool3DGUI_h +#define MySegTool3DGUI_h +#include +#include"DeepLearningSegmentationGUI.h" +#include"MySegTool3D.h" +namespace Ui { +class MySegTool3DGUI; +} +class DEEPLEARNINGSEGMENTATION_EXPORT MySegTool3DGUI : public DeepLearningSegmentationGUI{ + Q_OBJECT +public: + mitkClassMacro(MySegTool3DGUI, QmitkToolGUI) + itkFactorylessNewMacro(Self) +protected slots: + void OnNewToolAssociated(mitk::Tool *); +}; +#endif // MySegTool3DGUI_h + +\endcode + +The cpp file of the tool GUI class typically has the following structure: + +\code{.cpp} +#include "MySegTool3DGUI.h" +MITK_TOOL_GUI_MACRO(DEEPLEARNINGSEGMENTATION_EXPORT, MySegTool3DGUI, "") +void MySegTool3DGUI::OnNewToolAssociated(mitk::Tool* tool) { + m_SegTool = dynamic_cast(tool); +} +\endcode + +In the tool GUI class, some macros are defined as well. Furthermore, the method OnNewToolAssociated has to be implemented. This is necessary to associate the tool GUI class with the according tool class. + +If your segmentation algoithm fulfills all points from a typical deep learning workflow, you are done with integration. If modification is needed, methods have to be overwritten. The following section explains with an example how to add an additional parameter. + +\section DLSeg_AdditionalParameter Add an additional parameter + +This section describes how to add an additional parameter for your segmentation. The process is explained with a threshold parameter of the type double. You have to execute the following steps: + +
    +
  1. Implement a method for setting the parameter on the python side in the tool class. A method for setting the threshold might look like this: +\code{.cpp} +void mitk::MySegTool3D::SetThreshold(double threshold){ + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto pythonServiceRefs = context->GetServiceReferences(filter); + if (!pythonServiceRefs.empty()){ + mitk::IPythonService *pythonService = + dynamic_cast( context->GetService( pythonServiceRefs.front())); + pythonService->Execute("threshold = " + std::to_string(threshold)); + } +} +\endcode +
  2. Overwrite the method SetUpUI() for adding a new GUI element. In the code below a GUI element is created first, then it is added to the GUI and then the SetUpUI() of the base class is called. m_ThresholdSpinBox is a member variable in order to access the value of the threshold later on. +\code{.cpp} +void mitk::MySegTool3D::SetThreshold(double threshold){ + mitk::IPythonService::ForceLoadModule(); + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto pythonServiceRefs = context->GetServiceReferences(filter); + if (!pythonServiceRefs.empty()){ + mitk::IPythonService *pythonService = + dynamic_cast( context->GetService( pythonServiceRefs.front())); + pythonService->Execute("threshold = " + std::to_string(threshold)); + } +} +\endcode +
  3. Overwrite the method OnDoSegmentation() in the tool GUI class. This is shown in the code below. First, the method from step 1 is called. Casting to the concrete type is neccessary in order to be able to access the method. The value of the GUI element is set in the method. Afterwards, the OnDoSegmentation() method of the base class is called to execute the segmentation itself. +\code{.cpp} +void MySegTool3DGUI::OnDoSegmentation() { + dynamic_cast(m_SegTool)->SetThreshold(m_ThresholdSpinBox->value()); + DeepLearningSegmentationGUI::OnDoSegmentation(); +} +\endcode +
+ +*/ diff --git a/Modules/DeepLearningSegmentation/files.cmake b/Modules/DeepLearningSegmentation/files.cmake new file mode 100644 index 0000000000..b46dd2c52a --- /dev/null +++ b/Modules/DeepLearningSegmentation/files.cmake @@ -0,0 +1,6 @@ +set(CPP_FILES +DeepLearningSegmentationTool.cpp +) + +set(RESOURCE_FILES +) diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index d558488b7b..b801ca849b 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,76 +1,77 @@ # 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 US USUI DICOMUI Remeshing Python - QtPython + PythonService Persistence OpenIGTLinkUI IGTUI RT RTUI IOExt XNAT TubeGraph BoundingShape RenderWindowManagerUI SemanticRelations SemanticRelationsUI CEST BasicImageProcessing ModelFit ModelFitUI Pharmacokinetics PharmacokineticsUI DICOMPM REST RESTService DICOMweb + DeepLearningSegmentation ) diff --git a/Modules/Python/CMakeLists.txt b/Modules/Python/CMakeLists.txt index 161bddb4c7..55218afc0a 100644 --- a/Modules/Python/CMakeLists.txt +++ b/Modules/Python/CMakeLists.txt @@ -1,8 +1,10 @@ -if(MITK_USE_Python3) +if(MITK_WRAP_PYTHON_ENABLED) mitk_create_module( DEPENDS MitkCore PACKAGE_DEPENDS PUBLIC Python3|Python - ) + ) - add_subdirectory(autoload/PythonService) + if(TARGET ${MODULE_TARGET} AND BUILD_TESTING) + add_subdirectory(test) + endif() endif() diff --git a/Modules/Python/autoload/PythonService/CMakeLists.txt b/Modules/Python/autoload/PythonService/CMakeLists.txt deleted file mode 100644 index c0b5d4f8f6..0000000000 --- a/Modules/Python/autoload/PythonService/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -mitkFunctionCheckCompilerFlags("-Wno-cpp" CMAKE_CXX_FLAGS) - -mitk_create_module(PythonService - INCLUDE_DIRS - PRIVATE src/PythonService - DEPENDS PUBLIC MitkPython - PACKAGE_DEPENDS - PUBLIC Qt5|Widgets CTK|CTKScriptingPythonCore+CTKScriptingPythonWidgets - PRIVATE Python3|NumPy - AUTOLOAD_WITH MitkPython -) - -if(TARGET ${MODULE_TARGET}) - configure_file(PythonPath.h.in "${CMAKE_CURRENT_BINARY_DIR}/PythonPath.h" @ONLY) -endif() diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.cpp b/Modules/Python/autoload/PythonService/mitkPythonService.cpp deleted file mode 100644 index 513a7fe647..0000000000 --- a/Modules/Python/autoload/PythonService/mitkPythonService.cpp +++ /dev/null @@ -1,917 +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 "mitkPythonService.h" -#include -#include -#include -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 5208) -#endif - -#include - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#include "PythonPath.h" -#include -#include -#include -#include -#include -#include -#include - -#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION -#include - -#include - -#ifndef WIN32 -#include -#endif - -typedef itksys::SystemTools ist; - -mitk::PythonService::PythonService() - : m_ItkWrappingAvailable( true ) - , m_OpenCVWrappingAvailable( true ) - , m_VtkWrappingAvailable( true ) - , m_ErrorOccured( false ) -{ - bool pythonInitialized = static_cast( Py_IsInitialized() ); //m_PythonManager.isPythonInitialized() ); - - // due to strange static var behaviour on windows Py_IsInitialized() returns correct value while - // m_PythonManager.isPythonInitialized() does not because it has been constructed and destructed again - if( !pythonInitialized ) - { - MITK_INFO << "Initializing python service"; - //TODO a better way to do this -#ifndef WIN32 - dlerror(); - if(dlopen(PYTHON_LIBRARY, RTLD_NOW | RTLD_GLOBAL) == nullptr ) - { - mitkThrow() << "Python runtime could not be loaded: " << dlerror(); - } -#endif - - std::string programPath = QCoreApplication::applicationDirPath().toStdString() + "/"; - - QString pythonCommand; - pythonCommand.append( QString("import site, sys\n") ); - pythonCommand.append( QString("import SimpleITK as sitk\n") ); - pythonCommand.append( QString("import SimpleITK._SimpleITK as _SimpleITK\n") ); - pythonCommand.append( QString("import numpy\n") ); - - pythonCommand.append( QString("sys.path.append('')\n") ); - pythonCommand.append( QString("sys.path.append('%1')\n").arg(programPath.c_str()) ); - pythonCommand.append( QString("sys.path.append('%1')\n").arg(EXTERNAL_DIST_PACKAGES) ); - pythonCommand.append( QString("\nsite.addsitedir('%1')").arg(EXTERNAL_SITE_PACKAGES) ); - - if( pythonInitialized ) - m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut|PythonQt::PythonAlreadyInitialized); - else - m_PythonManager.setInitializationFlags(PythonQt::RedirectStdOut); - m_PythonManager.initialize(); - - m_PythonManager.executeString( pythonCommand, ctkAbstractPythonManager::FileInput ); - } -} - -mitk::PythonService::~PythonService() -{ - MITK_DEBUG("mitk::PythonService") << "destructing PythonService"; -} - -void mitk::PythonService::AddRelativeSearchDirs(std::vector< std::string > dirs) -{ - std::string programPath = QCoreApplication::applicationDirPath().toStdString() + "/"; - std::string cwd = ist::GetCurrentWorkingDirectory() + "/"; - - for (auto dir : dirs) - { - m_PythonManager.executeString(QString("sys.path.append('%1')").arg((programPath + dir).c_str()), ctkAbstractPythonManager::SingleInput ); - m_PythonManager.executeString(QString("sys.path.append('%1')").arg((cwd + dir).c_str()), ctkAbstractPythonManager::SingleInput ); - } -} - -void mitk::PythonService::AddAbsoluteSearchDirs(std::vector< std::string > dirs) -{ - for (auto dir : dirs) - { - m_PythonManager.executeString(QString("sys.path.append('%1')").arg(dir.c_str()), ctkAbstractPythonManager::SingleInput ); - } -} - -std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) -{ - QString pythonCommand = QString::fromStdString(stdpythonCommand); - QVariant result; - - bool commandIssued = true; - if(commandType == IPythonService::SINGLE_LINE_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::SingleInput ); - else if(commandType == IPythonService::MULTI_LINE_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::FileInput ); - else if(commandType == IPythonService::EVAL_COMMAND ) - result = m_PythonManager.executeString(pythonCommand, ctkAbstractPythonManager::EvalInput ); - else - commandIssued = false; - - if(commandIssued) - { - this->NotifyObserver(pythonCommand.toStdString()); - m_ErrorOccured = PythonQt::self()->hadError(); - } - - return result.toString().toStdString(); -} - -void mitk::PythonService::ExecuteScript( const std::string& pythonScript ) -{ - std::ifstream t(pythonScript.c_str()); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - t.close(); - - m_PythonManager.executeString(QString::fromStdString(str)); -} - -std::vector mitk::PythonService::GetVariableStack() const -{ - std::vector list; - - PyObject* dict = PyImport_GetModuleDict(); - PyObject* object = PyDict_GetItemString(dict, "__main__"); - PyObject* dirMain = PyObject_Dir(object); - PyObject* tempObject = nullptr; - //PyObject* strTempObject = 0; - - if(dirMain) - { - std::string name, attrValue, attrType; - - for(int i = 0; iob_type->tp_name; - - if(tempObject && ( PyUnicode_Check(tempObject) || PyString_Check(tempObject) ) ) - attrValue = PyString_AsString(tempObject); - else - attrValue = ""; - - mitk::PythonVariable var; - var.m_Name = name; - var.m_Value = attrValue; - var.m_Type = attrType; - list.push_back(var); - } - } - - return list; -} - -std::string mitk::PythonService::GetVariable(const std::string& name) const -{ - std::vector allVars = this->GetVariableStack(); - for(unsigned int i = 0; i< allVars.size(); i++) - { - if( allVars.at(i).m_Name == name ) - return allVars.at(i).m_Value; - } - - return ""; -} - -bool mitk::PythonService::DoesVariableExist(const std::string& name) const -{ - bool varExists = false; - - std::vector allVars = this->GetVariableStack(); - for(unsigned int i = 0; i< allVars.size(); i++) - { - if( allVars.at(i).m_Name == name ) - { - varExists = true; - break; - } - } - - return varExists; -} - -void mitk::PythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) -{ - if(!m_Observer.contains(observer)) - m_Observer.append(observer); -} - -void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) -{ - m_Observer.removeOne(observer); -} - -void mitk::PythonService::NotifyObserver(const std::string &command) -{ - MITK_DEBUG("mitk::PythonService") << "number of observer " << m_Observer.size(); - for( int i=0; i< m_Observer.size(); ++i ) - { - m_Observer.at(i)->CommandExecuted(command); - } -} - -bool mitk::PythonService::CopyToPythonAsSimpleItkImage(mitk::Image *image, const std::string &stdvarName) -{ - QString varName = QString::fromStdString( stdvarName ); - QString command; - unsigned int* imgDim = image->GetDimensions(); - int npy_nd = 1; - - // access python module - PyObject *pyMod = PyImport_AddModule("__main__"); - // global dictionary - PyObject *pyDict = PyModule_GetDict(pyMod); - const mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); - const mitk::Point3D origin = image->GetGeometry()->GetOrigin(); - mitk::PixelType pixelType = image->GetPixelType(); - auto ioPixelType = image->GetPixelType().GetPixelType(); - PyObject* npyArray = nullptr; - mitk::ImageReadAccessor racc(image); - void* array = const_cast(racc.GetData()); - - mitk::Vector3D xDirection; - mitk::Vector3D yDirection; - mitk::Vector3D zDirection; - const vnl_matrix_fixed &transform = - image->GetGeometry()->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix(); - - mitk::Vector3D s = image->GetGeometry()->GetSpacing(); - - // ToDo: Check if this is a collumn or row vector from the matrix. - // right now it works but not sure for rotated geometries - mitk::FillVector3D(xDirection, transform[0][0]/s[0], transform[0][1]/s[1], transform[0][2]/s[2]); - mitk::FillVector3D(yDirection, transform[1][0]/s[0], transform[1][1]/s[1], transform[1][2]/s[2]); - mitk::FillVector3D(zDirection, transform[2][0]/s[0], transform[2][1]/s[1], transform[2][2]/s[2]); - - // save the total number of elements here (since the numpy array is one dimensional) - npy_intp* npy_dims = new npy_intp[1]; - npy_dims[0] = imgDim[0]; - - /** - * Build a string in the format [1024,1028,1] - * to describe the dimensionality. This is needed for simple itk - * to know the dimensions of the image - */ - QString dimensionString; - dimensionString.append(QString("[")); - dimensionString.append(QString::number(imgDim[0])); - for (unsigned i = 1; i < 3; ++i) - // always three because otherwise the 3d-geometry gets destroyed - // (relevant for backtransformation of simple itk image to mitk. - { - dimensionString.append(QString(",")); - dimensionString.append(QString::number(imgDim[i])); - npy_dims[0] *= imgDim[i]; - } - dimensionString.append("]"); - - - // the next line is necessary for vectorimages - npy_dims[0] *= pixelType.GetNumberOfComponents(); - - // default pixeltype: unsigned short - NPY_TYPES npy_type = NPY_USHORT; - std::string sitk_type = "sitkUInt8"; - if( ioPixelType == itk::IOPixelEnum::SCALAR ) - { - if( pixelType.GetComponentType() == itk::IOComponentEnum::DOUBLE ) { - npy_type = NPY_DOUBLE; - sitk_type = "sitkFloat64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::FLOAT ) { - npy_type = NPY_FLOAT; - sitk_type = "sitkFloat32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::SHORT) { - npy_type = NPY_SHORT; - sitk_type = "sitkInt16"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::CHAR ) { - npy_type = NPY_BYTE; - sitk_type = "sitkInt8"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::INT ) { - npy_type = NPY_INT; - sitk_type = "sitkInt32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::LONG ) { - npy_type = NPY_LONG; - sitk_type = "sitkInt64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UCHAR ) { - npy_type = NPY_UBYTE; - sitk_type = "sitkUInt8"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UINT ) { - npy_type = NPY_UINT; - sitk_type = "sitkUInt32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::ULONG ) { - npy_type = NPY_LONG; - sitk_type = "sitkUInt64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::USHORT ) { - npy_type = NPY_USHORT; - sitk_type = "sitkUInt16"; - } - } - else if ( ioPixelType == itk::IOPixelEnum::VECTOR || - ioPixelType == itk::IOPixelEnum::RGB || - ioPixelType == itk::IOPixelEnum::RGBA - ) - { - if( pixelType.GetComponentType() == itk::IOComponentEnum::DOUBLE ) { - npy_type = NPY_DOUBLE; - sitk_type = "sitkVectorFloat64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::FLOAT ) { - npy_type = NPY_FLOAT; - sitk_type = "sitkVectorFloat32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::SHORT) { - npy_type = NPY_SHORT; - sitk_type = "sitkVectorInt16"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::CHAR ) { - npy_type = NPY_BYTE; - sitk_type = "sitkVectorInt8"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::INT ) { - npy_type = NPY_INT; - sitk_type = "sitkVectorInt32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::LONG ) { - npy_type = NPY_LONG; - sitk_type = "sitkVectorInt64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UCHAR ) { - npy_type = NPY_UBYTE; - sitk_type = "sitkVectorUInt8"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UINT ) { - npy_type = NPY_UINT; - sitk_type = "sitkVectorUInt32"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::ULONG ) { - npy_type = NPY_LONG; - sitk_type = "sitkVectorUInt64"; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::USHORT ) { - npy_type = NPY_USHORT; - sitk_type = "sitkVectorUInt16"; - } - } - else { - MITK_WARN << "not a recognized pixeltype"; - return false; - } - - // creating numpy array - import_array1 (true); - npyArray = PyArray_SimpleNewFromData(npy_nd,npy_dims,npy_type,array); - - // add temp array it to the python dictionary to access it in python code - const int status = PyDict_SetItemString( pyDict,QString("%1_numpy_array") - .arg(varName).toStdString().c_str(), - npyArray ); - - - // sanity check - if ( status != 0 ) - return false; - - - command.append( QString("%1 = sitk.Image(%2,sitk.%3,%4)\n").arg(varName) - .arg(dimensionString) - .arg(QString(sitk_type.c_str())).arg(QString::number(pixelType.GetNumberOfComponents())) ); - command.append( QString("%1.SetSpacing([%2,%3,%4])\n").arg(varName) - .arg(QString::number(spacing[0])) - .arg(QString::number(spacing[1])) - .arg(QString::number(spacing[2])) ); - command.append( QString("%1.SetOrigin([%2,%3,%4])\n").arg(varName) - .arg(QString::number(origin[0])) - .arg(QString::number(origin[1])) - .arg(QString::number(origin[2])) ); - command.append( QString("%1.SetDirection([%2,%3,%4,%5,%6,%7,%8,%9,%10])\n").arg(varName) - .arg(QString::number(xDirection[0])) - .arg(QString::number(xDirection[1])) - .arg(QString::number(xDirection[2])) - .arg(QString::number(yDirection[0])) - .arg(QString::number(yDirection[1])) - .arg(QString::number(yDirection[2])) - .arg(QString::number(zDirection[0])) - .arg(QString::number(zDirection[1])) - .arg(QString::number(zDirection[2])) - ); - // directly access the cpp api from the lib - command.append( QString("_SimpleITK._SetImageFromArray(%1_numpy_array,%1)\n").arg(varName) ); - command.append( QString("del %1_numpy_array").arg(varName) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - - - this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - return true; -} - - -mitk::PixelType DeterminePixelType(const std::string& pythonPixeltype, unsigned long nrComponents, int dimensions) -{ - typedef itk::RGBPixel< unsigned char > UCRGBPixelType; - typedef itk::RGBPixel< unsigned short > USRGBPixelType; - typedef itk::RGBPixel< float > FloatRGBPixelType; - typedef itk::RGBPixel< double > DoubleRGBPixelType; - typedef itk::Image< UCRGBPixelType > UCRGBImageType; - typedef itk::Image< USRGBPixelType > USRGBImageType; - typedef itk::Image< FloatRGBPixelType > FloatRGBImageType; - typedef itk::Image< DoubleRGBPixelType > DoubleRGBImageType; - typedef itk::RGBAPixel< unsigned char > UCRGBAPixelType; - typedef itk::RGBAPixel< unsigned short > USRGBAPixelType; - typedef itk::RGBAPixel< float > FloatRGBAPixelType; - typedef itk::RGBAPixel< double > DoubleRGBAPixelType; - typedef itk::Image< UCRGBAPixelType > UCRGBAImageType; - typedef itk::Image< USRGBAPixelType > USRGBAImageType; - typedef itk::Image< FloatRGBAPixelType > FloatRGBAImageType; - typedef itk::Image< DoubleRGBAPixelType > DoubleRGBAImageType; - - auto pixelType = mitk::MakePixelType(nrComponents); - - if (nrComponents == 1) - { - if( pythonPixeltype.compare("float64") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("float32") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("int16") == 0) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("int8") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("int32") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("int64") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("uint8") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("uint32") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("uint64") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } else if( pythonPixeltype.compare("uint16") == 0 ) { - pixelType = mitk::MakePixelType(nrComponents); - } - else - { - mitkThrow()<< "unknown scalar PixelType"; - } - } else if(nrComponents == 3 && dimensions == 2) { - if( pythonPixeltype.compare("float64") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("float32") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("uint8") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("uint16") == 0 ) { - pixelType = mitk::MakePixelType(); - } - } else if( (nrComponents == 4) && dimensions == 2 ) { - if( pythonPixeltype.compare("float64") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("float32") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("uint8") == 0 ) { - pixelType = mitk::MakePixelType(); - } else if( pythonPixeltype.compare("uint16") == 0 ) { - pixelType = mitk::MakePixelType(); - } - } - else { - if( pythonPixeltype.compare("float64") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("float32") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("int16") == 0) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("int8") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("int32") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("int64") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("uint8") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("uint16") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("uint32") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else if( pythonPixeltype.compare("uint64") == 0 ) { - pixelType = mitk::MakePixelType >(nrComponents); - } else { - mitkThrow()<< "unknown vectorial PixelType"; - } - } - - return pixelType; -} - -mitk::Image::Pointer mitk::PythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) -{ - double*ds = nullptr; - // access python module - PyObject *pyMod = PyImport_AddModule("__main__"); - // global dictionarry - PyObject *pyDict = PyModule_GetDict(pyMod); - mitk::Image::Pointer mitkImage = mitk::Image::New(); - mitk::Vector3D spacing; - mitk::Point3D origin; - QString command; - QString varName = QString::fromStdString( stdvarName ); - - command.append( QString("%1_numpy_array = sitk.GetArrayFromImage(%1)\n").arg(varName) ); - command.append( QString("%1_spacing = numpy.asarray(%1.GetSpacing())\n").arg(varName) ); - command.append( QString("%1_origin = numpy.asarray(%1.GetOrigin())\n").arg(varName) ); - command.append( QString("%1_dtype = %1_numpy_array.dtype.name\n").arg(varName) ); - command.append( QString("%1_direction = numpy.asarray(%1.GetDirection())\n").arg(varName) ); - command.append( QString("%1_nrComponents = numpy.asarray(%1.GetNumberOfComponentsPerPixel())\n").arg(varName)); - command.append( QString("%1_dtype = %1_numpy_array.dtype.name\n").arg(varName) ); - - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - PyObject* py_dtype = PyDict_GetItemString(pyDict,QString("%1_dtype").arg(varName).toStdString().c_str() ); - std::string dtype = PyString_AsString(py_dtype); - PyArrayObject* py_data = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_numpy_array").arg(varName).toStdString().c_str() ); - PyArrayObject* py_spacing = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_spacing").arg(varName).toStdString().c_str() ); - PyArrayObject* py_origin = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_origin").arg(varName).toStdString().c_str() ); - PyArrayObject* py_direction = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_direction").arg(varName).toStdString().c_str() ); - - PyArrayObject* py_nrComponents = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_nrComponents").arg(varName).toStdString().c_str() ); - - unsigned int nr_Components = *(reinterpret_cast(PyArray_DATA(py_nrComponents))); - - unsigned int nr_dimensions = PyArray_NDIM(py_data); - if (nr_Components > 1) // for VectorImages the last dimension in the numpy array are the vector components. - { - --nr_dimensions; - } - - mitk::PixelType pixelType = DeterminePixelType(dtype, nr_Components, nr_dimensions); - - unsigned int* dimensions = new unsigned int[nr_dimensions]; - // fill backwards , nd data saves dimensions in opposite direction - for( unsigned i = 0; i < nr_dimensions; ++i ) - { - dimensions[i] = PyArray_DIMS(py_data)[nr_dimensions - 1 - i]; - } - - mitkImage->Initialize(pixelType, nr_dimensions, dimensions); - - - mitkImage->SetChannel(PyArray_DATA(py_data)); - - - ds = reinterpret_cast(PyArray_DATA(py_spacing)); - spacing[0] = ds[0]; - spacing[1] = ds[1]; - spacing[2] = ds[2]; - - mitkImage->GetGeometry()->SetSpacing(spacing); - - - ds = reinterpret_cast(PyArray_DATA(py_origin)); - origin[0] = ds[0]; - origin[1] = ds[1]; - origin[2] = ds[2]; - mitkImage->GetGeometry()->SetOrigin(origin); - - - itk::Matrix py_transform; - - ds = reinterpret_cast(PyArray_DATA(py_direction)); - py_transform[0][0] = ds[0]; - py_transform[0][1] = ds[1]; - py_transform[0][2] = ds[2]; - - py_transform[1][0] = ds[3]; - py_transform[1][1] = ds[4]; - py_transform[1][2] = ds[5]; - - py_transform[2][0] = ds[6]; - py_transform[2][1] = ds[7]; - py_transform[2][2] = ds[8]; - - mitk::AffineTransform3D::Pointer affineTransform = mitkImage->GetGeometry()->GetIndexToWorldTransform(); - - itk::Matrix transform = py_transform * affineTransform->GetMatrix(); - - affineTransform->SetMatrix(transform); - - mitkImage->GetGeometry()->SetIndexToWorldTransform(affineTransform); - - // mitk::AffineTransform3D::New(); - //mitkImage->GetGeometry()->SetIndexToWorldTransform(); - - // cleanup - command.clear(); - command.append( QString("del %1_numpy_array\n").arg(varName) ); - command.append( QString("del %1_dtype\n").arg(varName) ); - command.append( QString("del %1_spacing\n").arg(varName) ); - command.append( QString("del %1_origin\n").arg(varName) ); - command.append( QString("del %1_direction\n").arg(varName) ); - command.append( QString("del %1_nrComponents\n").arg(varName) ); - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - delete[] dimensions; - - - return mitkImage; -} - -bool mitk::PythonService::CopyToPythonAsCvImage( mitk::Image* image, const std::string& stdvarName ) -{ - QString varName = QString::fromStdString( stdvarName ); - QString command; - unsigned int* imgDim = image->GetDimensions(); - int npy_nd = 1; - - // access python module - PyObject *pyMod = PyImport_AddModule((char*)"__main__"); - // global dictionary - PyObject *pyDict = PyModule_GetDict(pyMod); - mitk::PixelType pixelType = image->GetPixelType(); - PyObject* npyArray = nullptr; - mitk::ImageReadAccessor racc(image); - void* array = (void*) racc.GetData(); - - // save the total number of elements here (since the numpy array is one dimensional) - npy_intp* npy_dims = new npy_intp[1]; - npy_dims[0] = imgDim[0]; - - /** - * Build a string in the format [1024,1028,1] - * to describe the dimensionality. This is needed for simple itk - * to know the dimensions of the image - */ - QString dimensionString; - dimensionString.append(QString("[")); - dimensionString.append(QString::number(imgDim[0])); - // ToDo: check if we need this - for (unsigned i = 1; i < 3; ++i) - // always three because otherwise the 3d-geometry gets destroyed - // (relevant for backtransformation of simple itk image to mitk. - { - dimensionString.append(QString(",")); - dimensionString.append(QString::number(imgDim[i])); - npy_dims[0] *= imgDim[i]; - } - dimensionString.append("]"); - - - // the next line is necessary for vectorimages - npy_dims[0] *= pixelType.GetNumberOfComponents(); - - // default pixeltype: unsigned short - NPY_TYPES npy_type = NPY_USHORT; - if( pixelType.GetComponentType() == itk::IOComponentEnum::DOUBLE ) { - npy_type = NPY_DOUBLE; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::FLOAT ) { - npy_type = NPY_FLOAT; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::SHORT) { - npy_type = NPY_SHORT; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::CHAR ) { - npy_type = NPY_BYTE; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::INT ) { - npy_type = NPY_INT; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::LONG ) { - npy_type = NPY_LONG; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UCHAR ) { - npy_type = NPY_UBYTE; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::UINT ) { - npy_type = NPY_UINT; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::ULONG ) { - npy_type = NPY_LONG; - } else if( pixelType.GetComponentType() == itk::IOComponentEnum::USHORT ) { - npy_type = NPY_USHORT; - } - else { - MITK_WARN << "not a recognized pixeltype"; - return false; - } - - // creating numpy array - import_array1 (true); - npyArray = PyArray_SimpleNewFromData(npy_nd,npy_dims,npy_type,array); - - // add temp array it to the python dictionary to access it in python code - const int status = PyDict_SetItemString( pyDict,QString("%1_numpy_array") - .arg(varName).toStdString().c_str(), - npyArray ); - // sanity check - if ( status != 0 ) - return false; - - command.append( QString("import numpy as np\n")); - //command.append( QString("if '%1' in globals():\n").arg(varName)); - //command.append( QString(" del %1\n").arg(varName)); - command.append( QString("%1_array_tmp=%1_numpy_array.copy()\n").arg(varName)); - command.append( QString("%1_array_tmp=%1_array_tmp.reshape(%2,%3,%4)\n").arg( varName, - QString::number(imgDim[1]), - QString::number(imgDim[0]), - QString::number(pixelType.GetNumberOfComponents()))); - - command.append( QString("%1 = %1_array_tmp[:,...,::-1]\n").arg(varName)); - command.append( QString("del %1_numpy_array\n").arg(varName) ); - command.append( QString("del %1_array_tmp").arg(varName) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - - this->Execute( command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - return true; -} - - -mitk::Image::Pointer mitk::PythonService::CopyCvImageFromPython( const std::string& stdvarName ) -{ - - // access python module - PyObject *pyMod = PyImport_AddModule((char*)"__main__"); - // global dictionarry - PyObject *pyDict = PyModule_GetDict(pyMod); - mitk::Image::Pointer mitkImage = mitk::Image::New(); - QString command; - QString varName = QString::fromStdString( stdvarName ); - - command.append( QString("import numpy as np\n")); - command.append( QString("%1_dtype=%1.dtype.name\n").arg(varName) ); - command.append( QString("%1_shape=np.asarray(%1.shape)\n").arg(varName) ); - command.append( QString("%1_np_array=%1[:,...,::-1]\n").arg(varName)); - command.append( QString("%1_np_array=np.reshape(%1_np_array,%1.shape[0] * %1.shape[1] * %1.shape[2])").arg(varName) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - PyObject* py_dtype = PyDict_GetItemString(pyDict,QString("%1_dtype").arg(varName).toStdString().c_str() ); - std::string dtype = PyString_AsString(py_dtype); - PyArrayObject* py_data = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_np_array").arg(varName).toStdString().c_str() ); - PyArrayObject* shape = (PyArrayObject*) PyDict_GetItemString(pyDict,QString("%1_shape").arg(varName).toStdString().c_str() ); - - size_t* d = reinterpret_cast(PyArray_DATA(shape)); - - unsigned int dimensions[3]; - dimensions[0] = d[1]; - dimensions[1] = d[0]; - dimensions[2] = d[2]; - - unsigned int nr_dimensions = 2; - - // get number of components - unsigned int nr_Components = (unsigned int) d[2]; - - auto pixelType = DeterminePixelType(dtype, nr_Components, nr_dimensions); - - mitkImage->Initialize(pixelType, nr_dimensions, dimensions); - //mitkImage->SetChannel(py_data->data); - - { - mitk::ImageWriteAccessor ra(mitkImage); - char* data = (char*)(ra.GetData()); - memcpy(data, PyArray_DATA(py_data), dimensions[0] * dimensions[1] * pixelType.GetSize()); - } - - command.clear(); - - command.append( QString("del %1_shape\n").arg(varName) ); - command.append( QString("del %1_dtype\n").arg(varName) ); - command.append( QString("del %1_np_array").arg(varName)); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - return mitkImage; -} - -ctkAbstractPythonManager *mitk::PythonService::GetPythonManager() -{ - return &m_PythonManager; -} - -mitk::Surface::Pointer mitk::PythonService::CopyVtkPolyDataFromPython( const std::string& stdvarName ) -{ - // access python module - PyObject *pyMod = PyImport_AddModule((char*)"__main__"); - // global dictionarry - PyObject *pyDict = PyModule_GetDict(pyMod); - // python memory address - PyObject *pyAddr = nullptr; - // cpp address - size_t addr = 0; - mitk::Surface::Pointer surface = mitk::Surface::New(); - QString command; - QString varName = QString::fromStdString( stdvarName ); - - command.append( QString("%1_addr_str = %1.GetAddressAsString(\"vtkPolyData\")\n").arg(varName) ); - // remove 0x from the address - command.append( QString("%1_addr = int(%1_addr_str[5:],16)").arg(varName) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - // get address of the object - pyAddr = PyDict_GetItemString(pyDict,QString("%1_addr").arg(varName).toStdString().c_str()); - - // convert to long - addr = PyInt_AsLong(pyAddr); - - MITK_DEBUG << "Python object address: " << addr; - - // get the object - vtkPolyData* poly = (vtkPolyData*)((void*)addr); - surface->SetVtkPolyData(poly); - - // delete helper variables from python stack - command = ""; - command.append( QString("del %1_addr_str\n").arg(varName) ); - command.append( QString("del %1_addr").arg(varName) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - return surface; -} - -bool mitk::PythonService::CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& stdvarName ) -{ - QString varName = QString::fromStdString( stdvarName ); - std::ostringstream oss; - std::string addr = ""; - QString command; - QString address; - - oss << (void*) ( surface->GetVtkPolyData() ); - - // get the address - addr = oss.str(); - - // remove "0x" - address = QString::fromStdString(addr.substr(2)); - - command.append( QString("%1 = vtk.vtkPolyData(\"%2\")\n").arg(varName).arg(address) ); - - MITK_DEBUG("PythonService") << "Issuing python command " << command.toStdString(); - this->Execute(command.toStdString(), IPythonService::MULTI_LINE_COMMAND ); - - return true; -} - -bool mitk::PythonService::IsSimpleItkPythonWrappingAvailable() -{ - this->Execute( "import SimpleITK as sitk\n", IPythonService::SINGLE_LINE_COMMAND ); - // directly access cpp lib - this->Execute( "import SimpleITK._SimpleITK as _SimpleITK\n", IPythonService::SINGLE_LINE_COMMAND ); - m_ItkWrappingAvailable = !this->PythonErrorOccured(); - - // check for numpy - this->Execute( "import numpy\n", IPythonService::SINGLE_LINE_COMMAND ); - - if ( this->PythonErrorOccured() ) - MITK_ERROR << "Numpy not found."; - - m_ItkWrappingAvailable = !this->PythonErrorOccured(); - - return m_ItkWrappingAvailable; -} - -bool mitk::PythonService::IsOpenCvPythonWrappingAvailable() -{ - this->Execute( "import cv2\n", IPythonService::SINGLE_LINE_COMMAND ); - m_OpenCVWrappingAvailable = !this->PythonErrorOccured(); - - return m_OpenCVWrappingAvailable; -} - -bool mitk::PythonService::IsVtkPythonWrappingAvailable() -{ - this->Execute( "import vtk", IPythonService::SINGLE_LINE_COMMAND ); - //this->Execute( "print \"Using VTK version \" + vtk.vtkVersion.GetVTKVersion()\n", IPythonService::SINGLE_LINE_COMMAND ); - m_VtkWrappingAvailable = !this->PythonErrorOccured(); - - return m_VtkWrappingAvailable; -} - -bool mitk::PythonService::PythonErrorOccured() const -{ - return m_ErrorOccured; -} - diff --git a/Modules/Python/documentation/mitkPython.dox b/Modules/Python/documentation/mitkPython.dox index ce19e8112b..de6a810166 100644 --- a/Modules/Python/documentation/mitkPython.dox +++ b/Modules/Python/documentation/mitkPython.dox @@ -1,47 +1,99 @@ /** \page mitkPython_Overview Python Module -\section python_sec1 Brief description -The MITK Python Module provides a service class to interactively run python code (passed as C++ strings) and -evaluate the results. Furthermore the service class offers means to convert an MITK Image to an ITK/OpenCV image in their wrapped python environment. -Thus, one can process MITK images with Python Code from the OpenCV and ITK wrapping system. -Furthermore one can convert an mitk::Surface to a vtkPolyData in its Python environment.
-Under the hood, the MITK build system takes care that the wrapping build process for SimpleITK/VTK/OpenCV is correctly initiated and all paths are correctly set within MITK code. -To use the features of the different toolkits make sure they are enabled during the superbuild process. - -\section python_sec2 Build Instructions - -Have a look at \ref python_sec3 on how to build MITK-Python with Qt5. -The following CMake build options are available: +\section python_sec1 Description +The MITK Python Module provides a service class to run python code and evaluate the results. Furthermore, you can transfer data structures such as MITK images to your python environment for processing. +The service implementation of the Python Module is the PythonService that uses the Python/C API to execute Python Code. Additionally, SWIG is used to wrap some MITK datatypes in python. + +\section python_build Build instructions + +To build MITK with the PythonService, the following CMake build options have to be enabled:
    -
  • MITK_USE_Python3 +
  • MITK_USE_Python3 +
  • MITK_USE_SWIG +
  • WRAP_DEFAULT +
  • WRAP_PYTHON
-\subsection python_ssec1 MITK_USE_Python3 -MITK_USE_Python3 enables the python wrapping in MITK. When the option is activated -the build of the additional dependency SimpleITK is also enabled. The default behaviour is to use the python runtime from the system is used. -Only Python 3.x is supported. -The user can also specify it's own runtime by modifying the variables added by the -FindPythonLib.cmake script. Note: A Python runtime with numpy is needed to use the MITK Python wrapping. -When using this options all additional libraries installed in the python runtime will be available within the MITK-Python console. +MITK_USE_Python3 enables the use of python in MITK. When the option is activated the build of the additional dependency SimpleITK is also enabled. The default behaviour is to use the python runtime from the system. Only Python 3.x is supported. +The other options are all for wrapping MITK classes in Python classes. + +\section python_setup Setup +To get an instance of the PythonService, the following code is necessary: + +\code{.cpp} +us::ModuleContext *context = us::GetModuleContext(); +std::string filter = "(Name=PythonService)"; +auto m_PythonServiceRefs = context->GetServiceReferences(filter); +auto *m_PythonService = dynamic_cast (context->GetService (m_PythonServiceRefs.front())); +\endcode + +\section python_usage Usage +In the following sections, some of the key features of the PythonService are described. -\section python_sec3 Suported Data Types -The following data types in MITK are supported in the MITK Python Wrapping: +\subsection python_executing_code Executing python code +Python code can be executed in two ways:
    -
  • Image -
  • Surface +
  • With the method Execute(const std::string &pythonCommand, int commandType), code can be executed in form of a C++ string. The variable commandType can have the following values: +
      +
    • IPythonService::SINGLE_LINE_COMMAND for single statements +
    • IPythonService::MULTI_LINE_COMMAND for larger code snippets +
    • IPythonService::EVAL_COMMAND for isolated expressions, e.g. calculations. +
    + If no commandType is given, IPythonService::MULTI_LINE_COMMAND is the default. +
  • With the method ExecuteScript(const std::string &pythonScript), whole python scripts can be executed. pythonScript is the path to the script which should be executed. + If this file is located within the MITK sourcecode, the path can be determined by the method FindFile(const char *filename, const char *pathInSourceDir) which is implemented in the class mitk::StandardFileLocations. The following code shows an example of a script to be executed: + \code{.cpp} + std::string pythonFileName = "hello.py"; + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( pythonFileName.c_str(), "Examples/Plugins/org.mitk.example.gui.pythonexample/resources"); + m_PythonService->ExecuteScript(fileName); + \endcode
-\subsection python_ssec4 Image -Mitk Images can be transferred to python. The images are copied in-memory and -transferred as a numpy array to Python and vice versa. The MITK python wrapping creates a SimpleITK image -using the numpy array with the properties of the MITK Image. Two dimensional images -can also be transferred as an OpenCV image to python. +\subsection python_access_variables Accessing variables +The following methods are available for accessing varaibles: +
    +
  • GetVariableStack() returns all variables from the python context. The variables are returned as a list of the type PythonVariable. This contains for all variables the name, type and value as string format. +
  • DoesVariableExist(const std::string& name) returns a boolean, whether a variable with a given name exists in the current python context. +
  • GetVariable (const std::string& name) returns the value of a python variable with the given name as a string. +
+ +\subsection python_transfer_images Transfer Images + +With the PythonService, images can be transferred from C++ to the python context and vice versa. +\note Currently, MITK images can be transferred and can be used in the python context either as MITK image or as SimpleITK image. If you want to use the MITK image data structure in the python context, you need to import pyMITK in your script. + +\subsubsection python_images_mitk_python Transfer images from C++ to python +To transfer images from C++ to python, the following methods are provided: +
    +
  • CopyToPythonAsSimpleItkImage(mitk::Image::Pointer image, const std::string &stdvarName) to transfer a MITK image to python which should be used as SimpleITK image in the python context. +
  • CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &stdvarName) to transfer a MITK image to python which should be used as MITK image in the python context as well. +
+ +In this methods image defines the image which should be transferred and stdvarName the name of the image variable in the python context. + +\subsubsection python_images_python_mitk Transfer Images from python to C++ +To transfer images from python to C++, the following methods are provided: +
    +
  • CopySimpleItkImageFromPython(const std::string &stdvarName) for transferring a SimpleITK image from the python context to a MITK image in C++. +
  • CopyMITKImageFromPython(const std::string &stdvarName) for transferring a MITK image from the python context to a MITK image in C++. +
+The parameter stdvarName is the variable name of the image in the python context. + +\subsubsection python_multiple_images Transferring multiple images +\note Multiple images can currently only be transferred from the python context to C++ and only, if they are provided as a list of MITK images in the python context. + +Sometimes, multiple images should be transferred from python to C++, e.g. when you have a multilabel segmentation and want to return the result as single images. +If the images are stored in a list, this list can be transferred to C++, where it will be a std::vector of the type mitk::Image::Pointer. +Therefore, the method CopyListOfMITKImagesFromPython(const std::string, &listVarName) exists. listVarName ist the name of the list variable of images in python, that should be transferred. + +\subsection python_observer Inform observer +If a class should be notified as soon as a python command gets executed, the interface PythonCommandObserver has to be implemented. +Within this, only the method CommandExecuted(const std::string& pythonCommand) has to be implemented, which is called as soon as the python service executes a command. +To register the observer, the method AddPythonCommandObserver(PythonCommandObserver* observer) has to be called with the implemented observer class as parameter. +Analogously, the observer can be removed with the method RemovePythonCommandObserver(PythonCommandObserver* observer) -\subsection python_ssec5 Surface -Surfaces within mitk can be transferred as a vtkPolyData Object to Python. -The surfaces are fully memory mapped. When changing a python wrapped surface -the original object is also modified on the C++ side of MITK. +With the method GetNumberOfObserver(), the number of currently registered observers can be determined. - */ +*/ \ No newline at end of file diff --git a/Modules/Python/mitkIPythonService.cpp b/Modules/Python/mitkIPythonService.cpp index e52b7bb25e..2d2f0b1c2f 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Modules/Python/mitkIPythonService.cpp @@ -1,25 +1,25 @@ /*============================================================================ 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 "mitkIPythonService.h" mitk::IPythonService::~IPythonService() { } std::string mitk::IPythonService::ForceLoadModule() { std::string ret = "Load python module"; - MITK_INFO << ret; + MITK_DEBUG << ret; return ret; } diff --git a/Modules/Python/mitkIPythonService.h b/Modules/Python/mitkIPythonService.h index eb9c4d1dad..21d6fa0626 100644 --- a/Modules/Python/mitkIPythonService.h +++ b/Modules/Python/mitkIPythonService.h @@ -1,153 +1,148 @@ /*============================================================================ 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 mitkIPythonService_h #define mitkIPythonService_h // mitk #include #include "mitkImage.h" //for microservices #include #include "mitkSurface.h" #include -class ctkAbstractPythonManager; namespace mitk { /// /// describes a python variable (data container) /// \see IPythonService::GetVariableStack() /// struct PythonVariable { std::string m_Name; std::string m_Type; std::string m_Value; }; /// /// a PythonCommandObserver gets informed as soon as a python command was issued /// \see IPythonService::AddPythonCommandObserver() /// class PythonCommandObserver { public: virtual void CommandExecuted(const std::string& pythonCommand) = 0; }; /// /// The central service for issuing Python Code /// The class also enables to transfer mitk images to python as itk::Image and vice versa /// \see IPythonService::GetVariableStack() /// class MITKPYTHON_EXPORT IPythonService { public: /// /// Constant representing a single line command /// \see IPythonService::Execute() static const int SINGLE_LINE_COMMAND = 0; /// /// Constant representing a command in which the commands are seperated by new lines, i.e. "\\n" /// \see IPythonService::Execute() static const int MULTI_LINE_COMMAND = 1; /// /// Constant representing a single line command x which is run as "eval(x)" /// \see IPythonService::Execute() static const int EVAL_COMMAND = 2; - + /// /// /// Executes a python command. /// \return A variant containing the return value as string of the python code (if any) - virtual std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) = 0; + virtual std::string Execute( const std::string& pythonCommand, int commandType= MULTI_LINE_COMMAND) = 0; /// /// Executes a python script. - virtual void ExecuteScript( const std::string& pathToPythonScript ) = 0; + virtual void ExecuteScript(const std::string &pathToPythonScript) = 0; /// /// \return true if the last call to Execute...() resulted in an error, false otherwise virtual bool PythonErrorOccured() const = 0; /// /// \return The list of variables in the __main__ namespace - virtual std::vector GetVariableStack() const = 0; + virtual std::vector GetVariableStack() = 0; /// /// \return true if a variable with this name is defined in the __main__ namespace, false otherwise - virtual bool DoesVariableExist(const std::string& name) const = 0; + virtual bool DoesVariableExist(const std::string& name) = 0; /// /// \return value of variable with this name as string, empty string if variable does not exist - virtual std::string GetVariable(const std::string& name) const = 0; + virtual std::string GetVariable(const std::string& name) = 0; /// /// adds a command observer which is informed after a command was issued with "Execute" virtual void AddPythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// removes a specific command observer virtual void RemovePythonCommandObserver( PythonCommandObserver* observer ) = 0; /// /// notify all observer. this should only be used if it can be garantueed that the /// current python interpreter instance got another command from anywhere else /// the the Execute() method of this service, e.g. the shell widget uses this function /// since it does not use Execute() virtual void NotifyObserver( const std::string& command ) = 0; - + /// + /// \return the number of registered Observers + virtual int GetNumberOfObserver() = 0; /// /// \return true, if itk wrapping is available, false otherwise virtual bool IsSimpleItkPythonWrappingAvailable() = 0; /// /// copies an mitk image as itk image into the python interpreter process /// the image will be available as "varName" in python if everythin worked /// \return true if image was copied, else false - virtual bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ) = 0; + virtual bool CopyToPythonAsSimpleItkImage( mitk::Image::Pointer image, const std::string& varName ) = 0; /// /// copies an itk image from the python process that is named "varName" /// \return the image or 0 if copying was not possible virtual mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ) = 0; - - /// - /// \return true, if OpenCv wrapping is available, false otherwise - virtual bool IsOpenCvPythonWrappingAvailable() = 0; - /// - /// \see CopyToPythonAsItkImage() - virtual bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) = 0; - /// - /// \see CopyCvImageFromPython() - virtual mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) = 0; - /// - /// \return true, if vtk wrapping is available, false otherwise - virtual bool IsVtkPythonWrappingAvailable() = 0; + /// copies an mitk image into the python interpreter process + /// the image will be available as "varName" in python if everythin worked + /// \return true if image was copied, else false + virtual bool CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) = 0; /// - /// \see CopyToPythonAsItkImage() - virtual bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) = 0; + /// copies an mitk image from the python process that is named "varName" + /// \return the image or 0 if copying was not possible + virtual mitk::Image::Pointer CopyMITKImageFromPython(const std::string &varName) = 0; /// - /// \see CopyCvImageFromPython() - virtual mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) = 0; - - /// \return the ctk abstract python manager instance - virtual ctkAbstractPythonManager* GetPythonManager() = 0; - + /// copies an list of mitk images from the python process that is named "listVarName" + /// \return the image or 0 if copying was not possible + virtual std::vector CopyListOfMITKImagesFromPython(const std::string &listVarName) = 0; /// /// nothing to do here virtual ~IPythonService(); // leer in mitkIPythonService.cpp implementieren // force us module loading by linking static std::string ForceLoadModule(); + // adding search directories enables to call python code located in the given directory + // relative paths to the mitk root directory virtual void AddRelativeSearchDirs(std::vector< std::string > dirs) = 0; - virtual void AddAbsoluteSearchDirs(std::vector< std::string > dirs) = 0; + // absolute paths for directories to be added + virtual void AddAbsoluteSearchDirs(std::vector dirs) = 0; + + protected: }; } MITK_DECLARE_SERVICE_INTERFACE(mitk::IPythonService, "org.mitk.services.IPythonService") #endif diff --git a/Modules/Python/test/CMakeLists.txt b/Modules/Python/test/CMakeLists.txt new file mode 100644 index 0000000000..153cd81e2e --- /dev/null +++ b/Modules/Python/test/CMakeLists.txt @@ -0,0 +1 @@ +MITK_CREATE_MODULE_TESTS() diff --git a/Modules/Python/test/files.cmake b/Modules/Python/test/files.cmake new file mode 100644 index 0000000000..609c1cd374 --- /dev/null +++ b/Modules/Python/test/files.cmake @@ -0,0 +1,11 @@ +set(MODULE_TESTS + mitkPythonTest.cpp +) + +set(CPP_FILES + mitkPythonObserverMock.cpp +) + +set(H_FILES + mitkPythonObserverMock.h +) diff --git a/Modules/Python/test/hello_world_project/__init__.py b/Modules/Python/test/hello_world_project/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Modules/Python/test/hello_world_project/call_hello.py b/Modules/Python/test/hello_world_project/call_hello.py new file mode 100644 index 0000000000..02da366bd0 --- /dev/null +++ b/Modules/Python/test/hello_world_project/call_hello.py @@ -0,0 +1,6 @@ +from hello_to_call import HelloToCall + +if __name__ == "__main__": + hi = HelloToCall() + hi.text = "Hello from another script!" + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py b/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py new file mode 100644 index 0000000000..391ac82dc6 --- /dev/null +++ b/Modules/Python/test/hello_world_project/call_hello_in_subfolder.py @@ -0,0 +1,5 @@ +from hello_subfolder.hello import HelloToCallInFolder +if __name__ == "__main__": + hi = HelloToCallInFolder() + hi.text = "Hello from outside the subfolder!" + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello.py b/Modules/Python/test/hello_world_project/hello.py new file mode 100644 index 0000000000..43baad3a57 --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello.py @@ -0,0 +1,10 @@ +class HelloWorld: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) + +if __name__ == "__main__": + hi = HelloWorld() + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello_subfolder/__init__.py b/Modules/Python/test/hello_world_project/hello_subfolder/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Modules/Python/test/hello_world_project/hello_subfolder/hello.py b/Modules/Python/test/hello_world_project/hello_subfolder/hello.py new file mode 100644 index 0000000000..124fcc5e55 --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello_subfolder/hello.py @@ -0,0 +1,10 @@ +class HelloToCallInFolder: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) + +if __name__ == "__main__": + hi = HelloWorld() + hi.print_text() diff --git a/Modules/Python/test/hello_world_project/hello_to_call.py b/Modules/Python/test/hello_world_project/hello_to_call.py new file mode 100644 index 0000000000..dc484f591a --- /dev/null +++ b/Modules/Python/test/hello_world_project/hello_to_call.py @@ -0,0 +1,6 @@ +class HelloToCall: + def __init__(self): + self.text = "Hello World!" + + def print_text(self): + print(self.text) diff --git a/Modules/Python/test/mitkPythonObserverMock.cpp b/Modules/Python/test/mitkPythonObserverMock.cpp new file mode 100644 index 0000000000..1636f45c22 --- /dev/null +++ b/Modules/Python/test/mitkPythonObserverMock.cpp @@ -0,0 +1,12 @@ +#include "mitkPythonObserverMock.h" + +PythonObserverMock::PythonObserverMock() + : m_Updated(false) +{ +} + +void PythonObserverMock::CommandExecuted(const std::string &pythonCommand) +{ + MITK_DEBUG << "received Command " << pythonCommand; + m_Updated = true; +} diff --git a/Modules/Python/mitkIPythonService.cpp b/Modules/Python/test/mitkPythonObserverMock.h similarity index 57% copy from Modules/Python/mitkIPythonService.cpp copy to Modules/Python/test/mitkPythonObserverMock.h index e52b7bb25e..7edccc0f74 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Modules/Python/test/mitkPythonObserverMock.h @@ -1,25 +1,24 @@ /*============================================================================ 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 mitkPythonObserverMock_h +#define mitkPythonObserverMock_h +#include -#include "mitkIPythonService.h" - -mitk::IPythonService::~IPythonService() -{ -} - -std::string mitk::IPythonService::ForceLoadModule() +class PythonObserverMock : public mitk::PythonCommandObserver { - std::string ret = "Load python module"; - MITK_INFO << ret; - return ret; -} +public: + PythonObserverMock(); + void CommandExecuted(const std::string &pythonCommand) override; + bool m_Updated; +}; +#endif \ No newline at end of file diff --git a/Modules/Python/test/mitkPythonTest.cpp b/Modules/Python/test/mitkPythonTest.cpp new file mode 100644 index 0000000000..516d0a40aa --- /dev/null +++ b/Modules/Python/test/mitkPythonTest.cpp @@ -0,0 +1,581 @@ +/*============================================================================ + +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 + + + + +class mitkPythonTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkPythonTestSuite); + + MITK_TEST(TestEvaluateOperationWithResult); + MITK_TEST(TestExecuteStatement); + MITK_TEST(TestSettingVariable); + MITK_TEST(TestSettingVariableAndUseIt); + MITK_TEST(TestRunningScript); + MITK_TEST(TestRunningScriptCallOtherScript); + MITK_TEST(TestRunningScriptCallOtherScriptInSubfolder); + MITK_TEST(TestGetVariableStack); + MITK_TEST(TestGetVariable); + MITK_TEST(TestDoesVariableExist_True); + MITK_TEST(TestDoesVariableExist_False); + MITK_TEST(TestAddObserver); + MITK_TEST(TestRemoveObserver); + MITK_TEST(TestNotifyObserver); + MITK_TEST(TestCopyImageSimpleITK); + MITK_TEST(TestCopyImageMITK); + CPPUNIT_TEST_SUITE_END(); + +public: + + void setUp() + { + mitk::IPythonService::ForceLoadModule(); + } + + void TestEvaluateOperationWithResult() + { + std::string result = ""; + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + result = m_PythonService->Execute("5+5", mitk::IPythonService::EVAL_COMMAND); + try + { + std::string result = m_PythonService->Execute("5+5", mitk::IPythonService::EVAL_COMMAND); + CPPUNIT_ASSERT_MESSAGE("Testing if running python code 5+5 results in 10", result == "10"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution"); + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestExecuteStatement() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + std::string result = m_PythonService->Execute("print('Hello')"); + //std::string result = "None"; + CPPUNIT_ASSERT_MESSAGE("Testing if executing a statement works", result == "None"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution"); + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestSettingVariable() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + std::string result = m_PythonService->Execute("number = 5"); + CPPUNIT_ASSERT_MESSAGE("Testing if initializing a variable works", result == "None"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution"); + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestSettingVariableAndUseIt() + { + std::string result = ""; + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + result = m_PythonService->Execute("number = 5"); + result = m_PythonService->Execute("number+5", mitk::IPythonService::EVAL_COMMAND); + CPPUNIT_ASSERT_MESSAGE("Testing if initializing a variable and using it works", result == "10"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution"); + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestRunningScript() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + std::string pythonFileName = "hello.py"; + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( + pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); + m_PythonService->ExecuteScript(fileName); + } + catch(const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution for Script"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestRunningScriptCallOtherScript() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + try + { + std::string path = "Modules/Python/test/hello_world_project"; + std::vector pathVector; + pathVector.push_back(path); + m_PythonService->AddRelativeSearchDirs(pathVector); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in setting the search directory"); + return; + } + + std::string pythonFileName = "call_hello.py"; + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( + pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); + m_PythonService->ExecuteScript(fileName); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution for Script"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestRunningScriptCallOtherScriptInSubfolder() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + try + { + std::string path = "Modules/Python/test/hello_world_project"; + std::vector pathVector; + pathVector.push_back(path); + m_PythonService->AddRelativeSearchDirs(pathVector); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in setting the search directory"); + return; + } + + std::string pythonFileName = "call_hello_in_subfolder.py"; + std::string fileName = mitk::StandardFileLocations::GetInstance()->FindFile( + pythonFileName.c_str(), "Modules/Python/test/hello_world_project"); + m_PythonService->ExecuteScript(fileName); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution for Script"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestGetVariableStack() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + try + { + auto list = m_PythonService->GetVariableStack(); + if (!(list.size() > 0)) + { + CPPUNIT_FAIL("Failed to get variable stack"); + } + //for (mitk::PythonVariable var : list) + //{ + // MITK_INFO << var.m_Name << ", " << var.m_Value << ", " << var.m_Type; + //} + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in getting variable stack"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestGetVariable() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + m_PythonService->Execute("variable_to_get ='Get this variable'"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in setting the variable"); + return; + } + try + { + std::string variableToGet = m_PythonService->GetVariable("variable_to_get"); + CPPUNIT_ASSERT_MESSAGE("Testing if getting a variable as string representation works", + variableToGet == "'Get this variable'"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in getting a variable as string representation"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestDoesVariableExist_True() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + m_PythonService->Execute("existingVariable ='This variable exists'"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in setting the variable"); + return; + } + try + { + bool variableExists = m_PythonService->DoesVariableExist("existingVariable"); + CPPUNIT_ASSERT_MESSAGE("Testing if an existing variable is recognized", variableExists == true); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in checking if a variable exists"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestDoesVariableExist_False() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + try + { + bool variableExists = m_PythonService->DoesVariableExist("nonExistingVariable"); + CPPUNIT_ASSERT_MESSAGE("Testing if an not existing variable is not recognized", variableExists == false); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in checking if a variable exists"); + return; + } + } + else + { + CPPUNIT_FAIL("No Service Reference found"); + } + } + + void TestAddObserver() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + int numberBeforeAdding = m_PythonService->GetNumberOfObserver(); + auto observer = new PythonObserverMock; + m_PythonService->AddPythonCommandObserver(observer); + int numberAfterAdding = m_PythonService->GetNumberOfObserver(); + CPPUNIT_ASSERT_MESSAGE("Testing if a new command observer can be added", numberAfterAdding == numberBeforeAdding+1); + } + } + + void TestRemoveObserver() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + int numberBeforeAdding = m_PythonService->GetNumberOfObserver(); + auto observer = new PythonObserverMock; + m_PythonService->AddPythonCommandObserver(observer); + int numberAfterAdding = m_PythonService->GetNumberOfObserver(); + CPPUNIT_ASSERT_MESSAGE("Testing if a new command observer can be added", + numberAfterAdding == numberBeforeAdding + 1); + + m_PythonService->RemovePythonCommandObserver(observer); + int numberAfterRemoving = m_PythonService->GetNumberOfObserver(); + CPPUNIT_ASSERT_MESSAGE("Testing if a command observer can be removed", + numberAfterRemoving == numberBeforeAdding); + } + } + + void TestNotifyObserver() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + + auto observer = new PythonObserverMock; + m_PythonService->AddPythonCommandObserver(observer); + std::string command = "number = 5"; + try + { + m_PythonService->Execute(command); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in Python Execution"); + } + CPPUNIT_ASSERT_MESSAGE("Testing if a command observer is notified", + observer->m_Updated == true); + } + } + + + void TestCopyImageSimpleITK() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + mitk::Image::Pointer image_in = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); + mitk::Image::Pointer image_out; + try + { + m_PythonService->CopyToPythonAsSimpleItkImage(image_in, "image"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in copying Image to Python"); + } + try + { + image_out = m_PythonService->CopySimpleItkImageFromPython("image"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in copying Image to Python"); + } + CPPUNIT_ASSERT_MESSAGE("copy an image to python and back should result in equal image", + mitk::Equal(*image_in, *image_out, mitk::eps, true)); + } + } + + void TestCopyImageMITK() + { + us::ModuleContext *context = us::GetModuleContext(); + std::string filter = "(Name=PythonService)"; + auto m_PythonServiceRefs = context->GetServiceReferences(filter); + + if (!m_PythonServiceRefs.empty()) + { + mitk::IPythonService *m_PythonService = + dynamic_cast(context->GetService(m_PythonServiceRefs.front())); + mitk::Image::Pointer image_in = mitk::IOUtil::Load(GetTestDataFilePath("Pic3D.nrrd")); + mitk::Image::Pointer image_out; + try + { + m_PythonService->CopyMITKImageToPython(image_in, "mitkimage"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in copying Image to Python"); + } + try + { + image_out = m_PythonService->CopyMITKImageFromPython(/*image_in,*/"mitkimage"); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + CPPUNIT_FAIL("Error in copying Image to Python"); + } + if (image_out ==nullptr) + { + MITK_INFO << "ups"; + } + CPPUNIT_ASSERT_MESSAGE("copy an image to python and back should result in equal image", + mitk::Equal(*image_in, *image_out, mitk::eps, true)); + } + } +}; + +MITK_TEST_SUITE_REGISTRATION(mitkPython) diff --git a/Modules/PythonService/CMakeLists.txt b/Modules/PythonService/CMakeLists.txt new file mode 100644 index 0000000000..219f7a261f --- /dev/null +++ b/Modules/PythonService/CMakeLists.txt @@ -0,0 +1,13 @@ +if(MITK_WRAP_PYTHON_ENABLED) + mitkFunctionCheckCompilerFlags("-Wno-cpp" CMAKE_CXX_FLAGS) + + mitk_create_module(PythonService + DEPENDS PRIVATE MitkPython + PACKAGE_DEPENDS PRIVATE Python3|NumPy + AUTOLOAD_WITH MitkPython + ) + + if(TARGET ${MODULE_TARGET}) + configure_file(PythonPath.h.in "${CMAKE_CURRENT_BINARY_DIR}/PythonPath.h" @ONLY) + endif() +endif() diff --git a/Modules/Python/autoload/PythonService/PythonPath.h.in b/Modules/PythonService/PythonPath.h.in similarity index 79% rename from Modules/Python/autoload/PythonService/PythonPath.h.in rename to Modules/PythonService/PythonPath.h.in index 28581baec4..ae0a8942f8 100644 --- a/Modules/Python/autoload/PythonService/PythonPath.h.in +++ b/Modules/PythonService/PythonPath.h.in @@ -1,16 +1,16 @@ -#ifdef _DEBUG -#define PYTHON_PATH_BUILD_TYPE "/Debug" -#else -#define PYTHON_PATH_BUILD_TYPE "/Release" -#endif +#define EP_DLL_DIR "@MITK_EXTERNAL_PROJECT_PREFIX@/bin" -#define PYTHON_LIBRARY "@PYTHON_LIBRARY@" +#define BIN_DIR "@MITK_BINARY_DIR@/bin" #ifdef WIN32 //Todo: windows system python #define EXTERNAL_SITE_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/site-packages" #define EXTERNAL_DIST_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/dist-packages" #else #define EXTERNAL_SITE_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/site-packages" #define EXTERNAL_DIST_PACKAGES "@MITK_EXTERNAL_PROJECT_PREFIX@/lib/python@PYTHON_VERSION_MAJOR@.@PYTHON_VERSION_MINOR@/dist-packages" #endif + +#ifndef WIN32 +#define PYTHON_INCLUDE "@Python3_INCLUDE_DIR@" +#endif diff --git a/Modules/Python/autoload/PythonService/files.cmake b/Modules/PythonService/files.cmake similarity index 100% rename from Modules/Python/autoload/PythonService/files.cmake rename to Modules/PythonService/files.cmake diff --git a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp b/Modules/PythonService/mitkPythonActivator.cpp similarity index 97% rename from Modules/Python/autoload/PythonService/mitkPythonActivator.cpp rename to Modules/PythonService/mitkPythonActivator.cpp index d58ba5cf27..da88d0f24c 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonActivator.cpp +++ b/Modules/PythonService/mitkPythonActivator.cpp @@ -1,63 +1,64 @@ /*============================================================================ 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 mitkPythonActivator_h #define mitkPythonActivator_h // Microservices #include #include "usModuleContext.h" #include "mitkPythonService.h" #include namespace mitk { /// /// installs the PythonService /// runs all initial commands (setting env paths etc) /// class PythonActivator : public us::ModuleActivator { public: void Load(us::ModuleContext* context) override { MITK_DEBUG << "PythonActivator::Load"; // Registering PythonService as MicroService m_PythonService = itk::SmartPointer(new PythonService()); us::ServiceProperties _PythonServiceProps; _PythonServiceProps["Name"] = std::string("PythonService"); + _PythonServiceProps["service.ranking"] = int(0); m_PythonServiceRegistration = context->RegisterService(m_PythonService.GetPointer(), _PythonServiceProps); } void Unload(us::ModuleContext*) override { MITK_DEBUG("PythonActivator") << "PythonActivator::Unload"; MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); m_PythonServiceRegistration.Unregister(); m_PythonService->Delete(); MITK_DEBUG("PythonActivator") << "m_PythonService GetReferenceCount " << m_PythonService->GetReferenceCount(); } ~PythonActivator() override { } private: itk::SmartPointer m_PythonService; us::ServiceRegistration m_PythonServiceRegistration; }; } US_EXPORT_MODULE_ACTIVATOR(mitk::PythonActivator) #endif diff --git a/Modules/PythonService/mitkPythonService.cpp b/Modules/PythonService/mitkPythonService.cpp new file mode 100644 index 0000000000..1942396b7e --- /dev/null +++ b/Modules/PythonService/mitkPythonService.cpp @@ -0,0 +1,660 @@ +/*============================================================================ + +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 "mitkPythonService.h" +#include + +#ifdef _DEBUG + #undef _DEBUG + #include + #define _DEBUG +#else + #include +#endif + +#include "PythonPath.h" +#include +#include +#include +#include +#include + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include + +#include + +#ifndef WIN32 +#include +#endif + +#include +#include + +typedef itksys::SystemTools ist; + +mitk::PythonService::PythonService() + : m_ItkWrappingAvailable(true), + m_ErrorOccured(false) +{ + // for Linux, libpython needs to be opened before initializing the Python Interpreter to enable imports + #ifndef WIN32 + std::vector pythonIncludeVector; + // get libpython file to open (taken from "Python3_INCLUDE_DIR" variable from CMake to dynamically do it for different python versions) + boost::split(pythonIncludeVector, PYTHON_INCLUDE, boost::is_any_of( "/" ) ); + std::string libPython = "lib"+pythonIncludeVector[pythonIncludeVector.size()-1]+".so"; + dlopen(libPython.c_str(), RTLD_LAZY | RTLD_GLOBAL); + #endif + // Initialize Python interpreter and ensure global interpreter lock in order to execute python code safely + if (!Py_IsInitialized()) + { + Py_Initialize(); + } + + PyGILState_Ensure(); + std::string programPath = mitk::IOUtil::GetProgramPath(); + std::replace(programPath.begin(), programPath.end(), '\\', '/'); + programPath.append("/"); + MITK_INFO << programPath; + std::string pythonCommand; + + // execute a string which imports packages that are needed and sets paths to directories + pythonCommand.append("import SimpleITK as sitk\n"); + pythonCommand.append("import SimpleITK._SimpleITK as _SimpleITK\n"); + pythonCommand.append("import numpy\n"); + + pythonCommand.append("import site, sys\n"); + pythonCommand.append("import os\n"); + pythonCommand.append("sys.path.append('')\n"); + pythonCommand.append("sys.path.append('" + programPath + "')\n"); + pythonCommand.append("sys.path.append('" + std::string(BIN_DIR) + "')\n"); + pythonCommand.append("sys.path.append('" +std::string(EXTERNAL_DIST_PACKAGES) + "')\n"); + pythonCommand.append("\nsite.addsitedir('"+std::string(EXTERNAL_SITE_PACKAGES)+"')\n"); + // in python 3.8 onwards, the path system variable is not longer used to find dlls + // that's why the dlls that are needed for swig wrapping need to be searched manually + std::string searchForDll = "if sys.version_info[1] > 7:\n" + " os.add_dll_directory('"+std::string(EP_DLL_DIR)+"')\n"; + pythonCommand.append(searchForDll); + if (PyRun_SimpleString(pythonCommand.c_str()) == -1) + { + MITK_ERROR << "Something went wrong in setting the path in Python"; + } + PyObject *main = PyImport_AddModule("__main__"); + m_GlobalDictionary = PyModule_GetDict(main); + m_LocalDictionary = m_GlobalDictionary; + m_ThreadState = PyEval_SaveThread(); +} + +mitk::PythonService::~PythonService() +{ +} + +void mitk::PythonService::AddRelativeSearchDirs(std::vector< std::string > dirs) +{ + for (const auto& dir : dirs) + { + try + { + std::string path = std::string(MITK_ROOT) + dir; + // sys.path.append enables to call scripts which are located in the given path + std::string pythonCommand = "import sys\nsys.path.append('" + path + "')\n"; + this->Execute(pythonCommand.c_str()); + } + catch (const mitk::Exception&) + { + mitkThrow() << "An error occured setting the relative project path"; + } + } +} + +void mitk::PythonService::AddAbsoluteSearchDirs(std::vector< std::string > dirs) +{ + for (const auto& dir : dirs) + { + try + { + // sys.path.append enables to call scripts which are located in the given path + std::string pythonCommand = "import sys\nsys.path.append('" + dir + "')\n"; + this->Execute(pythonCommand.c_str()); + } + catch (const mitk::Exception&) + { + mitkThrow() << "An error occured setting the absolute project path"; + } + } +} + +std::string mitk::PythonService::Execute(const std::string &stdpythonCommand, int commandType) +{ + if (!Py_IsInitialized()) + { + Py_Initialize(); + } + std::string result = ""; + + PyGILState_Ensure(); + try + { + // command type is start symbol for python interpreter + switch (commandType) + { + case IPythonService::SINGLE_LINE_COMMAND: + commandType = Py_single_input; + break; + case IPythonService::MULTI_LINE_COMMAND: + commandType = Py_file_input; + break; + case IPythonService::EVAL_COMMAND: + commandType = Py_eval_input; + break; + default: + commandType = Py_file_input; + } + // executes python code given as string + // if result is NULL, an error occured + PyObject* executionResult = PyRun_String(stdpythonCommand.c_str(), commandType, m_GlobalDictionary, m_LocalDictionary); + // notifies registered observers that command has been executed + this->NotifyObserver(stdpythonCommand); + + // if no error occured, the result is represented as string which is returned + if (executionResult) + { + PyObject *objectsRepresentation = PyObject_Repr(executionResult); + const char *resultChar = PyUnicode_AsUTF8(objectsRepresentation); + result = std::string(resultChar); + m_ThreadState = PyEval_SaveThread(); + m_ErrorOccured = false; + } + else + { + m_ErrorOccured = true; + mitkThrow() << "An error occured while running the Python code"; + } + } + catch (const mitk::Exception& ) + { + PyErr_Print(); + m_ThreadState = PyEval_SaveThread(); + throw; + } + return result; +} + + +void mitk::PythonService::ExecuteScript(const std::string &pythonScript) +{ + // read given file as string + std::ifstream t(pythonScript.c_str()); + std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + t.close(); + // pass the file as string to the Execute() function + try + { + this->Execute(str.c_str(), MULTI_LINE_COMMAND); + } + catch (const mitk::Exception&) + { + throw; + } +} + +std::vector mitk::PythonService::GetVariableStack() +{ + // variables are returned as a list of type mitk::PythonVariable + std::vector list; + PyGILState_Ensure(); + try + { + // vaiables are taken from the main module + // get dictionary where these variables are stored + PyObject *dict = PyImport_GetModuleDict(); + PyObject *object = PyDict_GetItemString(dict, "__main__"); + if (!object) + { + mitkThrow() << "An error occured getting the Dictionary"; + } + PyObject *dirMain = PyObject_Dir(object); + PyObject *tempObject = nullptr; + + if (dirMain) + { + std::string name, attrValue, attrType; + + //iterate over python list of variables to get desired representation and store in returned variable list + for (int i = 0; i < PyList_Size(dirMain); i++) + { + // get variable at current index + tempObject = PyList_GetItem(dirMain, i); + if (!tempObject) + { + mitkThrow() << "An error occured getting an item from the dictionary"; + } + // get variable name as string + PyObject *objectsRepresentation = PyObject_Repr(tempObject); + const char *objectChar = PyUnicode_AsUTF8(objectsRepresentation); + std::string name = std::string(objectChar); + name = name.substr(1, name.size() - 2); + // get variable type as string + tempObject = PyObject_GetAttrString(object, name.c_str()); + if (!tempObject) + { + mitkThrow() << "Could not get the attribute to determine type"; + } + attrType = tempObject->ob_type->tp_name; + + // get variable value as string + PyObject *valueStringRepresentation = PyObject_Repr(tempObject); + const char *valueChar = PyUnicode_AsUTF8(valueStringRepresentation); + std::string attrValue = std::string(valueChar); + + // build variable type to store + mitk::PythonVariable var; + var.m_Name = name; + var.m_Value = attrValue; + var.m_Type = attrType; + list.push_back(var); + } + } + m_ThreadState = PyEval_SaveThread(); + } + catch (const mitk::Exception&) + { + m_ThreadState = PyEval_SaveThread(); + throw; + } + return list; +} + +std::string mitk::PythonService::GetVariable(const std::string& name) +{ + // get all variables from python context + std::vector allVars; + try + { + allVars = this->GetVariableStack(); + } + catch (const mitk::Exception&) + { + mitkThrow() << "Error getting the variable stack"; + } + // search for variable with given name + for (const auto& var: allVars) + { + if (var.m_Name == name) + { + return var.m_Value; + } + } + + return ""; +} + +bool mitk::PythonService::DoesVariableExist(const std::string& name) +{ + bool varExists = false; + // get all variables from python context + std::vector allVars; + try + { + allVars = this->GetVariableStack(); + } + catch (const mitk::Exception&) + { + mitkThrow() << "Error getting the variable stack"; + } + // check if variable with given name exists in context + for (const auto& var: allVars) + { + if (var.m_Name == name) + { + varExists = true; + break; + } + } + + return varExists; +} + +void mitk::PythonService::AddPythonCommandObserver(mitk::PythonCommandObserver *observer) +{ + //only add observer if it isn't already in list of observers + if (!(std::find(m_Observer.begin(), m_Observer.end(), observer) != m_Observer.end())) + { + m_Observer.push_back(observer); + } +} + +void mitk::PythonService::RemovePythonCommandObserver(mitk::PythonCommandObserver *observer) +{ + // iterate over all registered observers and remove the passed observer + for (std::vector::iterator iter = m_Observer.begin(); iter != m_Observer.end(); ++iter) + { + if (*iter == observer) + { + m_Observer.erase(iter); + break; + } + } +} + +void mitk::PythonService::NotifyObserver(const std::string &command) +{ + // call CommandExecuted() from observer interface in order to inform observers that command has been executed + for (const auto& observer: this->m_Observer) + { + observer->CommandExecuted(command); + } + +} + + +int mitk::PythonService::GetNumberOfObserver() +{ + return m_Observer.size(); +} + +bool mitk::PythonService::IsSimpleItkPythonWrappingAvailable() +{ + return m_ItkWrappingAvailable; +} + +bool mitk::PythonService::CopyToPythonAsSimpleItkImage(mitk::Image::Pointer image, const std::string &stdvarName) +{ + // this string is a python command which consists of two functions + // setup() is called in order to create an image variable on python side. At this point this is a MITK image + // convert_to_sitk() converts the MITK image from the previous step into a SimpleITK image. Spacing and Origin need to be set manually + // as these informations get lost when converting the image to an numpy array and back (only contains pixel information) + std::string transferToPython = "import pyMITK\n" + "import SimpleITK as sitk\n" + "mitk_image = None\n" + "geometry = None\n" + +stdvarName+" = None\n" + "\n" + "def setup(image_from_cxx):\n" + " print ('setup called with', image_from_cxx)\n" + " global mitk_image\n" + " mitk_image = image_from_cxx\n" + "\n" + "def convert_to_sitk(spacing, origin):\n" + " np = pyMITK.GetArrayViewFromImage(mitk_image)\n" + " global "+stdvarName+"\n" + " "+stdvarName+" = sitk.GetImageFromArray(np)\n" + " npSpacingArray = numpy.array(spacing , dtype=float)\n" + " "+stdvarName+".SetSpacing(npSpacingArray)\n" + " npOriginArray = numpy.array(origin , dtype=float)\n" + " " +stdvarName +".SetOrigin(npOriginArray)\n"; + // execute code to make the implemented functions available in the Python context (function is not executed, only definition loaded in Python) + this->Execute(transferToPython); + + mitk::Image::Pointer *img = ℑ + PyGILState_Ensure(); + //necessary for transfer array from C++ to Python + _import_array(); + PyObject *main = PyImport_ImportModule("__main__"); + if (main == NULL) + { + mitkThrow() << "Something went wrong getting the main module"; + } + + // create new pyobject from given image using SWIG + swig_type_info *pTypeInfo = nullptr; + pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); + int owned = 0; + PyObject *pInstance = SWIG_NewPointerObj(reinterpret_cast(img), pTypeInfo, owned); + if (pInstance == NULL) + { + mitkThrow() << "Something went wrong creating the Python instance of the image"; + } + // get image spacing and convert it to Python array + int numberOfImageDimension = image->GetDimension(); + auto spacing = image->GetGeometry()->GetSpacing(); + auto *spacingptr = &spacing; + + npy_intp dims[] = {numberOfImageDimension}; + PyObject *spacingArray = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void *)spacingptr); + + // get image origin and convert it to Python array + auto origin = image->GetGeometry()->GetOrigin(); + auto *originptr = &origin; + PyObject *originArray = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void *)originptr); + + // transfer image to python context by calling setup() function which was defined in Python string above + PyObject *setup = PyObject_GetAttrString(main, "setup"); + PyObject *result = PyObject_CallFunctionObjArgs(setup, pInstance, NULL); + if (result == NULL) + { + mitkThrow() << "Something went wrong setting the MITK image in Python"; + } + // convert MITK image in Python context to SimpleITK image and tranfer correct origin and spacing calling convert_to_sitk() from above + PyObject *convert = PyObject_GetAttrString(main, "convert_to_sitk"); + result = PyObject_CallFunctionObjArgs(convert,spacingArray, originArray, NULL); + if (result == NULL) + { + mitkThrow() << "Something went wrong converting the MITK image to a SimpleITK image"; + } + m_ThreadState = PyEval_SaveThread(); + return true; +} + +mitk::Image::Pointer mitk::PythonService::CopySimpleItkImageFromPython(const std::string &stdvarName) +{ + mitk::Image::Pointer mitkImage; + // Python code to convert SimpleITK image to MITK image + std::string convertToMITKImage = "import SimpleITK as sitk\n" + "import pyMITK\n" + "numpy_array = sitk.GetArrayViewFromImage("+stdvarName+")\n" + "mitk_image = pyMITK.GetImageFromArray(numpy_array)\n" + "spacing = "+stdvarName+".GetSpacing()\n" + "origin = "+stdvarName +".GetOrigin()\n"; + // after executing this, the desired mitk image is available in the Python context with the variable name mitk_image + this->Execute(convertToMITKImage); + + PyGILState_Ensure(); + // get dictionary with variables from main context + PyObject *main = PyImport_AddModule("__main__"); + PyObject *globals = PyModule_GetDict(main); + // get mitk_image from Python context + PyObject *pyImage = PyDict_GetItemString(globals, "mitk_image"); + if (pyImage==NULL) + { + mitkThrow() << "Could not get image from Python"; + } + + // res is status variable to check if result when getting the image from Python context is OK + int res = 0; + void *voidImage; + swig_type_info *pTypeInfo = nullptr; + pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); + // get image from Python context as C++ void pointer + res = SWIG_ConvertPtr(pyImage, &voidImage, pTypeInfo, 0); + if (!SWIG_IsOK(res)) + { + mitkThrow() << "Could not cast image to C++ type"; + } + // cast C++ void pointer to mitk::Image::Pointer + mitkImage = *(reinterpret_cast(voidImage)); + + // as spacing and origin again got lost when transferring between SimpleITK and MITK (see CopyToPythonAsSimpleItkImage()) we need to set them manually + // get spacing from Python context + PyObject *spacing = PyDict_GetItemString(globals, "spacing"); + mitk::Vector3D spacingMITK; + // convert Python Array to C++ vector + for (int i = 0; i < PyTuple_GET_SIZE(spacing); i++) + { + PyObject *spacingPy = PyTuple_GetItem(spacing, i); + double elem = PyFloat_AsDouble(spacingPy); + spacingMITK[i] = elem; + } + + // get origin from Python context + PyObject *origin = PyDict_GetItemString(globals, "origin"); + mitk::Point3D originMITK; + // convert Python Array to Point3D + for (int i = 0; i < PyTuple_GET_SIZE(origin); i++) + { + PyObject *originPy = PyTuple_GetItem(origin, i); + double elem = PyFloat_AsDouble(originPy); + originMITK[i] = elem; + } + + m_ThreadState = PyEval_SaveThread(); + // set origin and spacing correctly + mitkImage->GetGeometry()->SetSpacing(spacingMITK); + mitkImage->GetGeometry()->SetOrigin(originMITK); + return mitkImage; +} + +bool mitk::PythonService::CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &stdvarName) +{ + // this string is a python command which consists one functions + // setup() is called in order to create an image variable on python side. This is the MITK image which is passed + std::string transferToPython = "import pyMITK\n" + + stdvarName +" = None\n" + "\n" + "spacing = None\n" + "origin = None\n" + "def setup(image_from_cxx):\n" + " print ('setup called with', image_from_cxx)\n" + " global "+stdvarName+"\n" + " "+stdvarName+" = image_from_cxx\n" + "\n" + "def set_origin_and_spacing(s,o):\n" + " global spacing\n" + " global origin\n" + " spacing = numpy.array(s , dtype=float)\n" + " origin = numpy.array(o , dtype=float)\n"; + + // execute code to make the implemented functions available in the Python context (function is not executed, only + // definition loaded in Python) + this->Execute(transferToPython); + mitk::Image::Pointer *img = ℑ + // load main context to have access to defined function from above + PyGILState_Ensure(); + _import_array(); + PyObject *main = PyImport_ImportModule("__main__"); + if (main == NULL) + { + mitkThrow() << "Something went wrong getting the main module"; + } + + // create new pyobject from given image using SWIG + swig_type_info *pTypeInfo = nullptr; + pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); + int owned = 0; + PyObject *pInstance = SWIG_NewPointerObj(reinterpret_cast(img), pTypeInfo, owned); + if (pInstance == NULL) + { + mitkThrow() << "Something went wrong creating the Python instance of the image"; + } + + // call setup() function in Python with created PyObject of image + PyObject *setup = PyObject_GetAttrString(main, "setup"); + PyObject *result = PyObject_CallFunctionObjArgs(setup, pInstance, NULL); + if (result == NULL) + { + mitkThrow() << "Something went wrong setting the MITK image in Python"; + } + // get image spacing and convert it to Python array + int numberOfImageDimension = image->GetDimension(); + auto spacing = image->GetGeometry()->GetSpacing(); + auto *spacingptr = &spacing; + + npy_intp dims[] = {numberOfImageDimension}; + PyObject *spacingArray = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void *)spacingptr); + + // get image origin and convert it to Python array + auto origin = image->GetGeometry()->GetOrigin(); + auto *originptr = &origin; + PyObject *originArray = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void *)originptr); + + // convert correct origin and spacing calling set_origin_and_spacing from above + PyObject *convert = PyObject_GetAttrString(main, "set_origin_and_spacing"); + result = PyObject_CallFunctionObjArgs(convert,spacingArray, originArray, NULL); + if (result == NULL) + { + mitkThrow() << "Something went wrong setting the origin and spacing for the image"; + } + m_ThreadState = PyEval_SaveThread(); + return true; +} + +mitk::Image::Pointer GetImageFromPyObject(PyObject *pyImage) +{ + // helper function to get a MITK image from a PyObject + mitk::Image::Pointer mitkImage; + // res is status variable to check if result when getting the image from Python context is OK + int res = 0; + void *voidImage; + swig_type_info *pTypeInfo = nullptr; + pTypeInfo = SWIG_TypeQuery("_p_itk__SmartPointerT_mitk__Image_t"); + // get image from Python context as C++ void pointer + res = SWIG_ConvertPtr(pyImage, &voidImage, pTypeInfo, 0); + if (!SWIG_IsOK(res)) + { + mitkThrow() << "Could not cast image to C++ type"; + } + // cast C++ void pointer to mitk::Image::Pointer + mitkImage = *(reinterpret_cast(voidImage)); + + return mitkImage; +} + +mitk::Image::Pointer mitk::PythonService::CopyMITKImageFromPython(const std::string &stdvarName) +{ + mitk::Image::Pointer mitkImage; + + PyGILState_Ensure(); + // get image from Python context as PyObject + PyObject *main = PyImport_AddModule("__main__"); + PyObject *globals = PyModule_GetDict(main); + PyObject *pyImage = PyDict_GetItemString(globals, stdvarName.c_str()); + if (pyImage==NULL) + { + mitkThrow() << "Could not get image from Python"; + } + // convert PyObject to mitk::Image + mitkImage = GetImageFromPyObject(pyImage); + + m_ThreadState = PyEval_SaveThread(); + return mitkImage; +} + +std::vector mitk::PythonService::CopyListOfMITKImagesFromPython(const std::string &listVarName) +{ + std::vector mitkImages; + + PyGILState_Ensure(); + // get the list of the variable name as python list + PyObject *main = PyImport_AddModule("__main__"); + PyObject *globals = PyModule_GetDict(main); + PyObject *pyImageList = PyDict_GetItemString(globals, listVarName.c_str()); + if (pyImageList == NULL) + { + mitkThrow() << "Could not get image list from Python"; + } + // iterate over python list of images and convert them to C++ mitk::Image + for (int i = 0; i < PyList_GET_SIZE(pyImageList);i++) + { + PyObject *pyImage = PyList_GetItem(pyImageList, i); + mitk::Image::Pointer img = GetImageFromPyObject(pyImage); + mitkImages.push_back(img); + } + + m_ThreadState = PyEval_SaveThread(); + return mitkImages; +} + +bool mitk::PythonService::PythonErrorOccured() const +{ + return m_ErrorOccured; +} + diff --git a/Modules/Python/autoload/PythonService/mitkPythonService.h b/Modules/PythonService/mitkPythonService.h similarity index 60% rename from Modules/Python/autoload/PythonService/mitkPythonService.h rename to Modules/PythonService/mitkPythonService.h index 31338dd8e1..6b0bcb17a3 100644 --- a/Modules/Python/autoload/PythonService/mitkPythonService.h +++ b/Modules/PythonService/mitkPythonService.h @@ -1,107 +1,109 @@ /*============================================================================ 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 mitkPythonService_h #define mitkPythonService_h -#include #include "mitkIPythonService.h" #include #include "mitkSurface.h" +#ifdef _DEBUG + #undef _DEBUG + #include + #define _DEBUG +#else + #include +#endif + namespace mitk { /// /// implementation of the IPythonService using ctkabstractpythonmanager /// \see IPythonService class PythonService: public itk::LightObject, public mitk::IPythonService { public: /// /// instantiate python manager here PythonService(); /// /// empty implementation... ~PythonService() override; /// /// \see IPythonService::Execute() - std::string Execute( const std::string& pythonCommand, int commandType = SINGLE_LINE_COMMAND ) override; + std::string Execute(const std::string &pythonCommand, + int commandType = Py_file_input) override; /// /// \see IPythonService::ExecuteScript() void ExecuteScript(const std::string &pathToPythonScript) override; /// /// \see IPythonService::PythonErrorOccured() bool PythonErrorOccured() const override; /// /// \see IPythonService::GetVariableStack() - std::vector GetVariableStack() const override; + std::vector GetVariableStack() override; /// /// \see IPythonService::DoesVariableExist() - bool DoesVariableExist(const std::string& name) const override; + bool DoesVariableExist(const std::string& name) override; /// /// \see IPythonService::GetVariable() - std::string GetVariable(const std::string& name) const override; + std::string GetVariable(const std::string& name) override; /// /// \see IPythonService::AddPythonCommandObserver() void AddPythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::RemovePythonCommandObserver() void RemovePythonCommandObserver( PythonCommandObserver* observer ) override; /// /// \see IPythonService::NotifyObserver() void NotifyObserver( const std::string& command ) override; /// + /// \see IPythonService::GetNumberOfObserver() + int GetNumberOfObserver() override; + /// /// \see IPythonService::IsItkPythonWrappingAvailable() bool IsSimpleItkPythonWrappingAvailable() override; /// /// \see IPythonService::CopyToPythonAsItkImage() - bool CopyToPythonAsSimpleItkImage( mitk::Image* image, const std::string& varName ) override; + bool CopyToPythonAsSimpleItkImage( mitk::Image::Pointer image, const std::string& varName ) override; /// /// \see IPythonService::CopyItkImageFromPython() mitk::Image::Pointer CopySimpleItkImageFromPython( const std::string& varName ) override; /// - /// \see IPythonService::IsOpenCvPythonWrappingAvailable() - bool IsOpenCvPythonWrappingAvailable() override; - /// - /// \see IPythonService::CopyToPythonAsCvImage() - bool CopyToPythonAsCvImage( mitk::Image* image, const std::string& varName ) override; - /// - /// \see IPythonService::CopyCvImageFromPython() - mitk::Image::Pointer CopyCvImageFromPython( const std::string& varName ) override; + /// \see IPythonService::CopyMITKImageToPython() + bool CopyMITKImageToPython(mitk::Image::Pointer &image, const std::string &varName) override; /// - /// \see IPythonService::IsVtkPythonWrappingAvailable() - bool IsVtkPythonWrappingAvailable() override; + /// \see IPythonService::CopyMITKImageFromPython() + mitk::Image::Pointer CopyMITKImageFromPython(const std::string &varName) override; /// - /// \see IPythonService::CopyToPythonAsVtkPolyData() - bool CopyToPythonAsVtkPolyData( mitk::Surface* surface, const std::string& varName ) override; - /// - /// \see IPythonService::CopyVtkPolyDataFromPython() - mitk::Surface::Pointer CopyVtkPolyDataFromPython( const std::string& varName ) override; - /// - /// \return the ctk abstract python manager instance - ctkAbstractPythonManager* GetPythonManager() override; + /// \see IPythonService::CopyListOfMITKImagesFromPython() + std::vector CopyListOfMITKImagesFromPython(const std::string &listVarName) override; + /// + /// \see IPythonService::AddRelativeSearchDirs() void AddRelativeSearchDirs(std::vector< std::string > dirs) override; - + /// + /// \see IPythonService::AddAbsoluteSearchDirs() void AddAbsoluteSearchDirs(std::vector< std::string > dirs) override; protected: private: - QList m_Observer; - ctkAbstractPythonManager m_PythonManager; + std::vector m_Observer; + PyThreadState *m_ThreadState; + PyObject *m_GlobalDictionary; + PyObject *m_LocalDictionary; bool m_ItkWrappingAvailable; - bool m_OpenCVWrappingAvailable; - bool m_VtkWrappingAvailable; bool m_ErrorOccured; }; } #endif diff --git a/Modules/QtPython/CMakeLists.txt b/Modules/QtPython/CMakeLists.txt deleted file mode 100644 index 433b7ae4f4..0000000000 --- a/Modules/QtPython/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -if(MITK_USE_Python3) - mitkFunctionCheckCompilerFlags("/wd4273" CMAKE_CXX_FLAGS) - - mitk_create_module( - DEPENDS MitkCore MitkQtWidgets MitkPython - PACKAGE_DEPENDS - PUBLIC Qt5|Widgets CTK|CTKScriptingPythonCore+CTKScriptingPythonWidgets - ) - - if(BUILD_TESTING) - add_subdirectory(Testing) - endif() -endif() diff --git a/Modules/QtPython/QmitkCtkPythonShell.cpp b/Modules/QtPython/QmitkCtkPythonShell.cpp deleted file mode 100644 index ebdbbf36d8..0000000000 --- a/Modules/QtPython/QmitkCtkPythonShell.cpp +++ /dev/null @@ -1,94 +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 "QmitkCtkPythonShell.h" - -#include -#include -#include -#include -#include -#include "mitkIPythonService.h" -#include -#include -#include - -struct QmitkCtkPythonShellData -{ - mitk::IPythonService* m_PythonService; - us::ServiceReference m_PythonServiceRef; -}; - -QmitkCtkPythonShell::QmitkCtkPythonShell(QWidget* parent) - : ctkPythonConsole(parent), d( new QmitkCtkPythonShellData ) -{ - this->setWelcomeTextColor(Qt::green); - this->setPromptColor(Qt::gray); - this->setStdinTextColor(Qt::white); - this->setCommandTextColor(Qt::white); - this->setOutputTextColor(Qt::white); - - MITK_DEBUG("QmitkCtkPythonShell") << "retrieving IPythonService"; - us::ModuleContext* context = us::GetModuleContext(); - d->m_PythonServiceRef = context->GetServiceReference(); - d->m_PythonService = dynamic_cast ( context->GetService(d->m_PythonServiceRef) ); - - MITK_DEBUG("QmitkCtkPythonShell") << "checking IPythonService"; - Q_ASSERT( d->m_PythonService ); - - MITK_DEBUG("QmitkCtkPythonShell") << "initialize m_PythonService"; - this->initialize( d->m_PythonService->GetPythonManager() ); - - MITK_DEBUG("QmitkCtkPythonShell") << "m_PythonService initialized"; - mitk::IPythonService::ForceLoadModule(); -} - -QmitkCtkPythonShell::~QmitkCtkPythonShell() -{ - us::ModuleContext* context = us::GetModuleContext(); - context->UngetService( d->m_PythonServiceRef ); - delete d; -} - -void QmitkCtkPythonShell::dragEnterEvent(QDragEnterEvent *event) -{ - event->accept(); -} -void QmitkCtkPythonShell::dropEvent(QDropEvent *event) -{ - QList urls = event->mimeData()->urls(); - for(int i = 0; i < urls.size(); i++) - { - d->m_PythonService->Execute( urls[i].toString().toStdString(), mitk::IPythonService::SINGLE_LINE_COMMAND ); - } -} - -bool QmitkCtkPythonShell::canInsertFromMimeData(const QMimeData *) const -{ - return true; -} - -void QmitkCtkPythonShell::executeCommand(const QString& command) -{ - MITK_DEBUG("QmitkCtkPythonShell") << "executing command " << command.toStdString(); - d->m_PythonService->Execute(command.toStdString(),mitk::IPythonService::MULTI_LINE_COMMAND); - d->m_PythonService->NotifyObserver(command.toStdString()); -} - -void QmitkCtkPythonShell::Paste(const QString &command) -{ - if( this->isVisible() ) - { - this->exec( command ); - //this->executeCommand( command ); - } -} diff --git a/Modules/QtPython/QmitkCtkPythonShell.h b/Modules/QtPython/QmitkCtkPythonShell.h deleted file mode 100644 index 10c507a63d..0000000000 --- a/Modules/QtPython/QmitkCtkPythonShell.h +++ /dev/null @@ -1,56 +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 QmitkCtkPythonShell_h -#define QmitkCtkPythonShell_h - -#include -#include -#include - -/// -/// forward declarations -/// -struct QmitkCtkPythonShellData; -class ctkAbstractPythonManager; -class QDragEnterEvent; -class QDropEvent; -class QMimeData; - -/// -/// Reimplements the ctkPythonConsole with drag and drop functionality for text -/// Furthermore it calls NotifyObserver() on the IPythonService to inform listeners -/// -class MITKQTPYTHON_EXPORT QmitkCtkPythonShell : public ctkPythonConsole -{ - Q_OBJECT - -public: - QmitkCtkPythonShell(QWidget* parent = nullptr); - ~QmitkCtkPythonShell() override; -public slots: - void Paste( const QString& command ); -protected: - void dragEnterEvent(QDragEnterEvent *event) override; - void dropEvent(QDropEvent *event) override; - bool canInsertFromMimeData( const QMimeData *source ) const; - void executeCommand(const QString& command) override; - -private: - QmitkCtkPythonShellData* d; -}; - - - - -#endif // QmitkCtkPythonShell_h - diff --git a/Modules/QtPython/QmitkPythonScriptEditorHighlighter.cpp b/Modules/QtPython/QmitkPythonScriptEditorHighlighter.cpp deleted file mode 100644 index 09356d6569..0000000000 --- a/Modules/QtPython/QmitkPythonScriptEditorHighlighter.cpp +++ /dev/null @@ -1,106 +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 "QmitkPythonScriptEditorHighlighter.h" - -QmitkPythonScriptEditorHighlighter::QmitkPythonScriptEditorHighlighter(QTextDocument *parent) -: QSyntaxHighlighter(parent) -{ -} - -QmitkPythonScriptEditorHighlighter::~QmitkPythonScriptEditorHighlighter() -{ -} - -void QmitkPythonScriptEditorHighlighter::highlightBlock(const QString &text) -{ - QTextCharFormat commentFormat; - commentFormat.setFontWeight(QFont::Courier); - commentFormat.setForeground(Qt::darkGreen); - - QTextCharFormat keywordFormat; - keywordFormat.setFontWeight(QFont::Bold); - keywordFormat.setForeground(Qt::blue); - QString pattern = "\\b(and|assert|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|raise|return|try|while|yield|None|True|False)\\b"; - - QTextCharFormat qouteFormat; - qouteFormat.setForeground(Qt::gray); - - QTextCharFormat numberFormat; - numberFormat.setForeground(Qt::red); - - QRegExp numberExpression("\\d+"); - int indexNumbers = text.indexOf(numberExpression); - - while (indexNumbers >= 0) { - int length = numberExpression.matchedLength(); - setFormat(indexNumbers, length, numberFormat); - indexNumbers = text.indexOf(numberExpression, indexNumbers + length); - } - - QRegExp qouteExpression("\""); - int startQouteIndex = text.indexOf(qouteExpression); - int endQouteIndex = text.indexOf(qouteExpression, startQouteIndex); - - QRegExp keyword(pattern); - int indexKeyword = text.indexOf(keyword); - - QRegExp startCommentExpression("^#"); - QRegExp endCommentExpression("\\n"); - int startCommentIndex = text.indexOf(startCommentExpression); - int endCommentIndex = text.indexOf(endCommentExpression, startCommentIndex); - - - while (startQouteIndex >= 0) { - endQouteIndex = text.indexOf(qouteExpression, startQouteIndex+1); - int commentLength; - if (endQouteIndex == -1) { - setCurrentBlockState(1); - commentLength = text.length() - startQouteIndex; - } else { - commentLength = endQouteIndex - startQouteIndex - + qouteExpression.matchedLength(); - } - setFormat(startQouteIndex, commentLength, qouteFormat); - startQouteIndex = text.indexOf(qouteExpression, - startQouteIndex + commentLength); - } - - if(startCommentIndex < 0) - { - while (indexKeyword >= 0) { - int length = keyword.matchedLength(); - setFormat(indexKeyword, length, keywordFormat); - indexKeyword = text.indexOf(keyword, indexKeyword + length); - } - } - - while (startCommentIndex >= 0) { - endCommentIndex = text.indexOf(endCommentExpression, startCommentIndex); - int commentLength; - if (endCommentIndex == -1) { - setCurrentBlockState(1); - commentLength = text.length() - startCommentIndex; - } else { - commentLength = endCommentIndex - startCommentIndex - + endCommentExpression.matchedLength(); - } - setFormat(startCommentIndex, commentLength, commentFormat); - startCommentIndex = text.indexOf(startCommentExpression, - startCommentIndex + commentLength); - } -} - -void QmitkPythonScriptEditorHighlighter::highlightComments(const QString &) -{ -} - diff --git a/Modules/QtPython/QmitkPythonScriptEditorHighlighter.h b/Modules/QtPython/QmitkPythonScriptEditorHighlighter.h deleted file mode 100644 index a628b3ef5e..0000000000 --- a/Modules/QtPython/QmitkPythonScriptEditorHighlighter.h +++ /dev/null @@ -1,36 +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 QmitkPythonScriptEditorHighlighter_h -#define QmitkPythonScriptEditorHighlighter_h - -#include -#include - -/// -/// A script highlighter for Python Scripts -class MITKQTPYTHON_EXPORT QmitkPythonScriptEditorHighlighter : public QSyntaxHighlighter -{ - Q_OBJECT - -public: - QmitkPythonScriptEditorHighlighter(QTextDocument *parent); - ~QmitkPythonScriptEditorHighlighter() override; - -protected: - void highlightBlock(const QString &text) override; - void highlightComments(const QString &text); - -private: -}; - -#endif // QmitkPythonScriptEditorHighlighter_h diff --git a/Modules/QtPython/QmitkPythonSnippets.cpp b/Modules/QtPython/QmitkPythonSnippets.cpp deleted file mode 100644 index 460ae115dd..0000000000 --- a/Modules/QtPython/QmitkPythonSnippets.cpp +++ /dev/null @@ -1,491 +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 "QmitkPythonSnippets.h" -#include "QmitkPythonScriptEditorHighlighter.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct QmitkPythonSnippetsData -{ - QString m_AutoSaveFileName; - QString m_SaveFileName; - - QAction* m_PasteSnippet; - QAction* m_RemoveSnippet; - QAction* m_RenameSnippet; - QAction* m_AddSnippet; - QAction* m_RestoreDefaultSnippets; - QAction* m_LoadSnippets; - QAction* m_SaveSnippets; - - QToolBar* m_Toolbar; - - QComboBox* m_Name; - - QTextEdit* m_Content; - - QGridLayout* m_Layout; - - QmitkPythonSnippets::QStringMap m_Snippets; -}; - -const QString QmitkPythonSnippets::DEFAULT_SNIPPET_FILE( ":/mitkPython/PythonSnippets.xml" ); -const QString QmitkPythonSnippets::SNIPPETS_ROOT_XML_ELEMENT_NAME( "PythonSnippets" ); -const QString QmitkPythonSnippets::SNIPPETS_XML_ELEMENT_NAME( "PythonSnippet" ); - -QmitkPythonSnippets::QmitkPythonSnippets( const QString& _AutoSaveFileName, QWidget* parent ) -: QWidget(parent), d(new QmitkPythonSnippetsData) -{ - d->m_SaveFileName = QDir::currentPath(); - d->m_AutoSaveFileName = _AutoSaveFileName; - - if( !QmitkPythonSnippets::LoadStringMap( d->m_AutoSaveFileName, d->m_Snippets ) ) - { - QmitkPythonSnippets::LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); - } - - d->m_PasteSnippet = new QAction(this); - d->m_PasteSnippet->setObjectName(QString::fromUtf8("PasteSnippet")); - QIcon icon; - icon.addFile(QString::fromUtf8(":/mitkPython/edit-paste.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_PasteSnippet->setIcon(icon); - d->m_PasteSnippet->setToolTip("Paste snippet!"); - d->m_PasteSnippet->setEnabled(false); - - d->m_RemoveSnippet = new QAction(this); - d->m_RemoveSnippet->setObjectName(QString::fromUtf8("RemoveSnippet")); - QIcon icon1; - icon1.addFile(QString::fromUtf8(":/mitkPython/edit-delete.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_RemoveSnippet->setIcon(icon1); - d->m_RemoveSnippet->setToolTip("Remove snippet."); - d->m_RemoveSnippet->setEnabled(false); - - d->m_RenameSnippet = new QAction(this); - d->m_RenameSnippet->setObjectName(QString::fromUtf8("RenameSnippet")); - QIcon icon2; - icon2.addFile(QString::fromUtf8(":/mitkPython/edit-find-replace.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_RenameSnippet->setIcon(icon2); - d->m_RenameSnippet->setToolTip("Rename snippet."); - d->m_RenameSnippet->setEnabled(false); - - d->m_AddSnippet = new QAction(this); - d->m_AddSnippet->setObjectName(QString::fromUtf8("AddSnippet")); - QIcon icon3; - icon3.addFile(QString::fromUtf8(":/mitkPython/document-new.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_AddSnippet->setIcon(icon3); - d->m_AddSnippet->setToolTip("Add snippet."); - - d->m_RestoreDefaultSnippets = new QAction(this); - d->m_RestoreDefaultSnippets->setObjectName(QString::fromUtf8("RestoreDefaultSnippets")); - QIcon icon4; - icon4.addFile(QString::fromUtf8(":/mitkPython/edit-clear.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_RestoreDefaultSnippets->setIcon(icon4); - d->m_RestoreDefaultSnippets->setToolTip("Restore default snippets"); - - d->m_LoadSnippets = new QAction(this); - d->m_LoadSnippets->setToolTip("Load Snippets from disk."); - d->m_LoadSnippets->setObjectName(QString::fromUtf8("LoadSnippets")); - QIcon icon5; - icon5.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_LoadSnippets->setIcon(icon5); - - d->m_SaveSnippets = new QAction(this); - d->m_SaveSnippets->setToolTip("Save Snippets to disk."); - d->m_SaveSnippets->setObjectName(QString::fromUtf8("SaveSnippets")); - QIcon icon6; - icon6.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_SaveSnippets->setIcon(icon6); - d->m_SaveSnippets->setEnabled(false); - - d->m_Toolbar = new QToolBar; - d->m_Toolbar->addAction( d->m_PasteSnippet ); - d->m_Toolbar->addAction( d->m_AddSnippet ); - d->m_Toolbar->addAction( d->m_RemoveSnippet ); - d->m_Toolbar->addAction( d->m_RenameSnippet ); - d->m_Toolbar->addAction( d->m_RestoreDefaultSnippets ); - d->m_Toolbar->addAction( d->m_SaveSnippets ); - d->m_Toolbar->addAction( d->m_LoadSnippets ); - - d->m_Name = new QComboBox; - d->m_Name->setObjectName(QString::fromUtf8("Name")); - - d->m_Content = new QTextEdit(this); - d->m_Content->setObjectName(QString::fromUtf8("Content")); - d->m_Content->setEnabled(false); - - new QmitkPythonScriptEditorHighlighter( d->m_Content->document() ); - - d->m_Layout = new QGridLayout; - d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); - d->m_Layout->addWidget( d->m_Name, 1, 0, 1, 1 ); - d->m_Layout->addWidget( d->m_Content, 2, 0, 1, 1 ); - d->m_Layout->setContentsMargins(2,2,2,2); - - this->setLayout(d->m_Layout); - QMetaObject::connectSlotsByName(this); - - this->Update(); -} - -QmitkPythonSnippets::~QmitkPythonSnippets() -{ - delete d; -} - -void QmitkPythonSnippets::on_PasteSnippet_triggered( bool ) -{ - emit PasteCommandRequested( d->m_Content->toPlainText() ); -} - -void QmitkPythonSnippets::on_RenameSnippet_triggered(bool) -{ - QString oldname = d->m_Name->currentText(); - QString name = oldname; - bool ok = false; - while( true ) - { - name = QInputDialog::getText(this, - tr("Add new snippet"), - tr("Name of snippet:"), - QLineEdit::Normal, - name, - &ok); - - if (ok) - { - if ( d->m_Snippets.contains(name) ) - { - QMessageBox::warning(this, - tr("Duplicate name."), - tr("The entered name already exists. Enter another one or cancel the operation."), - QMessageBox::Ok, - QMessageBox::Ok ); - } - else - { - QString tmpSnippet = d->m_Snippets[oldname]; - d->m_Snippets.remove(oldname); - d->m_Snippets[name] = tmpSnippet; - this->Update(name); - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - break; - } - } - else - { - break; - } - } -} - -void QmitkPythonSnippets::on_AddSnippet_triggered(bool) -{ - bool ok; - QString name = QInputDialog::getText(this, - tr("Add new snippet"), - tr("Name of snippet:"), - QLineEdit::Normal, - "newSnippet", - &ok); - if (ok && !name.isEmpty()) - { - MITK_DEBUG("QmitkPythonSnippets") << "creating unique name for " << name.toStdString(); - name = this->CreateUniqueName(name); - - MITK_DEBUG("QmitkPythonSnippets") << "creating snippet " << name.toStdString(); - d->m_Snippets[name] = ""; - this->Update(name); - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - } -} - -QString QmitkPythonSnippets::CreateUniqueName( const QString& name ) const -{ - QString newName = name; - size_t i = 2; - while( d->m_Snippets.contains(name) ) - { - newName = name + QString("_%1").arg(i); - ++i; - } - - return newName; -} - -void QmitkPythonSnippets::on_RemoveSnippet_triggered(bool) -{ - QString name = d->m_Name->currentText(); - QString question = QString("Really remove Snippet %1?").arg(name); - int remove = QMessageBox::question( this, - QString("Confirm removal"), - question, - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No ); - - if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) - { - d->m_Snippets.remove(name); - this->Update(); - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - } -} - -void QmitkPythonSnippets::on_RestoreDefaultSnippets_triggered(bool) -{ - QString question = QString("Really restore default Snippets?"); - int remove = QMessageBox::question( this, - QString("Confirm restoring"), - question, - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No ); - if( remove == QMessageBox::Yes || remove == QMessageBox::Ok ) - { - QmitkPythonSnippets::LoadStringMap( DEFAULT_SNIPPET_FILE, d->m_Snippets ); - this->Update(); - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - } -} - -void QmitkPythonSnippets::on_Name_currentIndexChanged(int i) -{ - bool validSelection = i >= 0 ; - - d->m_PasteSnippet->setEnabled(validSelection); - d->m_RemoveSnippet->setEnabled(validSelection); - d->m_RenameSnippet->setEnabled(validSelection); - d->m_Content->setEnabled(validSelection); - d->m_SaveSnippets->setEnabled(validSelection); - - if( validSelection ) - { - QString name = d->m_Name->currentText(); - MITK_DEBUG("QmitkPythonSnippets") << "selected snippet " << name.toStdString(); - d->m_Content->setText( d->m_Snippets[name] ); - MITK_DEBUG("QmitkPythonSnippets") << "selected snippet content " << d->m_Snippets[name].toStdString(); - } -} - -void QmitkPythonSnippets::SaveStringMap(const QString &filename, const QmitkPythonSnippets::QStringMap &) const -{ - MITK_DEBUG("QmitkPythonSnippets") << "saving to xml file " << filename.toStdString(); - - if( filename.isEmpty() ) - { - MITK_WARN("QmitkPythonSnippets") << "empty auto save file path given. quit."; - return; - } - - QFile file(filename); - file.open(QIODevice::WriteOnly); - if( !file.isOpen() ) - { - MITK_WARN("QmitkPythonSnippets") << "could not open file " << filename.toStdString() << " for writing"; - return; - } - QXmlStreamWriter xmlWriter(&file); - - xmlWriter.setAutoFormatting(true); - xmlWriter.writeStartDocument(); - xmlWriter.writeStartElement(SNIPPETS_ROOT_XML_ELEMENT_NAME); - - QStringMap::const_iterator it = d->m_Snippets.begin(); - while( it != d->m_Snippets.end() ) - { - - { - MITK_DEBUG("QmitkPythonSnippets") << "SNIPPETS_XML_ELEMENT_NAME " << SNIPPETS_XML_ELEMENT_NAME.toStdString(); - MITK_DEBUG("QmitkPythonSnippets") << "writing item " << it.key().toStdString(); - } - - xmlWriter.writeStartElement(SNIPPETS_XML_ELEMENT_NAME); - - xmlWriter.writeAttribute( "key", it.key() ); - xmlWriter.writeAttribute( "value", it.value() ); - - xmlWriter.writeEndElement(); - - ++it; - } - - xmlWriter.writeEndDocument(); - if( file.isOpen() ) - file.close(); - - { - MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful "; - } - -} - -bool QmitkPythonSnippets::LoadStringMap( const QString& filename, QmitkPythonSnippets::QStringMap& oldMap ) -{ - MITK_DEBUG("QmitkPythonSnippets") << "loading from xml file " << filename.toStdString(); - QStringMap map; - - QXmlStreamReader xmlReader; - QFile file; - QByteArray data; - // resource file - if( filename.startsWith(":") ) - { - QResource res( filename ); - data = QByteArray( reinterpret_cast< const char* >( res.data() ), res.size() ); - xmlReader.addData( data ); - } - else - { - file.setFileName( filename ); - if (!file.open(QFile::ReadOnly | QFile::Text)) - { - MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) - << ": " << qPrintable(file.errorString()); - return false; - } - xmlReader.setDevice(&file); - } - - xmlReader.readNext(); - - while(!xmlReader.atEnd()) - { - xmlReader.readNext(); - - if(xmlReader.name() == SNIPPETS_XML_ELEMENT_NAME) - { - QXmlStreamAttributes attributes = xmlReader.attributes(); - QString key; - QString value; - if(attributes.hasAttribute("key")) - { - key = attributes.value("key").toString(); - } - - if(attributes.hasAttribute("value")) - { - value = attributes.value("value").toString(); - } - - if( !key.isEmpty() ) - { - MITK_DEBUG("QmitkPythonSnippets") << "loaded snippet " << key.toStdString(); - MITK_DEBUG("QmitkPythonSnippets") << "value " << value.toStdString(); - map[key] = value; - } - } - } - - if (xmlReader.hasError()) - { - MITK_ERROR << "Error: Failed to parse file " - << qPrintable(filename) << ": " - << qPrintable(xmlReader.errorString()); - return false; - } - else if (file.error() != QFile::NoError) - { - MITK_ERROR << "Error: Cannot read file " << qPrintable(filename) - << ": " << qPrintable(file.errorString()); - return false; - } - - if( file.isOpen() ) - file.close(); - - oldMap = map; - return true; -} - -void QmitkPythonSnippets::Update(const QString &name) -{ - d->m_Name->clear(); - d->m_Content->clear(); - - MITK_DEBUG("QmitkPythonSnippets") << "size of snippets " << d->m_Snippets.size(); - QStringMap::const_iterator it = d->m_Snippets.begin(); - - while( it != d->m_Snippets.end() ) - { - MITK_DEBUG("QmitkPythonSnippets") << "adding item " << it.key().toStdString(); - d->m_Name->addItem( it.key() ); - ++it; - } - - int index = d->m_Name->findText( name ); - if( index >= 0 ) - { - MITK_DEBUG("QmitkPythonSnippets") << "selecting index " << index; - d->m_Name->setCurrentIndex(index); - } - -} - -void QmitkPythonSnippets::on_Content_textChanged() -{ - if( d->m_Content->isEnabled() ) - { - QString name = d->m_Name->currentText(); - QString snippet = d->m_Content->toPlainText(); - d->m_Snippets[name] = snippet; - - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - MITK_DEBUG("QmitkPythonSnippets") << "SaveStringMap successful"; - } -} - -void QmitkPythonSnippets::on_SaveSnippets_triggered(bool) -{ - QString fileName = QFileDialog::getSaveFileName(this, "Save snippets", d->m_SaveFileName, "XML files (*.xml)"); - if( !fileName.isEmpty() ) - { - d->m_SaveFileName = fileName; - this->SaveStringMap( d->m_SaveFileName, d->m_Snippets ); - } -} - -void QmitkPythonSnippets::on_LoadSnippets_triggered(bool) -{ - QString fileName = QFileDialog::getOpenFileName(this, "Load snippets", d->m_SaveFileName, "XML files (*.xml)"); - - if( !fileName.isEmpty() ) - { - d->m_SaveFileName = fileName; - QString question = QString("Your current snippets will be overwritten. Proceed?"); - int overwrite = QMessageBox::warning(this, - QString("Confirm overwrite"), - question, - QMessageBox::Yes | QMessageBox::No, - QMessageBox::No ); - - if( overwrite == QMessageBox::Yes ) - { - this->LoadStringMap( d->m_SaveFileName, d->m_Snippets ); - this->Update( d->m_Name->currentText() ); - this->SaveStringMap( d->m_AutoSaveFileName, d->m_Snippets ); - } - } - -} diff --git a/Modules/QtPython/QmitkPythonSnippets.h b/Modules/QtPython/QmitkPythonSnippets.h deleted file mode 100644 index abec155fc2..0000000000 --- a/Modules/QtPython/QmitkPythonSnippets.h +++ /dev/null @@ -1,101 +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 _QmitkPythonSnippets_H -#define _QmitkPythonSnippets_H - -#include -#include -#include -struct QmitkPythonSnippetsData; - -/// -/// a widget that holds snippets and serializes the snippets to a certain places -class MITKQTPYTHON_EXPORT QmitkPythonSnippets: public QWidget -{ - Q_OBJECT - - public: - static const QString DEFAULT_SNIPPET_FILE; - static const QString SNIPPETS_ROOT_XML_ELEMENT_NAME; - static const QString SNIPPETS_XML_ELEMENT_NAME; - /// - /// typedef for string map - typedef QMap QStringMap; - /// - /// build ui here - /// the snippets will be loaded from _AutoSaveFileName if not empty and readable - /// otherwise the default snippets will be loaded - QmitkPythonSnippets( const QString& _AutoSaveFileName="", QWidget* parent=nullptr ); - /// - /// delete d pointer - ~QmitkPythonSnippets() override; - /// - /// read string map from xml file - static bool LoadStringMap( const QString& filename, QStringMap& oldMap ); - -signals: - /// - /// this class whishes to paste sth command - void PasteCommandRequested(const QString& command); - - protected slots: - /// - /// emits PasteCommandRequested signal - void on_PasteSnippet_triggered( bool checked = false ); - /// - /// ask for name as long as it exists, call update() - void on_RenameSnippet_triggered( bool checked = false ); - /// - /// ask for name, create snippet, call update() - void on_AddSnippet_triggered( bool checked = false ); - /// - /// remove the current snippet, call update() - void on_RemoveSnippet_triggered( bool checked = false ); - /// - /// call LoadStringMap with d->m_DefaultSnippetsAutoSaveFileName - void on_RestoreDefaultSnippets_triggered( bool checked = false ); - /// - /// update action state (enable/disable), update text box - void on_Name_currentIndexChanged( int i ); - /// - /// save changed snippet - void on_Content_textChanged(); - /// - /// ask for file, save snippets - void on_SaveSnippets_triggered( bool checked = false ); - /// - /// ask for file, load snippets (do not replace) - void on_LoadSnippets_triggered( bool checked = false ); - - protected: - /// - /// write string map to xml file - void SaveStringMap( const QString& filename, const QStringMap& map ) const; - /// - /// creates a name which does not exist in the list - QString CreateUniqueName(const QString &name) const; - /// - /// update combo box - /// if name is passed, the according element will be selected - void Update(const QString &name = ""); - private: - /// - /// d pointer declaration (holds members) - QmitkPythonSnippetsData* d; -}; - - - - -#endif // _QmitkPythonSnippets_H_INCLUDED - diff --git a/Modules/QtPython/QmitkPythonSnippets.ui b/Modules/QtPython/QmitkPythonSnippets.ui deleted file mode 100644 index f7bc574d07..0000000000 --- a/Modules/QtPython/QmitkPythonSnippets.ui +++ /dev/null @@ -1,116 +0,0 @@ - - - QmitkPythonSnippets - - - - 0 - 0 - 613 - 436 - - - - - 0 - 0 - - - - true - - - QmitkTemplate - - - - - - Name: - - - - - - - true - - - - - - - Content: - - - - - - - - - - - :/mitkPython/edit-paste.png:/mitkPython/edit-paste.png - - - Paste snippet! - - - Push button to paste the snippet into the console or the editor. Or double click on the snippet text window. - - - - - - :/mitkPython/edit-delete.png:/mitkPython/edit-delete.png - - - Remove snippet - - - Remove the selected snippet. - - - - - - :/mitkPython/edit-find-replace.png:/mitkPython/edit-find-replace.png - - - Rename snippet - - - Rename the selected snippet. - - - - - - :/mitkPython/document-new.png:/mitkPython/document-new.png - - - Add snippet - - - Add a new snippet to the list. - - - - - - :/mitkPython/edit-clear.png:/mitkPython/edit-clear.png - - - Restore default snippets - - - Clear and restore the default snippets. - - - - - - - - diff --git a/Modules/QtPython/QmitkPythonTextEditor.cpp b/Modules/QtPython/QmitkPythonTextEditor.cpp deleted file mode 100644 index 29de17ca46..0000000000 --- a/Modules/QtPython/QmitkPythonTextEditor.cpp +++ /dev/null @@ -1,185 +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 "QmitkPythonTextEditor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "QmitkPythonScriptEditorHighlighter.h" - -struct QmitkPythonTextEditorData -{ - QString m_FilePath; - - QAction* m_LoadScript; - QAction* m_SaveScript; - QAction* m_RunScript; - QToolBar* m_Toolbar; - - QTextEdit* m_Content; - - QGridLayout* m_Layout; - mitk::IPythonService* m_PythonService; - us::ServiceReference m_PythonServiceRef; - - QString m_FileName; -}; - -QmitkPythonTextEditor::QmitkPythonTextEditor(QWidget *parent) - :QWidget(parent), d(new QmitkPythonTextEditorData) -{ - us::ModuleContext* context = us::GetModuleContext(); - d->m_PythonServiceRef = context->GetServiceReference(); - d->m_PythonService = context->GetService( d->m_PythonServiceRef ); - - d->m_LoadScript = new QAction(this); - d->m_LoadScript->setToolTip("Load script from disk."); - d->m_LoadScript->setObjectName(QString::fromUtf8("LoadScript")); - QIcon icon2; - icon2.addFile(QString::fromUtf8(":/mitkPython/document-open.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_LoadScript->setIcon(icon2); - - d->m_SaveScript = new QAction(this); - d->m_SaveScript->setToolTip("Save script to disk."); - d->m_SaveScript->setObjectName(QString::fromUtf8("SaveScript")); - QIcon icon3; - icon3.addFile(QString::fromUtf8(":/mitkPython/document-save.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_SaveScript->setIcon(icon3); - - d->m_RunScript = new QAction(this); - d->m_RunScript->setToolTip("Run the current script."); - d->m_RunScript->setObjectName(QString::fromUtf8("RunScript")); - QIcon icon4; - icon4.addFile(QString::fromUtf8(":/mitkPython/media-playback-start.png"), QSize(), QIcon::Normal, QIcon::Off); - d->m_RunScript->setIcon(icon4); - - d->m_Toolbar = new QToolBar; - d->m_Toolbar->addAction( d->m_LoadScript ); - d->m_Toolbar->addAction( d->m_SaveScript ); - d->m_Toolbar->addAction( d->m_RunScript ); - - d->m_Content = new QTextEdit(this); - d->m_Content->setObjectName(QString::fromUtf8("Content")); - - new QmitkPythonScriptEditorHighlighter(d->m_Content->document()); - - d->m_Layout = new QGridLayout; - d->m_Layout->addWidget( d->m_Toolbar, 0, 0, 1, 1 ); - d->m_Layout->addWidget( d->m_Content, 1, 0, 1, 1 ); - d->m_Layout->setContentsMargins(2,2,2,2); - - this->setLayout(d->m_Layout); - QMetaObject::connectSlotsByName(this); -} - -QmitkPythonTextEditor::~QmitkPythonTextEditor() -{ - us::ModuleContext* context = us::GetModuleContext(); - context->UngetService( d->m_PythonServiceRef ); - - delete d; -} - -void QmitkPythonTextEditor::dragEnterEvent(QDragEnterEvent *event) -{ - event->accept(); -} - -void QmitkPythonTextEditor::dropEvent(QDropEvent *event) -{ - QList urls = event->mimeData()->urls(); - for(int i = 0; i < urls.size(); i++) - { - this->Paste( urls[i].toString() ); - } -} -/* -bool QmitkPythonTextEditor::canInsertFromMimeData( const QMimeData * ) const -{ - return true; -} -*/ - -void QmitkPythonTextEditor::Paste(const QString &command) -{ - if( this->isVisible() ) - { - d->m_Content->insertPlainText(command + "\n"); - } -} - - -QString QmitkPythonTextEditor::ReadFile(const QString& filename) -{ - QFile file(filename); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - MITK_ERROR << "Could not open file " << filename.toStdString(); - return nullptr; - } - - QByteArray total; - QByteArray line; - while (!file.atEnd()) - { - line = file.read(1024); - total.append(line); - } - - return QString(total); -} - -void QmitkPythonTextEditor::on_SaveScript_triggered( bool ) -{ - d->m_FileName = QFileDialog::getSaveFileName(this,tr("Save File"), d->m_FileName,tr("*.py")); - if( d->m_FileName.compare("") != 0) - { - std::ofstream myfile; - myfile.open(d->m_FileName.toLocal8Bit().data()); - myfile << d->m_Content->toPlainText().toLocal8Bit().data(); - myfile.close(); - } -} - -void QmitkPythonTextEditor::on_LoadScript_triggered( bool ) -{ - d->m_FileName = QFileDialog::getOpenFileName( this, "Load Script", d->m_FileName, tr("*.py")); - if( !d->m_FileName.isEmpty() ) - { - QString contents = this->ReadFile( d->m_FileName ); - d->m_Content->setText(contents); - } -} - -void QmitkPythonTextEditor::on_RunScript_triggered( bool ) -{ - if( !d->m_PythonService ) - { - MITK_ERROR << "Python service not available."; - return; - } - - d->m_PythonService->Execute( d->m_Content->toPlainText().toStdString(), mitk::IPythonService::MULTI_LINE_COMMAND ); -} diff --git a/Modules/QtPython/QmitkPythonTextEditor.h b/Modules/QtPython/QmitkPythonTextEditor.h deleted file mode 100644 index 2c34734200..0000000000 --- a/Modules/QtPython/QmitkPythonTextEditor.h +++ /dev/null @@ -1,49 +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 QMITKPYTHONTEXTEDITOR_H_ -#define QMITKPYTHONTEXTEDITOR_H_ - -#include -#include -#include -#include -struct QmitkPythonTextEditorData; - -/// -/// this is a python text editor with syntax highlightning -class MITKQTPYTHON_EXPORT QmitkPythonTextEditor : public QWidget -{ - Q_OBJECT - -public: - QmitkPythonTextEditor(QWidget *parent = nullptr); - ~QmitkPythonTextEditor() override; -public slots: - void Paste(const QString& command); - -protected slots: - void on_SaveScript_triggered(bool checked=false); - void on_LoadScript_triggered(bool checked=false); - void on_RunScript_triggered(bool checked=false); - -protected: - void dragEnterEvent(QDragEnterEvent *event) override; - void dropEvent(QDropEvent *event) override; - //bool canInsertFromMimeData( const QMimeData *source ) const; - QString ReadFile(const QString &filename); - -private: - QmitkPythonTextEditorData* d; -}; - -#endif diff --git a/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp b/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp deleted file mode 100755 index dfd18a0a43..0000000000 --- a/Modules/QtPython/QmitkPythonVariableStackTableModel.cpp +++ /dev/null @@ -1,214 +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 "QmitkPythonVariableStackTableModel.h" -#include -#include -#include -#include -#include -#include -#include "QmitkMimeTypes.h" - -const QString QmitkPythonVariableStackTableModel::MITK_IMAGE_VAR_NAME = "mitkImage"; -const QString QmitkPythonVariableStackTableModel::MITK_SURFACE_VAR_NAME = "mitkSurface"; - -QmitkPythonVariableStackTableModel::QmitkPythonVariableStackTableModel(QObject *parent) - :QAbstractTableModel(parent) -{ - us::ModuleContext* context = us::GetModuleContext(); - m_PythonServiceRef = context->GetServiceReference(); - m_PythonService = context->GetService(m_PythonServiceRef); - m_PythonService->AddPythonCommandObserver( this ); -} - -QmitkPythonVariableStackTableModel::~QmitkPythonVariableStackTableModel() -{ - us::ModuleContext* context = us::GetModuleContext(); - context->UngetService( m_PythonServiceRef ); - m_PythonService->RemovePythonCommandObserver( this ); -} - -bool QmitkPythonVariableStackTableModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int, int, const QModelIndex &) -{ - // Early exit, returning true, but not actually doing anything (ignoring data). - if (action == Qt::IgnoreAction) - return true; - - // Note, we are returning true if we handled it, and false otherwise - bool returnValue = false; - - if(data->hasFormat(QmitkMimeTypes::DataNodePtrs)) - { - returnValue = true; - - int i = 0; - QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); - mitk::DataNode* node = nullptr; - foreach(node, dataNodeList) - { - mitk::Image* mitkImage = dynamic_cast(node->GetData()); - - QRegExp rx("^\\d"); - QString varName(node->GetName().c_str()); - // regex replace every character that is not allowed in a python variable - varName = varName.replace(QRegExp("[.\\+\\-*\\s\\/\\n\\t\\r]"),QString("_")); - - if( mitkImage ) - { - if ( varName.isEmpty() ) - varName = MITK_IMAGE_VAR_NAME; - if ( rx.indexIn(varName) == 0) - varName.prepend("_").prepend(MITK_IMAGE_VAR_NAME); - - if( i > 0 ) - varName = QString("%1%2").arg(varName).arg(i); - - bool exportAsCvImage = mitkImage->GetDimension() == 2 && m_PythonService->IsOpenCvPythonWrappingAvailable(); - - if( exportAsCvImage ) - { - int ret = QMessageBox::question(nullptr, "Export option", - "2D image detected. Export as OpenCV image to Python instead of an SimpleITK image?", - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - exportAsCvImage = ret == QMessageBox::Yes; - if(exportAsCvImage) - { - m_PythonService->CopyToPythonAsCvImage( mitkImage, varName.toStdString() ); - ++i; - } - } - if( !exportAsCvImage ) - { - if( m_PythonService->IsSimpleItkPythonWrappingAvailable() ) - { - m_PythonService->CopyToPythonAsSimpleItkImage( mitkImage, varName.toStdString() ); - ++i; - } - else - { - MITK_ERROR << "SimpleITK Python wrapping not available. Skipping export for image " << node->GetName(); - } - } - } - else - { - mitk::Surface* surface = dynamic_cast(node->GetData()); - - if( surface ) - { - if (varName.isEmpty() ) - varName = MITK_SURFACE_VAR_NAME; - if ( rx.indexIn(varName) == 0) - varName.prepend("_").prepend(MITK_SURFACE_VAR_NAME); - - if( m_PythonService->IsVtkPythonWrappingAvailable() ) - { - m_PythonService->CopyToPythonAsVtkPolyData( surface, varName.toStdString() ); - } - else - { - MITK_ERROR << "VTK Python wrapping not available. Skipping export for surface " << node->GetName(); - } - } - } - } - } - return returnValue; -} - -QVariant QmitkPythonVariableStackTableModel::headerData(int section, Qt::Orientation orientation, - int role) const -{ - QVariant headerData; - - // show only horizontal header - if ( role == Qt::DisplayRole ) - { - if( orientation == Qt::Horizontal ) - { - // first column: "Attribute" - if(section == 0) - headerData = "Attribute"; - else if(section == 1) - headerData = "Type"; - else if(section == 2) - headerData = "Value"; - } - } - - return headerData; -} - -Qt::ItemFlags QmitkPythonVariableStackTableModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = QAbstractItemModel::flags(index); - - if(index.isValid()) - return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | flags; - else - return Qt::ItemIsDropEnabled | flags; -} - -int QmitkPythonVariableStackTableModel::rowCount(const QModelIndex &) const -{ - return m_VariableStack.size(); -} - -int QmitkPythonVariableStackTableModel::columnCount(const QModelIndex &) const -{ - return 3; -} - -QVariant QmitkPythonVariableStackTableModel::data(const QModelIndex &index, int role) const -{ - if (index.isValid() && !m_VariableStack.empty()) - { - if(role == Qt::DisplayRole) - { - mitk::PythonVariable item = m_VariableStack.at(index.row()); - if(index.column() == 0) - return QString::fromStdString(item.m_Name); - if(index.column() == 1) - return QString::fromStdString(item.m_Type); - if(index.column() == 2) - return QString::fromStdString(item.m_Value); - } - } - return QVariant(); -} - -QStringList QmitkPythonVariableStackTableModel::mimeTypes() const -{ - return QAbstractTableModel::mimeTypes(); - QStringList types; - types << "application/x-mitk-datanodes"; - types << "application/x-qabstractitemmodeldatalist"; - return types; -} - -Qt::DropActions QmitkPythonVariableStackTableModel::supportedDropActions() const -{ - return Qt::CopyAction | Qt::MoveAction; -} - -void QmitkPythonVariableStackTableModel::CommandExecuted(const std::string&) -{ - m_VariableStack = m_PythonService->GetVariableStack(); - QAbstractTableModel::beginResetModel(); - QAbstractTableModel::endResetModel(); -} - -std::vector QmitkPythonVariableStackTableModel::GetVariableStack() const -{ - return m_VariableStack; -} diff --git a/Modules/QtPython/QmitkPythonVariableStackTableModel.h b/Modules/QtPython/QmitkPythonVariableStackTableModel.h deleted file mode 100755 index a9e8ac748f..0000000000 --- a/Modules/QtPython/QmitkPythonVariableStackTableModel.h +++ /dev/null @@ -1,59 +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 QmitkPythonVariableStackTableModel_h -#define QmitkPythonVariableStackTableModel_h - -#include -#include -#include -#include "mitkIPythonService.h" -#include -#include - -/// -/// implements a table model to show the variables of the Python "__main__" dictionary -/// furthermore implements dragging and dropping of datanodes (conversion from and to python) -/// -class MITKQTPYTHON_EXPORT QmitkPythonVariableStackTableModel : public QAbstractTableModel, public mitk::PythonCommandObserver -{ - Q_OBJECT - -public: - static const QString MITK_IMAGE_VAR_NAME; - static const QString MITK_SURFACE_VAR_NAME; - - QmitkPythonVariableStackTableModel(QObject *parent = nullptr); - ~QmitkPythonVariableStackTableModel() override; - - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - Qt::ItemFlags flags( const QModelIndex& index ) const override; - QVariant headerData(int section, Qt::Orientation orientation, - int role) const override; - - QStringList mimeTypes() const override; - bool dropMimeData ( const QMimeData *, Qt::DropAction, int, int, const QModelIndex & ) override; - Qt::DropActions supportedDropActions() const override; - //Qt::DropActions supportedDragActions() const; - - void CommandExecuted(const std::string& pythonCommand) override; - - std::vector GetVariableStack() const; -private: - std::vector m_VariableStack; - mitk::IPythonService* m_PythonService; - us::ServiceReference m_PythonServiceRef; -}; - -#endif // QmitkPythonVariableStackTableModel_h diff --git a/Modules/QtPython/QmitkPythonVariableStackTableView.cpp b/Modules/QtPython/QmitkPythonVariableStackTableView.cpp deleted file mode 100755 index 4d3ddc392a..0000000000 --- a/Modules/QtPython/QmitkPythonVariableStackTableView.cpp +++ /dev/null @@ -1,112 +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 "QmitkPythonVariableStackTableView.h" -#include -#include -#include -#include -#include -#include - -QmitkPythonVariableStackTableView::QmitkPythonVariableStackTableView(QWidget *parent) - :QTableView(parent) -{ - m_TableModel = new QmitkPythonVariableStackTableModel(parent); - m_TableModel->CommandExecuted(""); - - this->setSelectionBehavior( QAbstractItemView::SelectRows ); - this->setAlternatingRowColors(true); - this->setDropIndicatorShown(true); - this->setAcceptDrops(true); - this->setModel( m_TableModel ); - - us::ModuleContext* context = us::GetModuleContext(); - us::ServiceReference serviceRef = context->GetServiceReference(); - m_PythonService = context->GetService(serviceRef); - - connect( this, SIGNAL(doubleClicked ( const QModelIndex& )), this, SLOT( OnVariableStackDoubleClicked(const QModelIndex&) ) ); -} - -QmitkPythonVariableStackTableView::~QmitkPythonVariableStackTableView() -{ -} - -void QmitkPythonVariableStackTableView::SetDataStorage(mitk::DataStorage *_DataStorage) -{ - m_DataStorage = _DataStorage; -} - -void QmitkPythonVariableStackTableView::OnVariableStackDoubleClicked(const QModelIndex &index) -{ - if( m_DataStorage.IsNull() || m_PythonService == nullptr ) - { - MITK_ERROR << "QmitkPythonVariableStackTableView not configured correctly. Quit"; - return; - } - - int row = index.row(); - std::vector variableStack = m_TableModel->GetVariableStack(); - { - MITK_DEBUG("QmitkPythonVariableStackTableView") << "row " << row; - MITK_DEBUG("QmitkPythonVariableStackTableView") << "variableStack.size(): " << variableStack.size(); - } - - QString varName = QString::fromStdString( variableStack.at(row).m_Name ); - QString type = QString::fromStdString( variableStack.at(row).m_Type ); - QString value = QString::fromStdString( variableStack.at(row).m_Value ); - - { - MITK_DEBUG("QmitkPythonVariableStackTableView") << "varName: " << varName.toStdString(); - MITK_DEBUG("QmitkPythonVariableStackTableView") << "type: " << type.toStdString(); - } - - mitk::Image::Pointer mitkImage; - mitk::Surface::Pointer mitkSurface; - - if( type.startsWith("Image") ) - { - mitkImage = m_PythonService->CopySimpleItkImageFromPython(varName.toStdString()); - } - else if( type.startsWith("numpy.ndarray") ) - { - mitkImage = m_PythonService->CopyCvImageFromPython(varName.toStdString()); - } - else if( value.startsWith("(vtkCommonDataModelPython.vtkPolyData)") ) - { - mitkSurface = m_PythonService->CopyVtkPolyDataFromPython(varName.toStdString()); - } - - std::string nodeName = varName.toStdString(); - mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(nodeName); - - // only create data node if it does not exist - if ( node.IsNull() ) - { - node = mitk::DataNode::New(); - node->SetName ( nodeName ); - m_DataStorage->Add(node); - } - - if( mitkImage.IsNotNull() ) - { - node->SetData( mitkImage ); - } - else if( mitkSurface.IsNotNull() ) - { - node->SetData( mitkSurface ); - // init renderwindow geometry - mitk::RenderingManager::GetInstance()->InitializeViews(mitkSurface->GetGeometry()); - } - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} diff --git a/Modules/QtPython/QmitkPythonVariableStackTableView.h b/Modules/QtPython/QmitkPythonVariableStackTableView.h deleted file mode 100755 index 3754279bbf..0000000000 --- a/Modules/QtPython/QmitkPythonVariableStackTableView.h +++ /dev/null @@ -1,46 +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 QmitkPythonVariableStackTableView_h -#define QmitkPythonVariableStackTableView_h - -#include -#include -#include "QmitkPythonVariableStackTableModel.h" -#include -#include - -/// -/// implements the table view for the variable stack -/// purpose of this class: 1. Setup the view correctly, 2. Implement the double click to write back results -/// to the datastorage -/// -class MITKQTPYTHON_EXPORT QmitkPythonVariableStackTableView : public QTableView -{ - Q_OBJECT - -public: - QmitkPythonVariableStackTableView(QWidget *parent = nullptr); - ~QmitkPythonVariableStackTableView() override; - - void SetDataStorage(mitk::DataStorage* _DataStorage); - -protected slots: - void OnVariableStackDoubleClicked(const QModelIndex &index); - -private: - QmitkPythonVariableStackTableModel* m_TableModel; - mitk::DataStorage::Pointer m_DataStorage; - mitk::IPythonService* m_PythonService; -}; - -#endif // QmitkPythonVariableStackTableView_h diff --git a/Modules/QtPython/Testing/CMakeLists.txt b/Modules/QtPython/Testing/CMakeLists.txt deleted file mode 100644 index e9cde47bc8..0000000000 --- a/Modules/QtPython/Testing/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -set(package_deps PACKAGE_DEPENDS PRIVATE) - -MITK_CREATE_MODULE_TESTS(${package_deps}) - -if(UNIX AND NOT APPLE) - #[[ The PythonQt library (dependency of MitkQtPython module) depends on Qt - libraries without absolute paths. Use LD_LIBRARY_PATH as workaround. - See T26955. ]] - if(TARGET ${TESTDRIVER}) - get_target_property(ld_library_path Qt5::Core IMPORTED_LOCATION_RELEASE) - get_filename_component(ld_library_path "${ld_library_path}" DIRECTORY) - - add_test( - NAME mitkPythonTest - COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${ld_library_path}" - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPythonTest - ) - endif() -endif() diff --git a/Modules/QtPython/Testing/files.cmake b/Modules/QtPython/Testing/files.cmake deleted file mode 100644 index 2be97879a7..0000000000 --- a/Modules/QtPython/Testing/files.cmake +++ /dev/null @@ -1,10 +0,0 @@ -if(UNIX AND NOT APPLE) - # See T26955. - set(MODULE_CUSTOM_TESTS - mitkPythonTest.cpp - ) -else() - set(MODULE_TESTS - mitkPythonTest.cpp - ) -endif() diff --git a/Modules/QtPython/Testing/mitkPythonTest.cpp b/Modules/QtPython/Testing/mitkPythonTest.cpp deleted file mode 100644 index 762a8f3a18..0000000000 --- a/Modules/QtPython/Testing/mitkPythonTest.cpp +++ /dev/null @@ -1,43 +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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class mitkPythonTestSuite : public mitk::TestFixture -{ - CPPUNIT_TEST_SUITE(mitkPythonTestSuite); - MITK_TEST(TestPython); - CPPUNIT_TEST_SUITE_END(); - -public: - - void TestPython() - { - us::ModuleContext* context = us::GetModuleContext(); - us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); - mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); - mitk::IPythonService::ForceLoadModule(); - - std::string result = m_PythonService->Execute( "5+5", mitk::IPythonService::EVAL_COMMAND ); - MITK_TEST_CONDITION( result == "10", "Testing if running python code 5+5 results in 10" ); - } -}; - -MITK_TEST_SUITE_REGISTRATION(mitkPython) diff --git a/Modules/QtPython/files.cmake b/Modules/QtPython/files.cmake deleted file mode 100644 index b2aa0226dc..0000000000 --- a/Modules/QtPython/files.cmake +++ /dev/null @@ -1,25 +0,0 @@ -SET(CPP_FILES - QmitkCtkPythonShell.cpp - QmitkPythonVariableStackTableModel.cpp - QmitkPythonVariableStackTableView.cpp - QmitkPythonScriptEditorHighlighter.cpp - QmitkPythonTextEditor.cpp - QmitkPythonSnippets.cpp -) - -#SET(UI_FILES -# QmitkPythonSnippets.ui -#) - -SET(MOC_H_FILES - QmitkCtkPythonShell.h - QmitkPythonVariableStackTableModel.h - QmitkPythonVariableStackTableView.h - QmitkPythonScriptEditorHighlighter.h - QmitkPythonTextEditor.h - QmitkPythonSnippets.h -) - -set(QRC_FILES - resources/mitkPython.qrc -) diff --git a/Modules/QtPython/resources/PythonSnippets.xml b/Modules/QtPython/resources/PythonSnippets.xml deleted file mode 100644 index 7e8a1bcb5d..0000000000 --- a/Modules/QtPython/resources/PythonSnippets.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/Modules/QtPython/resources/document-new.png b/Modules/QtPython/resources/document-new.png deleted file mode 100644 index fe0808b96a..0000000000 Binary files a/Modules/QtPython/resources/document-new.png and /dev/null differ diff --git a/Modules/QtPython/resources/document-open.png b/Modules/QtPython/resources/document-open.png deleted file mode 100644 index d07347689e..0000000000 Binary files a/Modules/QtPython/resources/document-open.png and /dev/null differ diff --git a/Modules/QtPython/resources/document-save.png b/Modules/QtPython/resources/document-save.png deleted file mode 100644 index 26f6689e44..0000000000 Binary files a/Modules/QtPython/resources/document-save.png and /dev/null differ diff --git a/Modules/QtPython/resources/edit-clear.png b/Modules/QtPython/resources/edit-clear.png deleted file mode 100644 index a316e45b08..0000000000 Binary files a/Modules/QtPython/resources/edit-clear.png and /dev/null differ diff --git a/Modules/QtPython/resources/edit-delete.png b/Modules/QtPython/resources/edit-delete.png deleted file mode 100644 index 3c09637cd2..0000000000 Binary files a/Modules/QtPython/resources/edit-delete.png and /dev/null differ diff --git a/Modules/QtPython/resources/edit-find-replace.png b/Modules/QtPython/resources/edit-find-replace.png deleted file mode 100644 index 575e6feac9..0000000000 Binary files a/Modules/QtPython/resources/edit-find-replace.png and /dev/null differ diff --git a/Modules/QtPython/resources/edit-paste.png b/Modules/QtPython/resources/edit-paste.png deleted file mode 100644 index 911ed85b5a..0000000000 Binary files a/Modules/QtPython/resources/edit-paste.png and /dev/null differ diff --git a/Modules/QtPython/resources/media-playback-start.png b/Modules/QtPython/resources/media-playback-start.png deleted file mode 100644 index fbe68ea24f..0000000000 Binary files a/Modules/QtPython/resources/media-playback-start.png and /dev/null differ diff --git a/Modules/QtPython/resources/mitkPython.qrc b/Modules/QtPython/resources/mitkPython.qrc deleted file mode 100644 index 55d4c94e13..0000000000 --- a/Modules/QtPython/resources/mitkPython.qrc +++ /dev/null @@ -1,13 +0,0 @@ - - - document-new.png - document-open.png - document-save.png - edit-delete.png - edit-paste.png - edit-find-replace.png - edit-clear.png - media-playback-start.png - PythonSnippets.xml - - diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 8b336a0d7e..8e3b7eaee7 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,89 +1,89 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.mitkworkbench.intro:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.mxnmultiwidgeteditor:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.chartExample:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicombrowser:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF - org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.deformableclippingplane:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.semanticrelations:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.ultrasoundtrackingnavigation:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.radiomics:OFF org.mitk.gui.qt.cest:OFF org.mitk.gui.qt.fit.demo:OFF org.mitk.gui.qt.fit.inspector:OFF org.mitk.gui.qt.fit.genericfitting:OFF org.mitk.gui.qt.pharmacokinetics.mri:OFF org.mitk.gui.qt.pharmacokinetics.pet:OFF org.mitk.gui.qt.pharmacokinetics.simulation:OFF org.mitk.gui.qt.pharmacokinetics.curvedescriptor:OFF org.mitk.gui.qt.pharmacokinetics.concentration.mri:OFF org.mitk.gui.qt.flowapplication:OFF org.mitk.gui.qt.flow.segmentation:OFF org.mitk.gui.qt.pixelvalue:ON + org.mitk.deeplearningsegmentation:ON ) diff --git a/Plugins/org.mitk.deeplearningsegmentation/CMakeLists.txt b/Plugins/org.mitk.deeplearningsegmentation/CMakeLists.txt new file mode 100644 index 0000000000..5bf3202538 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_deeplearningsegmentation) + +mitk_create_plugin( + EXPORT_DIRECTIVE DEEPLEARNINGSEGMENTATION_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkDeepLearningSegmentation +) diff --git a/Plugins/org.mitk.deeplearningsegmentation/files.cmake b/Plugins/org.mitk.deeplearningsegmentation/files.cmake new file mode 100644 index 0000000000..f3e021926c --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/files.cmake @@ -0,0 +1,40 @@ +set(INTERNAL_CPP_FILES + org_mitk_deeplearningsegmentation_Activator.cpp + DeepLearningSegmentationGUI.cpp + SegmentationWorker.cpp + SegmentationResultHandler.cpp +) + +set(UI_FILES + src/internal/DeepLearningSegmentationGUI.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_deeplearningsegmentation_Activator.h + src/internal/DeepLearningSegmentationGUI.h + src/internal/SegmentationWorker.h + src/internal/SegmentationResultHandler.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.deeplearningsegmentation/manifest_headers.cmake b/Plugins/org.mitk.deeplearningsegmentation/manifest_headers.cmake new file mode 100644 index 0000000000..901746905f --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/manifest_headers.cmake @@ -0,0 +1,7 @@ +set(Plugin-Name "DeepLearningsegmentation") +set(Plugin-Version "0.1") +set(Plugin-Vendor "German Cancer Research Center (DKFZ)") +set(Plugin-ContactAddress "") +set(Require-Plugin org.mitk.gui.qt.common) +set(Plugin-ActivationPolicy "eager") + diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp new file mode 100644 index 0000000000..f00c719774 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.cpp @@ -0,0 +1,123 @@ +/*============================================================================ + +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 "DeepLearningSegmentationGUI.h" +#include +#include +#include"SegmentationResultHandler.h" + +DeepLearningSegmentationGUI::DeepLearningSegmentationGUI() + : m_Ui(new Ui::DeepLearningSegmentationGUI) +{ + //register Meta types which is necessary for the qt signals/slots with those classes as parameter + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType>(); + + qRegisterMetaType>(); + + //set up the ui + m_Ui->setupUi(this); + + //connect the UI elements in signals/slots + connect(m_Ui->buttonPerformImageProcessing, &QPushButton::clicked, this, &DeepLearningSegmentationGUI::OnDoSegmentation); + connect(m_Ui->buttonLoadTrainedNetwork, &QPushButton::clicked, this, &DeepLearningSegmentationGUI::DoLoadTrainedNet); + m_Ui->buttonPerformImageProcessing->setEnabled(false); + + //create a new worker thread to execute some functions in a seperate thread + m_SegmentationThread = new QThread; + m_Worker = new SegmentationWorker; + m_Worker->moveToThread(m_SegmentationThread); + + // Signal/Slot connects between worker thread and GUI + connect(this, &DeepLearningSegmentationGUI::Operate, m_Worker, &SegmentationWorker::DoWork); + connect(this, &DeepLearningSegmentationGUI::Wait, m_Worker, &SegmentationWorker::WaitForSegmentationToFinish); + connect(m_Worker, &SegmentationWorker::Finished, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::FinishedMultilabel, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::Failed, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + connect(m_Worker, &SegmentationWorker::PreviousSegmentationFinished, this, &DeepLearningSegmentationGUI::DoSegmentationProcessFinished); + + connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); + connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(SetUpUI())); +} + +DeepLearningSegmentationGUI::~DeepLearningSegmentationGUI() { +} + +void DeepLearningSegmentationGUI::SetUpUI() +{ + // Disable buttons if a segmentation is already running + if (m_SegTool->IsSegmentationRunning()) + { + this->SegmentationRunning(); + m_SegmentationThread->start(); + emit Wait(m_SegTool); + } +} + +void DeepLearningSegmentationGUI::DoLoadTrainedNet() +{ + //Open a file dialog to select a trained network + QString tempPath = QString::fromStdString(mitk::IOUtil::GetTempPath()); + QString pretrainedNetResourcesPath = + QFileDialog::getOpenFileName(nullptr, tr("Open File"), tempPath, tr("Images (*.pth.tar)")); + + //set the trained network + m_TrainedNet = pretrainedNetResourcesPath; + + //enable segmentation + if (m_TrainedNet != "") + { + m_Ui->labelWarning->setVisible(false); + m_Ui->buttonPerformImageProcessing->setEnabled(true); + } +} + +void DeepLearningSegmentationGUI::OnDoSegmentation() +{ + MITK_INFO << "[Start] Segmentation"; + //adapt gui to show that segmentation is running + this->SegmentationRunning(); + + SegmentationResultHandler *resultSetter = new SegmentationResultHandler; + if (!m_SegmentationThread->isRunning()) + { + m_SegmentationThread->start(); + } + //start segmentation in worker thread + emit Operate(m_SegTool, resultSetter, m_TrainedNet); +} + +void DeepLearningSegmentationGUI::SegmentationRunning() +{ + m_Ui->labelWarning->setText("Segmentation running. This might take a while."); + m_Ui->labelWarning->setVisible(true); + m_Ui->buttonLoadTrainedNetwork->setEnabled(false); + m_Ui->buttonPerformImageProcessing->setEnabled(false); +} + +void DeepLearningSegmentationGUI::DoSegmentationProcessFinished() +{ + m_Ui->buttonLoadTrainedNetwork->setEnabled(true); + if (m_TrainedNet == "") + { + m_Ui->labelWarning->setText("Please load a network!"); + m_Ui->labelWarning->setVisible(true); + m_Ui->buttonPerformImageProcessing->setEnabled(false); + } + else + { + m_Ui->labelWarning->setVisible(false); + m_Ui->buttonPerformImageProcessing->setEnabled(true); + } +} + diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h new file mode 100644 index 0000000000..8e61027142 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.h @@ -0,0 +1,103 @@ +/*============================================================================ + +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 DeepLearningSegmentationGUI_h +#define DeepLearningSegmentationGUI_h + +#include +#include "ui_DeepLearningSegmentationGUI.h" +#include +#include "DeepLearningSegmentationTool.h" +#include +#include"SegmentationWorker.h" + +namespace Ui { +class DeepLearningSegmentationGUI; +} + +/** + * @class DeepLearningSegmentationGUI + * @brief This is the base class for all GUIs of Deep Learning Based Segmentations + */ +class DEEPLEARNINGSEGMENTATION_EXPORT DeepLearningSegmentationGUI : public QmitkToolGUI +{ + Q_OBJECT + +public: + /** + * @brief Constructor. Mainly for setting UI up and connect some signals and slots + * icon resource. + */ + DeepLearningSegmentationGUI(); + ~DeepLearningSegmentationGUI() override; + + /** + * @brief Adapt the gui (e.g. deactivate buttons) if a segmentation is running. + */ + void SegmentationRunning(); + +signals: + + /** + * @brief signal for starting the segmentation which is caught by a worker thread. + * + * @param tool the Segmentation Tool for running the segmentation + * @param guiSetter the result handler which displays the result in the UI after the segmentation + * @param networkPath the path to the trained network which is needed for the segmentation + */ + void Operate(mitk::DeepLearningSegmentationTool* tool, SegmentationResultHandler* guiSetter, QString networkPath); + /** + * @brief if a segmentation is executed when the tool is started, emit a signal for waiting in the worker thread. + * + * @param tool the Segmentation Tool to check in worker, if the segmentation is still running. + */ + void Wait(mitk::DeepLearningSegmentationTool *tool); + + protected slots: + /** + * @brief set up the UI depending on whether a segmentation is running + */ + virtual void SetUpUI(); + /** + * @brief start the segmentation by emitting a operate signal which is caught by a worker thread. + * Called when the "Run Segmentation" button is pressed. + */ + virtual void OnDoSegmentation(); + /** + * @brief set m_TrainedNetwork after a File Dialog is appearing to select a trained network. + * Called when the "Load trained network" button is pressed. + */ + void DoLoadTrainedNet(); + /** + * @brief Set the segmentation method m_SegTool. + * This method has to be overwritten by every individual segmentation method to set the correct segmentation tool. + */ + virtual void OnNewToolAssociated(mitk::Tool *) = 0; + /** + * @brief set up the UI if a segmentation is finished + */ + void DoSegmentationProcessFinished(); + + protected: + mitk::DeepLearningSegmentationTool* m_SegTool; + QScopedPointer m_Ui; + QString m_TrainedNet; + + private: + + QThread *m_SegmentationThread; + SegmentationWorker *m_Worker; + +}; + +#endif // DeepLearningSegmentationGUI_h diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui new file mode 100644 index 0000000000..69964a1f52 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/DeepLearningSegmentationGUI.ui @@ -0,0 +1,55 @@ + + + DeepLearningSegmentationGUI + + + + 0 + 0 + 222 + 96 + + + + + 0 + 0 + + + + QmitkTemplate + + + + + + QLabel { color: rgb(255, 0, 0) } + + + Please load a network! + + + + + + + Load network + + + + + + + Do image processing + + + Run Segmentation + + + + + + + + + diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp new file mode 100644 index 0000000000..420a6c50f5 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.cpp @@ -0,0 +1,68 @@ +/*============================================================================ + +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"SegmentationResultHandler.h" +#include + +SegmentationResultHandler::SegmentationResultHandler() { +} + +SegmentationResultHandler::~SegmentationResultHandler(){ +} + +void SegmentationResultHandler::SetResult(mitk::LabelSetImage::Pointer resultSegmentation, + mitk::DeepLearningSegmentationTool *segTool) +{ + try + { + //create new data node with the segmentation output as data + mitk::DataNode::Pointer outputNode = mitk::DataNode::New(); + outputNode->SetName(segTool->GetName()); + outputNode->SetData(resultSegmentation); + //add data node to data storage and update GUI + segTool->GetDataStorage()->Add(outputNode, segTool->GetReferenceData()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + catch (const mitk::Exception &e) + { + MITK_INFO << e.GetDescription(); + } +} + +void SegmentationResultHandler::SetMultilabelResult(std::vector resultSegmentation, + mitk::DeepLearningSegmentationTool *segTool) +{ + try + { int resultSegmentationSize= static_cast(resultSegmentation.size()); + for (int i = 0; iGetName()+std::to_string(i); + outputNode->SetName(name); + outputNode->SetData(resultSegmentation[i]); + // add data node to data storage and update GUI + segTool->GetDataStorage()->Add(outputNode, segTool->GetReferenceData()); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } + catch (const mitk::Exception &e) + { + MITK_INFO << e.GetDescription(); + } +} + +void SegmentationResultHandler::SegmentationProcessFailed() +{ + QMessageBox::warning(nullptr, + "Error in segmentation", + "There was an error in the segmentation process. No resulting segmentation can be loaded."); +} diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.h b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.h new file mode 100644 index 0000000000..4bb839e526 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationResultHandler.h @@ -0,0 +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 SegmentationResultHandler_h +#define SegmentationResultHandler_h + +#include +#include + +/** +* @class SegmentationResultHandler +* @brief Class which sets the result in the UI after a deep learning method is finished +*/ +class SegmentationResultHandler : public QObject +{ + Q_OBJECT +public: + SegmentationResultHandler(); + ~SegmentationResultHandler(); +public slots: + /** + * @brief display the result of the segmentation if the segmentation process was successful + * + * @param resultSegmentation the resulting segmentation from the segmentation process to display + * @param segTool the Segmentation Tool for running the segmentation + */ + void SetResult(mitk::LabelSetImage::Pointer resultSegmentation, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief display the result of the segmentation if the segmentation process was successful + * + * @param resultSegmentation the resulting segmentation from the segmentation process to display + * @param segTool the Segmentation Tool for running the segmentation + */ + void SetMultilabelResult(std::vector resultSegmentation, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief display a warning for the user if segmentation process failed + */ + void SegmentationProcessFailed(); + +signals: + +}; + +#endif diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.cpp b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.cpp new file mode 100644 index 0000000000..fda8c10be4 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.cpp @@ -0,0 +1,67 @@ +/*============================================================================ + +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"SegmentationWorker.h" + +SegmentationWorker::SegmentationWorker() +{ +} +void SegmentationWorker::DoWork(mitk::DeepLearningSegmentationTool* segTool, + SegmentationResultHandler *resultSetter, + QString networkPath) +{ + //connect signals/slots with the result setter which sets the result in the main thread afterwards + connect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + connect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + connect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + + try + { + bool multilabel = segTool->IsMultilabelSegmentation(); + //execute segmentation with segmentation tool + if (!multilabel) + { + mitk::LabelSetImage::Pointer result = segTool->DoSegmentation(networkPath.toStdString()); + MITK_INFO << "Back in Worker"; + emit Finished(result, segTool); + } + else + { + std::vector result = segTool->DoMultilabelSegmentation(networkPath.toStdString()); + MITK_INFO << "Back in Worker"; + emit FinishedMultilabel(result, segTool); + } + //disconnect from result setter. Otherwise, the result is set twice after second execution, + //three times after third execution,... + disconnect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + disconnect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + disconnect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + emit Failed(); + // disconnect from result setter. Otherwise, the result is set twice after second execution, + // three times after third execution,... + disconnect(this, &SegmentationWorker::Finished, resultSetter, &SegmentationResultHandler::SetResult); + disconnect(this, &SegmentationWorker::FinishedMultilabel, resultSetter, &SegmentationResultHandler::SetMultilabelResult); + disconnect(this, &SegmentationWorker::Failed, resultSetter, &SegmentationResultHandler::SegmentationProcessFailed); + } +} + +void SegmentationWorker::WaitForSegmentationToFinish(mitk::DeepLearningSegmentationTool *segTool) +{ + while (segTool->IsSegmentationRunning()) + { + //Wait + } + emit PreviousSegmentationFinished(); +} diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.h b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.h new file mode 100644 index 0000000000..b6c5c2c104 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/SegmentationWorker.h @@ -0,0 +1,76 @@ +/*============================================================================ + +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 SegmentationWorker_h +#define SegmentationWorker_h + +#include +#include +#include"SegmentationResultHandler.h" + +Q_DECLARE_METATYPE(mitk::DeepLearningSegmentationTool*) +Q_DECLARE_METATYPE(mitk::LabelSetImage::Pointer) +Q_DECLARE_METATYPE(std::vector) + +/** + * @class SegmentationWorker + * @brief Class to execute some functions (mainly segmentation) from the Segmentation Plugin in a seperate thread + */ +class SegmentationWorker : public QObject +{ + Q_OBJECT +public: + SegmentationWorker(); +public slots: + /** + * @brief execute segmentation with the correct segmentation tool + * + * @param segTool the Segmentation Tool for running the segmentation + * @param resultSetter the SegmentationResultHandler which sets the result in the GUI after the segmentation + * @param networkPath the path to the trained network which is needed for the segmentation + */ + void DoWork(mitk::DeepLearningSegmentationTool* segTool, + SegmentationResultHandler *resultSetter, + QString networkPath); + /** + * @brief if a segmentation is executed when the tool is started, + * wait for the segmentation to finish and emit a signal (PreviouesSegmentationFinished) afterwards. + * + * @param tool the Segmentation Tool to check, if the segmentation is still running. + */ + void WaitForSegmentationToFinish(mitk::DeepLearningSegmentationTool *segTool); + +signals: + /** + * @brief the signal emitted when a segmentation process finished successful + * + * @param result the resulting segmentation + * @param segTool the Segmentation Tool for running the segmentation + */ + void Finished(mitk::LabelSetImage::Pointer result, mitk::DeepLearningSegmentationTool* segTool); + /** + * @brief the signal emitted when a multilabel segmentation process finished successful + * + * @param result the resulting segmentation + * @param segTool the Segmentation Tool for running the segmentation + */ + void FinishedMultilabel(std::vector result, mitk::DeepLearningSegmentationTool *segTool); + /** + * @brief the signal emitted when a segmentation process failed + */ + void Failed(); + /** + * @brief the signal emitted when a segmentation, which ran when the tool was started, finished + */ + void PreviousSegmentationFinished(); +}; + +#endif diff --git a/Modules/Python/mitkIPythonService.cpp b/Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.cpp similarity index 56% copy from Modules/Python/mitkIPythonService.cpp copy to Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.cpp index e52b7bb25e..e9b45aadf1 100644 --- a/Modules/Python/mitkIPythonService.cpp +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.cpp @@ -1,25 +1,27 @@ /*============================================================================ 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 "mitkIPythonService.h" -mitk::IPythonService::~IPythonService() -{ -} +#include "org_mitk_deeplearningsegmentation_Activator.h" -std::string mitk::IPythonService::ForceLoadModule() +namespace mitk { - std::string ret = "Load python module"; - MITK_INFO << ret; - return ret; + void org_mitk_deeplearningsegmentation_Activator::start(ctkPluginContext *context) + { + Q_UNUSED(context) + } + + void org_mitk_deeplearningsegmentation_Activator::stop(ctkPluginContext *context) + { + Q_UNUSED(context) + } } - diff --git a/Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.h b/Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.h new file mode 100644 index 0000000000..06702bc139 --- /dev/null +++ b/Plugins/org.mitk.deeplearningsegmentation/src/internal/org_mitk_deeplearningsegmentation_Activator.h @@ -0,0 +1,34 @@ +/*============================================================================ + +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 org_mitk_deeplearningsegmentation_Activator_h +#define org_mitk_deeplearningsegmentation_Activator_h + +#include + +namespace mitk +{ + class org_mitk_deeplearningsegmentation_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_deeplearningsegmentation") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext *context); + void stop(ctkPluginContext *context); + + }; // org_mitk_deeplearningsegmentation_Activator +} + +#endif // org_mitk_deeplearningsegmentation_Activator_h diff --git a/Plugins/org.mitk.gui.qt.python/CMakeLists.txt b/Plugins/org.mitk.gui.qt.python/CMakeLists.txt deleted file mode 100644 index fb55d48c06..0000000000 --- a/Plugins/org.mitk.gui.qt.python/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -if(MITK_USE_Python3) - -project(org_mitk_gui_qt_python) - -mitk_create_plugin( - EXPORT_DIRECTIVE org_mitk_gui_qt_python_EXPORT - EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkPython MitkQtPython) - -endif() diff --git a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/MitkPythonPluginView.png b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/MitkPythonPluginView.png deleted file mode 100644 index 44c8d928b0..0000000000 Binary files a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/MitkPythonPluginView.png and /dev/null differ diff --git a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox b/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox deleted file mode 100644 index 73d1ecb6af..0000000000 --- a/Plugins/org.mitk.gui.qt.python/documentation/UserManual/QmitkPython.dox +++ /dev/null @@ -1,33 +0,0 @@ -/** -\page org_mitk_views_python The Python Plugin - -Available sections: - - \ref org_mitk_views_pythonOverview - - \ref org_mitk_views_pythonUsage - - \ref org_mitk_views_pythonConsole - - \ref org_mitk_views_pythonSnippets - -\section org_mitk_views_pythonOverview Overview -The Python view provides the graphical front end to run Python code through the mitkPython module. Furthermore the SimpleITK/VTK/OpenCV Python wrapping can be used. -Images and surfaces in the DataManager can be transferred via a drag & drop mechanism into the MITK Python Console. - -\section org_mitk_views_pythonUsage Transfer data -Images and surfaces can be tranferred from the data manger into the python console. To transfer an image or -surface simply drag it from the data manager into the Variable Stack view, as shown in Figure. -A new entry will appear in the Variable Stack, as soon as the data is transferred. As soon as the -entry is available the object can be accessed and modified in the python console. Three dimensional -images will be copied in-memory to python via numpy and a SimpleITK image object is created with the -same properties. When a two dimensional image is transferred the user can choose to transfer it as an OpenCV -image object. Surfaces are fully memory mapped as a vtkPolyData object. To transfer an image or surface -from the python runtime to the data manager just double click on the corresponding entry in the Variable Stack View. - -\imageMacro{MitkPythonPluginView.png,"Screenshot of the MITK Python Plugin",6} - -\section org_mitk_views_pythonConsole Console -The Python console can be used for interactive programming. All items in the data storage can be accessed -in the python console. The console can also be used to load python scripts and run them. - -\section org_mitk_views_pythonSnippets Snippets -The python plugin contains some code snippets of SimpleITK/VTK/OpenCV that can be run in the python console. -Snippets can be modified and saved by the user. -*/ diff --git a/Plugins/org.mitk.gui.qt.python/files.cmake b/Plugins/org.mitk.gui.qt.python/files.cmake deleted file mode 100644 index d2d693e932..0000000000 --- a/Plugins/org.mitk.gui.qt.python/files.cmake +++ /dev/null @@ -1,31 +0,0 @@ -set(SRC_CPP_FILES -) - -set(INTERNAL_CPP_FILES - mitkPluginActivator.cpp - QmitkPythonView.cpp -) - -set(MOC_H_FILES - src/internal/QmitkPythonView.h - src/internal/mitkPluginActivator.h -) - -set(CPP_FILES ) - -set(CACHED_RESOURCE_FILES - plugin.xml - resources/Python.png -) - -set(QRC_FILES - resources/Python.qrc -) - -foreach(file ${SRC_CPP_FILES}) - set(CPP_FILES ${CPP_FILES} src/${file}) -endforeach(file ${SRC_CPP_FILES}) - -foreach(file ${INTERNAL_CPP_FILES}) - set(CPP_FILES ${CPP_FILES} src/internal/${file}) -endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.python/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.python/manifest_headers.cmake deleted file mode 100644 index 3aaa799b06..0000000000 --- a/Plugins/org.mitk.gui.qt.python/manifest_headers.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(Plugin-Name "MITK Python") -set(Plugin-Version "1.0.0") -set(Plugin-Vendor "German Cancer Research Center (DKFZ)") -set(Plugin-ContactAddress "https://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.python/plugin.xml b/Plugins/org.mitk.gui.qt.python/plugin.xml deleted file mode 100644 index 9629c07384..0000000000 --- a/Plugins/org.mitk.gui.qt.python/plugin.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Allow the acces of python from MITK - - - - - - - - - - diff --git a/Plugins/org.mitk.gui.qt.python/resources/Python.png b/Plugins/org.mitk.gui.qt.python/resources/Python.png deleted file mode 100644 index 813e4d1b5c..0000000000 Binary files a/Plugins/org.mitk.gui.qt.python/resources/Python.png and /dev/null differ diff --git a/Plugins/org.mitk.gui.qt.python/resources/Python.qrc b/Plugins/org.mitk.gui.qt.python/resources/Python.qrc deleted file mode 100644 index 5b36d01dbf..0000000000 --- a/Plugins/org.mitk.gui.qt.python/resources/Python.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - Python.png - - diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp deleted file mode 100644 index 2f00d0aa01..0000000000 --- a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.cpp +++ /dev/null @@ -1,97 +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 "QmitkPythonView.h" -#include -#include "mitkPluginActivator.h" -#include -#include -#include - -#include -#include -#include - -const std::string QmitkPythonView::VIEW_ID = "org.mitk.views.python"; - -struct QmitkPythonViewData -{ - // widget - QmitkPythonVariableStackTableView* m_PythonVariableStackTableView; - QmitkPythonSnippets* m_PythonSnippets; - - QmitkCtkPythonShell* m_PythonShell; - QmitkPythonTextEditor* m_TextEditor; -}; - -QmitkPythonView::QmitkPythonView() - : d( new QmitkPythonViewData ) -{ - d->m_PythonVariableStackTableView = nullptr; - d->m_PythonShell = nullptr; -} - -QmitkPythonView::~QmitkPythonView() -{ - delete d; -} - -void QmitkPythonView::CreateQtPartControl(QWidget* parent) -{ - d->m_PythonVariableStackTableView = new QmitkPythonVariableStackTableView; - d->m_PythonVariableStackTableView->SetDataStorage(this->GetDataStorage()); - //d->m_PythonVariableStackTableView->horizontalHeader()->setResizeMode(QHeaderView::Interactive); - - QString snippetsFilePath = mitk::PluginActivator::m_XmlFilePath; - MITK_DEBUG("QmitkPythonView") << "got snippetsFilePath " << snippetsFilePath.toStdString(); - - d->m_PythonSnippets = new QmitkPythonSnippets(snippetsFilePath); - - MITK_DEBUG("QmitkPythonView") << "initializing varStackSnippetsTab"; - QTabWidget* varStackSnippetsTab = new QTabWidget; - varStackSnippetsTab->addTab( d->m_PythonVariableStackTableView, "Variable Stack" ); - varStackSnippetsTab->addTab( d->m_PythonSnippets, "Snippets" ); - varStackSnippetsTab->setTabPosition( QTabWidget::South ); - - MITK_DEBUG("QmitkPythonView") << "initializing m_PythonShell"; - d->m_PythonShell = new QmitkCtkPythonShell; - - MITK_DEBUG("QmitkPythonView") << "initializing m_TextEditor"; - d->m_TextEditor = new QmitkPythonTextEditor; - - MITK_DEBUG("QmitkPythonView") << "initializing tabWidgetConsoleEditor"; - QTabWidget* tabWidgetConsoleEditor = new QTabWidget; - tabWidgetConsoleEditor->addTab( d->m_PythonShell, "Console" ); - tabWidgetConsoleEditor->addTab( d->m_TextEditor, "Text Editor" ); - tabWidgetConsoleEditor->setTabPosition( QTabWidget::South ); - - QList sizes; - sizes << 1 << 3; - QSplitter* splitter = new QSplitter; - splitter->addWidget(varStackSnippetsTab); - splitter->addWidget(tabWidgetConsoleEditor); - splitter->setStretchFactor ( 0, 1 ); - splitter->setStretchFactor ( 1, 3 ); - - QGridLayout* layout = new QGridLayout; - layout->addWidget( splitter, 0, 0 ); - parent->setLayout(layout); - - MITK_DEBUG("QmitkPythonView") << "creating connections for m_PythonSnippets"; - connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_PythonShell, SLOT(Paste(QString)) ); - connect( d->m_PythonSnippets, SIGNAL(PasteCommandRequested(QString)), d->m_TextEditor, SLOT(Paste(QString)) ); -} - -void QmitkPythonView::SetFocus() -{ - d->m_PythonShell->setFocus(); -} diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h b/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h deleted file mode 100644 index 577e1f275e..0000000000 --- a/Plugins/org.mitk.gui.qt.python/src/internal/QmitkPythonView.h +++ /dev/null @@ -1,60 +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 QmitkPythonView_H_ -#define QmitkPythonView_H_ - -/// Qmitk -#include - -/// -/// d pointer forward declaration -/// -struct QmitkPythonViewData; - -/// -/// \brief New python view (CONSOLE) -/// -class QmitkPythonView : public QmitkAbstractView -{ - Q_OBJECT - -public: - - static const std::string VIEW_ID; // = "org.mitk.extapp.defaultperspective" - /// - /// \brief Standard ctor. - /// - QmitkPythonView(); - - /// - /// \brief Standard dtor. - /// - ~QmitkPythonView() override; - -protected: - - /// - /// \brief Create the view here. - /// - void CreateQtPartControl(QWidget* parent) override; - - /// - /// focus on load image - /// - void SetFocus() override; - -private: - QmitkPythonViewData* d; -}; - -#endif /*QmitkPythonView_H_*/ diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp deleted file mode 100644 index 0249049b5b..0000000000 --- a/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.cpp +++ /dev/null @@ -1,31 +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 "mitkPluginActivator.h" -#include "QmitkPythonView.h" - -namespace mitk -{ - QString PluginActivator::m_XmlFilePath; - - void PluginActivator::start(ctkPluginContext* context) - { - m_XmlFilePath = context->getDataFile("PythonSnippets.xml").absoluteFilePath(); - - BERRY_REGISTER_EXTENSION_CLASS(QmitkPythonView, context) - } - - void PluginActivator::stop(ctkPluginContext* context) - { - Q_UNUSED(context) - } -} diff --git a/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h deleted file mode 100644 index 5f499ce5c3..0000000000 --- a/Plugins/org.mitk.gui.qt.python/src/internal/mitkPluginActivator.h +++ /dev/null @@ -1,35 +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 MITKPLUGINACTIVATOR_H -#define MITKPLUGINACTIVATOR_H - -#include - -namespace mitk { - -class PluginActivator : - public QObject, public ctkPluginActivator -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_python") - Q_INTERFACES(ctkPluginActivator) - -public: - void start(ctkPluginContext* context) override; - void stop(ctkPluginContext* context) override; - - static QString m_XmlFilePath; -}; // PluginActivator - -} - -#endif // MITKPLUGINACTIVATOR_H diff --git a/Wrapping/CMakeLists.txt b/Wrapping/CMakeLists.txt index aa75bca1ba..9bf8ad48e2 100644 --- a/Wrapping/CMakeLists.txt +++ b/Wrapping/CMakeLists.txt @@ -1,71 +1,20 @@ -find_package(SWIG QUIET) - -if(SWIG_FOUND) - include(mitkLanguageOptions) +if(MITK_WRAP_PYTHON_ENABLED) include(UseSWIG) - include(mitkSwigAddLibraryDependencies) include(mitkSwigPrepareFiles) # Path to common files - set(MITK_WRAPPING_COMMON_DIR ${MITK_SOURCE_DIR}/Wrapping/Common) - # make a manual list of dependencies for the Swig.i files - list( APPEND SWIG_EXTRA_DEPS - "${MITK_WRAPPING_COMMON_DIR}/MITK_Common.i" - ) + set(MITK_WRAPPING_COMMON_DIR "${MITK_SOURCE_DIR}/Wrapping/Common") - # A general packaging target, not built by default, to build packages for each - # language. This should depend on all language specific targets. + # Make a manual list of dependencies for the Swig.i files + list(APPEND SWIG_EXTRA_DEPS + "${MITK_WRAPPING_COMMON_DIR}/mitk_swig_common.i" + ) - add_custom_target( dist ${CMAKE_COMMAND} -E echo "Finished generating wrapped packages for distribution..." ) + # A general packaging target, not built by default, to build packages for each + # language. This should depend on all language specific targets. + add_custom_target(dist ${CMAKE_COMMAND} -E echo "Finished generating wrapped packages for distribution...") set_property(TARGET dist PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Wrapping") - # - # lua SWIG configuration - # - #if ( WRAP_LUA ) - # add_subdirectory ( Lua ) - #endif() - - # - # python SWIG configuration - # - if ( WRAP_PYTHON ) - add_subdirectory ( Python ) - endif() - - # - # ruby SWIG configuration - # - #if ( WRAP_RUBY ) - # add_subdirectory ( Ruby ) - #endif() - - # - # JAVA SWIG configuration - # - #if ( WRAP_JAVA ) - # add_subdirectory( Java ) - #endif() - - # - # C# SWIG configuration - # - #if ( WRAP_CSHARP ) - # add_subdirectory ( CSharp ) - #endif() - - # - # TCL SWIG configuration - # - #if ( WRAP_TCL ) - # add_subdirectory ( Tcl ) - #endif() - - # - # R SWIG configuration - # - #if ( WRAP_R ) - # add_subdirectory( R ) - #endif() + add_subdirectory(Python) endif() diff --git a/Wrapping/Common/mitk_swig_classes.i b/Wrapping/Common/mitk_swig_classes.i index 9241ec56b9..686e07481b 100644 --- a/Wrapping/Common/mitk_swig_classes.i +++ b/Wrapping/Common/mitk_swig_classes.i @@ -1,157 +1,214 @@ - // // Defining some Macros that make problems with SWIG as the // corresponding definitions are not included by default. // Luckely, these includes are not necessary for SWIG. // #define ITK_NOEXCEPT #define ITKCommon_EXPORT #define ITK_OVERRIDE #define MITKCORE_EXPORT #define MITKCLCORE_EXPORT #define MITKCLUTILITIES_EXPORT #define ITKCommon_EXPORT #define MITKMATCHPOINTREGISTRATION_EXPORT #define MAPDeployment_EXPORT #define MAPAlgorithms_EXPORT #define MITKSEGMENTATION_EXPORT #define MITKMULTILABEL_EXPORT +#define MITKBASICIMAGEPROCESSING_EXPORT + +#define VCL_TEMPLATE_EXPORT #define ITKCommon_EXPORT #define ITK_FORWARD_EXPORT #define ITK_OVERRIDE #define ITK_NOEXCEPT - %include %include %include %include %include %include - +%include #define DEPRECATED(func) func #undef ITK_DISALLOW_COPY_AND_ASSIGN #define ITK_DISALLOW_COPY_AND_ASSIGN(TypeName) +typedef double ScalarType; +typedef Vector3D mitk::Vector3D; + %pythoncode %{ convertion_list = {} %} + SWIG_ADD_NONOBJECT_CLASS(Indent, itkIndent.h, itk) SWIG_ADD_MITK_CLASS(LightObject, itkLightObject.h, itk) SWIG_ADD_MITK_CLASS(Object, itkObject.h, itk) SWIG_ADD_MITK_CLASS(DataObject, itkDataObject.h, itk) SWIG_ADD_MITK_CLASS(TimeGeometry, mitkTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ArbitraryTimeGeometry, mitkArbitraryTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ProportionalTimeGeometry, mitkProportionalTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(BaseGeometry, mitkBaseGeometry.h, mitk) SWIG_ADD_MITK_CLASS(Geometry3D, mitkGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(SlicedGeometry3D, mitkSlicedGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(PlaneGeometry , mitkPlaneGeometry.h, mitk) -SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BoundingBox, mitkBaseGeometry.h, mitk) +%rename(itk_BoundingBox) itk::BoundingBox; +%include +%{ +#include +typedef mitk::BoundingBox BoundingBox; +%} +%template(VectorBoundingBoxPointer) std::vector< mitk::BoundingBox * >; + + +//SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BoundingBox, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(TimeBounds, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(FixedArrayType, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(VnlVector, mitkVector.h, mitk) -SWIG_ADD_NONOBJECT_CLASS(Vector2D, mitkVector.h, mitk) -SWIG_ADD_NONOBJECT_CLASS(Vector3D, mitkVector.h, mitk) -SWIG_ADD_NONOBJECT_CLASS(Vector4D, mitkVector.h, mitk) +%ignore rBegin() const; +%ignore rEnd() const; +%ignore rBegin(); +%ignore rEnd(); +%ignore itk::Vector::GetVnlVector; +%ignore itk::Vector::Get_vnl_vector; +%ignore itk::Vector::Get_vnl_vector const; + +%{ + #include + #include + #include + typedef vnl_vector_ref VnlVectorRef; +%} +//%include +//MITKSWIG_ADD_CLASS(VnlVectorRef, mitkVector.h,) +//typedef ::VnlVectorRef VnlVectorRef; +class VnlVectorRef; +%template(VectorVnlVectorRefPointer) std::vector<::VnlVectorRef * >; +//SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(VnlVectorRef, mitkVector.h, ) + +%include +%include +class itk::FixedArray::ReverseIterator; +//%template(VnlVectorRef) vnl_vector_ref; +%template(itkFixedArray2D) itk::FixedArray; +%template(itkFixedArray3D) itk::FixedArray; +%template(itkFixedArray3UD) itk::FixedArray; +%template(itkFixedArray4D) itk::FixedArray; +%template(itkVector2D) itk::Vector; +%template(itkVector3D) itk::Vector; +%template(itkVector3UD) itk::Vector; +%template(itkVector4D) itk::Vector; + +SWIG_ADD_NONOBJECT_TEMPLATE_CLASS(Vector2D, mitkVector.h, mitk) +%template(Vector2D) mitk::Vector; +SWIG_ADD_NONOBJECT_TEMPLATE_CLASS(Vector3D, mitkVector.h, mitk) +%template(Vector3D) mitk::Vector; +SWIG_ADD_NONOBJECT_TEMPLATE_CLASS(Vector4D, mitkVector.h, mitk) +%template(Vector4D) mitk::Vector; SWIG_ADD_MITK_CLASS(BaseData, mitkBaseData.h, mitk) SWIG_ADD_MITK_CLASS(SlicedData, mitkSlicedData.h, mitk) SWIG_ADD_MITK_CLASS(Image, mitkImage.h, mitk) SWIG_ADD_MITK_CLASS(LabelSetImage, mitkLabelSetImage.h, mitk) SWIG_ADD_MITK_CLASS(PointSet, mitkPointSet.h, mitk) %{ using mitk::Message; %} // // Phenotyping Related Classes // SWIG_ADD_MITK_CLASS(AbstractGlobalImageFeature, mitkAbstractGlobalImageFeature.h, mitk) SWIG_ADD_MITK_CLASS(GIFImageDescriptionFeatures, mitkGIFImageDescriptionFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderStatistics, mitkGIFFirstOrderStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderHistogramStatistics, mitkGIFFirstOrderHistogramStatistics.h, mitk) +SWIG_ADD_MITK_CLASS(GIFFirstOrderNumericStatistics, mitkGIFFirstOrderNumericStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricStatistics, mitkGIFVolumetricStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricDensityStatistics, mitkGIFVolumetricDensityStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFCooccurenceMatrix2, mitkGIFCooccurenceMatrix2.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbouringGreyLevelDependenceFeature, mitkGIFNeighbouringGreyLevelDependenceFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelRunLength, mitkGIFGreyLevelRunLength.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelSizeZone, mitkGIFGreyLevelSizeZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelDistanceZone, mitkGIFGreyLevelDistanceZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFLocalIntensity, mitkGIFLocalIntensity.h, mitk) SWIG_ADD_MITK_CLASS(GIFIntensityVolumeHistogramFeatures, mitkGIFIntensityVolumeHistogramFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbourhoodGreyToneDifferenceFeatures, mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFCurvatureStatistic, mitkGIFCurvatureStatistic.h, mitk) // // Conversion and Segmentation based Classes // SWIG_ADD_MITK_CLASS(ContourModelSetToImageFilter, mitkContourModelSetToImageFilter.h, mitk) SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BooleanOperation, mitkBooleanOperation.h, mitk) SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(MorphologicalOperations, mitkMorphologicalOperations.h, mitk) +//SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(MaskCleaningOperation, mitkMaskCleaningOperation.h, mitk) +//SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(TransformationOperation, mitkTransformationOperation.h, mitk) +//SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(ArithmeticOperation, mitkArithmeticOperation.h, mitk) %{ #include typedef itk::DataObject::DataObjectIdentifierType DataObjectIdentifierType; typedef itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; %} -// -// MatchPoint Related Classes -// -%ignore DLLHandle::LibraryHandleType; - -%{ -#include -namespace core -{ - typedef std::string String; -} -typedef map::deployment::DLLHandle::LibraryHandleType LibraryHandleType; -typedef map::deployment::DLLHandle DLLHandle; -%} -namespace core -{ - typedef std::string String; -} - -%nodefaultctor LibraryHandleType; -struct LibraryHandleType {}; - -%include -SWIG_ADD_MITK_CLASS(UID,mapUID.h, map::algorithm) -SWIG_ADD_MITK_CLASS(DLLInfo, mapDeploymentDLLInfo.h, map::deployment) -//SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, map::deployment) - -SWIG_ADD_MITK_CLASS_VECTORFREE(DLLDirectoryBrowser, mapDeploymentDLLDirectoryBrowser.h, ::map::deployment) -MITKSWIG_ADD_HEADERFILE(mapDeploymentDLLAccess.h) -%{ - DLLHandle const * ConvertDLLHandleSmartPointerToPointer(itk::SmartPointer p) - { - return p.GetPointer(); - } -%} -DLLHandle const * ConvertDLLHandleSmartPointerToPointer(DLLHandle::Pointer p); - -MITKSWIG_ADD_CLASS(MAPAlgorithmHelper, mitkMAPAlgorithmHelper.h, mitk) -MITKSWIG_ADD_CLASS(RegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) -MITKSWIG_ADD_CLASS(MITKRegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) +#ifdef MITK_USE_MatchPoint + // + // MatchPoint Related Classes + // + %ignore DLLHandle::LibraryHandleType; + + %{ + #include + namespace core + { + typedef std::string String; + } + typedef map::deployment::DLLHandle::LibraryHandleType LibraryHandleType; + typedef map::deployment::DLLHandle DLLHandle; + %} + namespace core + { + typedef std::string String; + } + + %nodefaultctor LibraryHandleType; + struct LibraryHandleType {}; + + %include + SWIG_ADD_MITK_CLASS(UID,mapUID.h, map::algorithm) + SWIG_ADD_MITK_CLASS(DLLInfo, mapDeploymentDLLInfo.h, map::deployment) + //SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, map::deployment) + + SWIG_ADD_MITK_CLASS_VECTORFREE(DLLDirectoryBrowser, mapDeploymentDLLDirectoryBrowser.h, ::map::deployment) + MITKSWIG_ADD_HEADERFILE(mapDeploymentDLLAccess.h) + %{ + DLLHandle const * ConvertDLLHandleSmartPointerToPointer(itk::SmartPointer p) + { + return p.GetPointer(); + } + %} + DLLHandle const * ConvertDLLHandleSmartPointerToPointer(DLLHandle::Pointer p); + + MITKSWIG_ADD_CLASS(MAPAlgorithmHelper, mitkMAPAlgorithmHelper.h, mitk) + MITKSWIG_ADD_CLASS(RegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) + MITKSWIG_ADD_CLASS(MITKRegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) +#endif // SWIG_ADD_MITK_CLASS(FastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm, mitkFastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(LevelSetMotionMultiResDefaultRegistrationAlgorithm, mitkLevelSetMotionMultiResDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(MultiModalAffineDefaultRegistrationAlgorithm, mitkMultiModalAffineDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(MultiModalRigidDefaultRegistrationAlgorithm, mitkMultiModalRigidDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(MultiModalTransDefaultRegistrationAlgorithm, mitkMultiModalTransDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(RigidClosedFormPointsDefaultRegistrationAlgorithm, mitkRigidClosedFormPointsDefaultRegistrationAlgorithm.h, mitk) // SWIG_ADD_MITK_CLASS(RigidICPDefaultRegistrationAlgorithm, mitkRigidICPDefaultRegistrationAlgorithm.h, mitk) \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_cpp_include.i b/Wrapping/Common/mitk_swig_cpp_include.i index 198e92ece6..ce8086d6a6 100644 --- a/Wrapping/Common/mitk_swig_cpp_include.i +++ b/Wrapping/Common/mitk_swig_cpp_include.i @@ -1,127 +1,127 @@ %{ - #include #include #include #include #include #include #include #include +#include // SWIG Doesn't wrap namespaces. This leads to some problems, if the namespaces are not used. using mitk::DataStorage; using mitk::IFileReader; using mitk::IFileWriter; using mitk::ScalarType; using mitk::Operation; using mitk::GeometryTransformHolder; using mitk::AffineTransform3D; using mitk::BaseProperty; using mitk::ImageDescriptor; using mitk::PropertyList; using mitk::ImageDataItem; using mitk::PointSpecificationType; using mitk::IntensityQuantifier; using itk::LightObject; using itk::ModifiedTimeType; using itk::TimeStamp; using itk::EventObject; using itk::MetaDataDictionary; using itk::SmartPointerForwardReference; using itk::RealTimeStamp; std::vector GetImageSize(mitk::Image::Pointer image) { std::vector< unsigned int > size; unsigned int dimension = image->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(image->GetDimension(i)); } return size; } std::vector GetImageSize(mitk::Image* image) { std::vector< unsigned int > size; unsigned int dimension = image->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(image->GetDimension(i)); } return size; } struct TypeDefinitions { static const int ComponentTypeUInt8 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeInt8 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeUInt16 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeInt16 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeUInt32 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeInt32 = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeFloat = mitk::MapPixelType::value>::IOComponentType; static const int ComponentTypeDouble = mitk::MapPixelType::value>::IOComponentType; }; mitk::PixelType MakePixelTypeFromTypeID(int componentTypeID, int numberOfComponents) { switch (componentTypeID) { case TypeDefinitions::ComponentTypeUInt8 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeInt8 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeUInt16 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeInt16 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeUInt32 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeInt32 : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeFloat : return mitk::MakePixelType(numberOfComponents); case TypeDefinitions::ComponentTypeDouble : return mitk::MakePixelType(numberOfComponents); default: return mitk::MakePixelType(numberOfComponents); } } mitk::Image::Pointer MakeImage(mitk::PixelType pixelType, std::vector shape) { mitk::Image::Pointer image = mitk::Image::New(); image->Initialize(pixelType, shape.size(), shape.data()); return image; } template typename T::Pointer ConvertTo(itk::Object::Pointer base) { typename T::Pointer erg = dynamic_cast(base.GetPointer()); return erg; } %} std::vector GetImageSize(mitk::Image::Pointer image); std::vector GetImageSize(mitk::Image* image); mitk::PixelType MakePixelTypeFromTypeID(int componentTypeID, int numberOfComponents); mitk::Image::Pointer MakeImage(mitk::PixelType pixelType, std::vector shape); %constant int ComponentTypeUInt8 = TypeDefinitions::ComponentTypeUInt8; %constant int ComponentTypeInt8 = TypeDefinitions::ComponentTypeInt8; %constant int ComponentTypeUInt16 = TypeDefinitions::ComponentTypeUInt16; %constant int ComponentTypeInt16 = TypeDefinitions::ComponentTypeInt16; %constant int ComponentTypeUInt32 = TypeDefinitions::ComponentTypeUInt32; %constant int ComponentTypeInt32 = TypeDefinitions::ComponentTypeInt32; %constant int ComponentTypeFloat = TypeDefinitions::ComponentTypeFloat; %constant int ComponentTypeDouble = TypeDefinitions::ComponentTypeDouble; template typename T::Pointer ConvertTo(itk::Object::Pointer base); diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i index 1d8c746414..cf34fa30da 100644 --- a/Wrapping/Common/mitk_swig_macros.i +++ b/Wrapping/Common/mitk_swig_macros.i @@ -1,232 +1,257 @@ // // This file contains macros for swig. // // // MITKSWIG_ADD_HEADERFILE includes a header-file into SWIG // %define MITKSWIG_ADD_HEADERFILE( classinclude ) // Include the given header, where the class definition is found %include < ## classinclude ## > // Include the include file in the generated cpp file %{ #include < ## classinclude ## > %} %enddef // // MITKSWIG_ADD_CLASS is a helper macro in order to do // all important stuff in order to wrap an existing // class // %define MITKSWIG_ADD_CLASS(classname, classinclude, nspace) MITKSWIG_ADD_HEADERFILE( classinclude ) // Using class name in order to remove ambigiouties %{ typedef nspace ## :: ## classname classname ## ; using nspace ## :: ## classname ; %} using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; %enddef // // MITKSWIG_AUTOMATED_CASTING is a helper macro in order to // provide a convenience interface for up/downcasting of // classes // %define MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) // Define a conversion method to convert from and to types %template(ConvertTo ## classname) ConvertTo< nspace ##:: ## classname ## >; // This extend is necessary to have the automatic cast methods available %extend itk::SmartPointer< nspace ## :: ## classname ## ::Self> { %pythoncode %{ def _GetListOfValidItems(self): - return [str(k) for k in self.GetClassHierarchy() if str(k) in convertion_list.keys() ] + return [str(k).replace("class itk::","") for k in self.GetClassHierarchy() if str(k).replace("class itk::","") in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %extend std::vector< nspace ## :: ## classname *>::value_type { %pythoncode %{ def _GetListOfValidItems(self): return [str(k) for k in self.GetClassHierarchy() if str(k) in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %pythoncode %{ convertion_list['classname'] = ConvertTo ## classname %} %enddef // // MITKSWIG_SMARTPOINTERVECTOR : Wrapper for Vectors of Smartpointer-Classes // %define MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; %enddef // // MITKSWIG_POINTERVECTOR : Wrapper for Vectors of Classes // %define MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %template(Vector ## classname) std::vector< nspace ## :: ## classname >; %enddef // // MITKSWIG_MITKSMARTPOINTER_INITIALIZATION : Wrapper for Vectors of Smartpointer-Classes // %define MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) // Declaring that this class is a smart-pointer class, in order to handle // online upcasting where necessary (for example python) + %feature("smartptr", noblock=1) classname { classname ## ::Pointer } + %feature("smartptr", noblock=1) nspace ##:: ## classname { nspace ## :: ## classname ## ::Pointer } + %feature("smartptr", noblock=1) nspace ##:: ## classname { classname ## ::Pointer } %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } %enddef // // MITKSWIG_MITKSMARTPOINTER_TEMPLATE : Wrapper for Vectors of Smartpointer-Classes // %define MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) // Defining the Smartpointer, allows easy access in target language %template(classname ## Pointer) itk::SmartPointer; %enddef // // SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_MITK_CLASS_VECTORFREE(classname, classinclude, nspace) %include < ## classinclude ## > MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) + //class classname ## ; + //class classname ## ::Pointer; + class nspace ## :: ## classname ## ; class nspace ## :: ## classname ## ::Pointer; MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) %enddef // // SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) %include < ## classinclude ## > MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) - + // Defining only the original classname + // If the ::Pointer is also defined, smartpointer won't work class nspace ## :: ## classname ## ; - class nspace ## :: ## classname ## ::Pointer; + //class nspace ## :: ## classname ## ::Pointer; // It is important to first define the Vectors and // then define the Smartpointer. Otherwise a SWIG-bug ... MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) %enddef // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) %include < ## classinclude ## > MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; class nspace ## :: ## classname ## ; MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) %enddef +// +// SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do +// all important stuff before an mitk::Class is included. +// Requires the name of the class as it is in c++ as classname +// and the include file, in which the class is defined. +// It is assumed that the class is somehow inherited from +// mitk::BaseData, and supports smartpointers. +// +%define SWIG_ADD_NONOBJECT_TEMPLATE_CLASS(classname, classinclude, nspace) + %include < ## classinclude ## > + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) + + //%template(classname) templateArgs; + //class nspace ## :: ## classname ## ; + + MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) +%enddef + // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(classname, classinclude, nspace) %include < ## classinclude ## > MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; -%enddef +%enddef \ No newline at end of file diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index cca64accd3..aec8c76d18 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,77 +1,88 @@ -# Version 2.8.1 is the minimum requirement for this script. -# this is lower than the general minimum requirement. -#cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) - include(mitkTargetLinkLibrariesWithDynamicLookup) -project( MITK_Python ) +project(MITK_Python) set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) mitk_check_dynamic_lookup(MODULE SHARED MITK_UNDEFINED_SYMBOLS_ALLOWED - ) +) -# -# Find the necessary libraries etc.. -# +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) - set( _QUIET_LIBRARY "QUIET" ) -else() - set( _QUIET_LIBRARY "REQUIRED" ) +option(MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) +option(MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) +option(MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) + +mark_as_advanced( + MITK_PYTHON_THREADS + MITK_PYTHON_EGG + MITK_PYTHON_WHEEL +) + +set(libraries + MitkCore + MitkCLCore + MitkCLUtilities + ITKCommon + MitkSegmentation + MitkMultilabel + MitkDICOM + MitkDICOMImageIO + MitkRT +) + +if(MITK_USE_MatchPoint) + list(APPEND libraries + MitkMatchPointRegistration + ) endif() -find_package ( PythonInterp REQUIRED ) -find_package ( PythonLibs ${_QUIET_LIBRARY} ) -include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) -# -# Options -# -option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) -mark_as_advanced( MITK_PYTHON_THREADS ) -option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) -mark_as_advanced( MITK_PYTHON_EGG ) -option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) -mark_as_advanced( MITK_PYTHON_WHEEL ) - -# Prepare the SWIG-File, i.e. especially add necessary include folders -mitkSwigPrepareFiles(pyMITK MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration;MitkSegmentation;MitkMultilabel;MitkDICOM;MitkDICOMImageIO;MitkRT") - -# Add additional SWIG Parameters -# These parameters depend on the target language -set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) -if( MITK_PYTHON_THREADS ) - set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) + + +mitkSwigPrepareFiles(pyMITK MITK.i ${libraries}) + +set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword) + +if(MITK_PYTHON_THREADS) + list(APPEND CMAKE_SWIG_FLAGS -threads) endif() -set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) -# Create the actual SWIG project -swig_add_module(pyMITK python MITK.i ) +set(CMAKE_SWIG_OUTDIR ${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}) +set(UseSWIG_TARGET_NAME_PREFERENCE STANDARD) +swig_add_library(pyMITK LANGUAGE python SOURCES MITK.i) +set_property(TARGET pyMITK PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Wrapping") +target_link_libraries(pyMITK ${libraries}) -mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration;MitkSegmentation;MitkMultilabel;MitkDICOM;MitkDICOMImageIO;MitkRT") -mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_pyMITK_REAL_NAME} ${PYTHON_LIBRARIES}) +mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_pyMITK_REAL_NAME} ${Python3_LIBRARIES}) +set_target_properties(pyMITK PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY}" +) +execute_process(COMMAND ${SWIG_EXECUTABLE} -python -external-runtime) if(DEFINED SKBUILD) - message(WARNING "SKBuild exists") - # Currently this installation - install(FILES + #message("SKBuild exists") + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/pyMITK.py ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py - # ${MITK_DOC_FILES} + #${MITK_DOC_FILES} DESTINATION pyMITK COMPONENT Runtime - ) - - install(TARGETS ${SWIG_MODULE_pyMITK_REAL_NAME} - RUNTIME DESTINATION pyMITK - LIBRARY DESTINATION pyMITK + ) + install( + TARGETS + ${SWIG_MODULE_pyMITK_REAL_NAME} + RUNTIME + DESTINATION pyMITK + LIBRARY + DESTINATION pyMITK COMPONENT Runtime - ) + ) else() - message(WARNING "SKBuild missing") + #message("SKBuild missing") include(LegacyPackaging.cmake) endif() diff --git a/Wrapping/Python/MITK.i b/Wrapping/Python/MITK.i index 83649ee83b..090715a0ac 100644 --- a/Wrapping/Python/MITK.i +++ b/Wrapping/Python/MITK.i @@ -1,167 +1,172 @@ +%begin %{ +#ifdef _MSC_VER +#define SWIG_PYTHON_INTERPRETER_NO_DEBUG +#endif +%} %module pyMITK %include %{ #include "mitkNumpyArrayConversion.cxx" %} // Numpy array conversion support %native(_GetMemoryViewFromImage) PyObject *mitk_GetMemoryViewFromImage( PyObject *self, PyObject *args ); %native(_SetImageFromArray) PyObject *mitk_SetImageFromArray( PyObject *(self), PyObject *args ); %pythoncode %{ HAVE_NUMPY = True try: import numpy except ImportError: HAVE_NUMPY = False def _get_numpy_dtype( mitkImage ): """Given a MITK image, returns the numpy.dtype which describes the data""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # this is a mapping from MITK's pixel id to numpy's dtype _mitk_np = {ComponentTypeUInt8:numpy.uint8, ComponentTypeUInt16:numpy.uint16, ComponentTypeUInt32:numpy.uint32, ComponentTypeInt8:numpy.int8, ComponentTypeInt16:numpy.int16, ComponentTypeInt32:numpy.int32, ComponentTypeFloat:numpy.float32, ComponentTypeDouble:numpy.float64, } return _mitk_np[ mitkImage.GetPixelType().GetComponentType() ] def _get_mitk_pixelid(numpy_array_type): """Returns a MITK PixelID given a numpy array.""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # This is a Mapping from numpy array types to sitks pixel types. _np_mitk = {numpy.character:ComponentTypeUInt8, numpy.uint8:ComponentTypeUInt8, numpy.uint16:ComponentTypeUInt16, numpy.uint32:ComponentTypeUInt32, numpy.int8:ComponentTypeInt8, numpy.int16:ComponentTypeInt16, numpy.int32:ComponentTypeInt32, numpy.float32:ComponentTypeFloat, numpy.float64:ComponentTypeDouble, } try: return _np_mitk[numpy_array_type.dtype] except KeyError: for key in _np_mitk: if numpy.issubdtype(numpy_array_type.dtype, key): return _np_mitk[key] raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) def _get_sitk_vector_pixelid(numpy_array_type): """Returns a MITK vector PixelID given a numpy array.""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # This is a Mapping from numpy array types to sitks pixel types. _np_sitk = {numpy.character:sitkVectorUInt8, numpy.uint8:sitkVectorUInt8, numpy.uint16:sitkVectorUInt16, numpy.uint32:sitkVectorUInt32, numpy.uint64:sitkVectorUInt64, numpy.int8:sitkVectorInt8, numpy.int16:sitkVectorInt16, numpy.int32:sitkVectorInt32, numpy.int64:sitkVectorInt64, numpy.float32:sitkVectorFloat32, numpy.float64:sitkVectorFloat64, } try: return _np_sitk[numpy_array_type.dtype] except KeyError: for key in _np_sitk: if numpy.issubdtype(numpy_array_type.dtype, key): return _np_sitk[key] raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) # MITK <-> Numpy Array conversion support. #http://www.nickdarnell.com/swig-casting-revisited/ def GetArrayViewFromImage(image): """Get a NumPy ndarray view of a MITK Image. Returns a Numpy ndarray object as a "view" of the MITK's Image buffer. This reduces pixel buffer copies, but requires that the MITK image object is kept around while the buffer is being used. """ if not HAVE_NUMPY: raise ImportError('NumPy not available.') dtype = _get_numpy_dtype( image ) shape = GetImageSize(image); if image.GetPixelType().GetNumberOfComponents() > 1: shape = ( image.GetPixelType().GetNumberOfComponents(), ) + shape imageMemoryView = _pyMITK._GetMemoryViewFromImage(image) arrayView = numpy.asarray(imageMemoryView).view(dtype = dtype) arrayView.shape = shape[::-1] return arrayView def GetArrayFromImage(image): """Get a NumPy ndarray from a MITK Image. This is a deep copy of the image buffer and is completely safe and without potential side effects. """ # TODO: If the image is already not unique then a second copy may be made before the numpy copy is done. arrayView = GetArrayViewFromImage(image) # perform deep copy of the image buffer return numpy.array(arrayView, copy=True) def GetImageFromArray( arr, isVector=False): """Get a MITK Image from a numpy array. If isVector is True, then a 3D array will be treated as a 2D vector image, otherwise it will be treated as a 3D image""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') z = numpy.asarray( arr ) assert z.ndim in ( 2, 3, 4 ), \ "Only arrays of 2, 3 or 4 dimensions are supported." id = _get_mitk_pixelid( z ) #img = Image_New() if ( z.ndim == 3 and isVector ) or (z.ndim == 4): pixelType=MakePixelTypeFromTypeID(id, z.shape[-1]) newShape=VectorUInt32(z.shape[-2::-1]) img = MakeImage(pixelType, newShape) #img.Initialize(pixelType, z.ndim - 1, z.shape[-2::-1]) elif z.ndim in ( 2, 3 ): pixelType=MakePixelTypeFromTypeID(id, 1) newShape=VectorUInt32(z.shape[::-1]) img = MakeImage(pixelType, newShape) #img.Initialize(pixelType, z.ndim, z.shape[::-1]) _pyMITK._SetImageFromArray( z.tostring(), img ) return img %} diff --git a/Wrapping/Python/dist/CMakeLists.txt b/Wrapping/Python/dist/CMakeLists.txt index 504c94c5fa..89f93e2f0c 100644 --- a/Wrapping/Python/dist/CMakeLists.txt +++ b/Wrapping/Python/dist/CMakeLists.txt @@ -1,40 +1,41 @@ # # Packaging # if( MITK_PYTHON_EGG OR MITK_PYTHON_WHEEL ) if( NOT MITK_PYTHON_USE_VIRTUALENV ) message( STATUS "Not using MITK's virtualenv for distribution!\n Using unknown versions of pip, setuptools and/or wheel packages/" ) endif() set(bdist_setup "${MITK_Python_BINARY_DIR}/Packaging/setup.py") set(bdist_commands "") if( MITK_PYTHON_EGG ) set(bdist_commands "bdist_egg") endif() if( MITK_PYTHON_WHEEL ) set(bdist_commands ${bdist_commands} "bdist_wheel") endif() set( MITK_PYTHON_PLAT_NAME "" CACHE STRING "Optional value passed to setup.py with the '--plat-name' argument") if( NOT "${MITK_PYTHON_PLAT_NAME}" STREQUAL "" ) set(bdist_commands ${bdist_commands} "--plat-name" "${MITK_PYTHON_PLAT_NAME}") endif() add_custom_target( dist.Python ${VIRTUAL_PYTHON_EXECUTABLE} ${bdist_setup} ${bdist_commands} WORKING_DIRECTORY ${MITK_Python_BINARY_DIR} DEPENDS ${SWIG_MODULE_pyMITK_REAL_NAME} COMMENT "Creating Python binary distribution" ) + set_property(TARGET dist.Python PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Wrapping") if( MITK_PYTHON_USE_VIRTUALENV ) add_dependencies( dist.Python PythonVirtualEnv) endif() add_dependencies( dist dist.Python ) elseif() message( STATUS "Not creating dist.Python target since MITK_FORBID_DOWNLOADS is enabled" ) endif() diff --git a/Wrapping/Python/mitkNumpyArrayConversion.cxx b/Wrapping/Python/mitkNumpyArrayConversion.cxx index b8256fb8c5..40fea6097b 100644 --- a/Wrapping/Python/mitkNumpyArrayConversion.cxx +++ b/Wrapping/Python/mitkNumpyArrayConversion.cxx @@ -1,237 +1,245 @@ /*========================================================================= * * Copyright Insight Software Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #include #include #include #include +#include #include "mitkImage.h" // Python is written in C #ifdef __cplusplus extern "C" { #endif /** An internal function that returns a memoryview object to the * MITK Image's buffer (shallow). The correct copy and writing * policies need to be done by the end-user method. */ static PyObject * mitk_GetMemoryViewFromImage( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) { const void * mitkBufferPtr; Py_ssize_t len; std::vector< unsigned int > size; size_t pixelSize = 1; unsigned int dimension; /* Cast over to a sitk Image. */ PyObject * pyImage; void * voidImage; mitk::Image * mitkImage; + mitk::ImageWriteAccessor* writeAccess = NULL; int res = 0; PyObject * memoryView = NULL; Py_buffer pyBuffer; memset(&pyBuffer, 0, sizeof(Py_buffer)); unsigned int accumulatorValue = 1; - if( !PyArg_ParseTuple( args, "O", &pyImage ) ) { SWIG_fail; // SWIG_fail is a macro that says goto: fail (return NULL) } res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); if (!SWIG_IsOK(res)) { mitk::Image::Pointer tmpImage; res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); } tmpImage = *(reinterpret_cast(voidImage)); voidImage = reinterpret_cast(tmpImage.GetPointer()); } mitkImage = reinterpret_cast< mitk::Image * >( voidImage ); - mitkBufferPtr = mitkImage->GetData(); + writeAccess = new mitk::ImageWriteAccessor(mitkImage); + mitkBufferPtr = writeAccess->GetData(); pixelSize = mitkImage->GetPixelType().GetBitsPerComponent() / 8; dimension = mitkImage->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(mitkImage->GetDimension(i)); } // if the image is a vector just treat is as another dimension if ( mitkImage->GetPixelType().GetNumberOfComponents() > 1 ) { size.push_back( mitkImage->GetPixelType().GetNumberOfComponents() ); } len = std::accumulate( size.begin(), size.end(), accumulatorValue, std::multiplies() ); len *= pixelSize; if (PyBuffer_FillInfo(&pyBuffer, NULL, (void*)mitkBufferPtr, len, true, PyBUF_CONTIG_RO)!=0) { SWIG_fail; } memoryView = PyMemoryView_FromBuffer(&pyBuffer); PyBuffer_Release(&pyBuffer); + delete writeAccess; return memoryView; fail: Py_XDECREF( memoryView ); + delete writeAccess; return NULL; } /** An internal function that performs a deep copy of the image buffer * into a python byte array. The byte array can later be converted * into a numpy array with the frombuffer method. */ static PyObject* mitk_SetImageFromArray( PyObject *SWIGUNUSEDPARM(self), PyObject *args ) { PyObject * pyImage = NULL; const void *buffer; Py_ssize_t buffer_len; Py_buffer pyBuffer; memset(&pyBuffer, 0, sizeof(Py_buffer)); mitk::Image * mitkImage = NULL; + mitk::ImageWriteAccessor *writeAccess = NULL; void * mitkBufferPtr = NULL; size_t pixelSize = 1; unsigned int dimension = 0; std::vector< unsigned int > size; size_t len = 1; unsigned int accuValue = 1; // We wish to support both the new PEP3118 buffer interface and the // older. So we first try to parse the arguments with the new buffer // protocol, then the old. if (!PyArg_ParseTuple( args, "s*O", &pyBuffer, &pyImage ) ) { PyErr_Clear(); #ifdef PY_SSIZE_T_CLEAN typedef Py_ssize_t bufSizeType; #else typedef int bufSizeType; #endif bufSizeType _len; // This function takes 2 arguments from python, the first is an // python object which support the old "ReadBuffer" interface if( !PyArg_ParseTuple( args, "s#O", &buffer, &_len, &pyImage ) ) { return NULL; } buffer_len = _len; } else { if ( PyBuffer_IsContiguous( &pyBuffer, 'C' ) != 1 ) { PyBuffer_Release( &pyBuffer ); PyErr_SetString( PyExc_TypeError, "A C Contiguous buffer object is required." ); return NULL; } buffer_len = pyBuffer.len; buffer = pyBuffer.buf; } /* Cast over to a sitk Image. */ { void * voidImage; int res = 0; res = SWIG_ConvertPtr( pyImage, &voidImage, SWIGTYPE_p_mitk__Image, 0 ); if (!SWIG_IsOK(res)) { mitk::Image::Pointer tmpImage; res = SWIG_ConvertPtr(pyImage, &voidImage, SWIGTYPE_p_itk__SmartPointerT_mitk__Image_t, 0); if (!SWIG_IsOK(res)) { SWIG_exception_fail(SWIG_ArgError(res), "in method 'GetByteArrayFromImage', argument needs to be of type 'sitk::Image *'"); } tmpImage = *(reinterpret_cast(voidImage)); voidImage = reinterpret_cast(tmpImage.GetPointer()); } mitkImage = reinterpret_cast< mitk::Image * >(voidImage); } try { - mitkBufferPtr = mitkImage->GetData(); + writeAccess = new mitk::ImageWriteAccessor(mitkImage); + mitkBufferPtr = writeAccess->GetData(); pixelSize= mitkImage->GetPixelType().GetBitsPerComponent() / 8; } catch( const std::exception &e ) { std::string msg = "Exception thrown in MITK new Image: "; msg += e.what(); PyErr_SetString( PyExc_RuntimeError, msg.c_str() ); goto fail; } dimension = mitkImage->GetDimension(); for (int i = 0; i < dimension; ++i) { size.push_back(mitkImage->GetDimension(i)); } // if the image is a vector just treat is as another dimension if (mitkImage->GetPixelType().GetNumberOfComponents() > 1) { size.push_back(mitkImage->GetPixelType().GetNumberOfComponents()); } len = std::accumulate(size.begin(), size.end(), accuValue, std::multiplies()); len *= pixelSize; if ( buffer_len != len ) { PyErr_SetString( PyExc_RuntimeError, "Size mismatch of image and Buffer." ); goto fail; } memcpy( (void *)mitkBufferPtr, buffer, len ); PyBuffer_Release( &pyBuffer ); + delete writeAccess; Py_RETURN_NONE; fail: PyBuffer_Release( &pyBuffer ); + delete writeAccess; return NULL; } #ifdef __cplusplus } // end extern "C" #endif