diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake b/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake index 43155e16cd..60335dbd92 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeExternals/MITK.cmake @@ -1,211 +1,210 @@ #----------------------------------------------------------------------------- # MITK #----------------------------------------------------------------------------- set(MITK_DEPENDS) set(proj_DEPENDENCIES) set(proj MITK) if(NOT MITK_DIR) #----------------------------------------------------------------------------- # Create CMake options to customize the MITK build #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Use superbuild for MITK" ON) option(MITK_USE_BLUEBERRY "Build the BlueBerry platform in MITK" ON) option(MITK_BUILD_EXAMPLES "Build the MITK examples" OFF) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) option(MITK_BUILD_TESTING "Build the MITK unit tests" OFF) option(MITK_USE_ACVD "Use Approximated Centroidal Voronoi Diagrams" OFF) option(MITK_USE_CTK "Use CTK in MITK" ${MITK_USE_BLUEBERRY}) option(MITK_USE_DCMTK "Use DCMTK in MITK" ON) option(MITK_USE_Qt5 "Use Qt 5 library in MITK" ON) option(MITK_USE_DCMQI "Use dcmqi in MITK" OFF) option(MITK_USE_OpenCV "Use Intel's OpenCV library" OFF) option(MITK_USE_Python3 "Enable Python wrapping in MITK" OFF) if(MITK_USE_BLUEBERRY AND 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() if(MITK_USE_CTK AND NOT MITK_USE_Qt5) message("Forcing MITK_USE_Qt5 to ON because of MITK_USE_CTK") set(MITK_USE_Qt5 ON CACHE BOOL "Use Qt 5 library in MITK" FORCE) endif() set(MITK_USE_CableSwig ${MITK_USE_Python3}) - set(MITK_USE_GDCM 1) set(MITK_USE_ITK 1) set(MITK_USE_VTK 1) mark_as_advanced(MITK_USE_SUPERBUILD MITK_BUILD_ALL_PLUGINS MITK_BUILD_TESTING ) set(mitk_cmake_boolean_args MITK_USE_SUPERBUILD MITK_USE_BLUEBERRY MITK_BUILD_EXAMPLES MITK_BUILD_ALL_PLUGINS MITK_USE_ACVD MITK_USE_CTK MITK_USE_DCMTK MITK_USE_Qt5 MITK_USE_DCMQI MITK_USE_OpenCV MITK_USE_Python3 ) if(MITK_USE_Qt5) # Look for Qt at the superbuild level, to catch missing Qt libs early find_package(Qt5Widgets REQUIRED) endif() set(additional_mitk_cmakevars ) # Configure the set of default 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") 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 "" 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") foreach(_arg MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS) mark_as_advanced(${_arg}) list(APPEND additional_mitk_cmakevars "-D${_arg}:STRING=${${_arg}}") endforeach() #----------------------------------------------------------------------------- # Create options to inject pre-build dependencies #----------------------------------------------------------------------------- - foreach(proj CTK DCMTK DCMQI GDCM VTK ACVD ITK OpenCV CableSwig) + foreach(proj CTK DCMTK DCMQI VTK ACVD ITK OpenCV CableSwig) if(MITK_USE_${proj}) set(MITK_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory") mark_as_advanced(MITK_${proj}_DIR) if(MITK_${proj}_DIR) list(APPEND additional_mitk_cmakevars "-D${proj}_DIR:PATH=${MITK_${proj}_DIR}") endif() endif() endforeach() set(MITK_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory") mark_as_advanced(MITK_BOOST_ROOT) if(MITK_BOOST_ROOT) list(APPEND additional_mitk_cmakevars "-DBOOST_ROOT:PATH=${MITK_BOOST_ROOT}") endif() set(MITK_SOURCE_DIR "" CACHE PATH "MITK source code location. If empty, MITK will be cloned from MITK_GIT_REPOSITORY") set(MITK_GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git" CACHE STRING "The git repository for cloning MITK") set(MITK_GIT_TAG "origin/master" CACHE STRING "The git tag/hash to be used when cloning from MITK_GIT_REPOSITORY") mark_as_advanced(MITK_SOURCE_DIR MITK_GIT_REPOSITORY MITK_GIT_TAG) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(mitk_boolean_args) foreach(mitk_cmake_arg ${mitk_cmake_boolean_args}) list(APPEND mitk_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}}) endforeach() #----------------------------------------------------------------------------- # Additional MITK CMake variables #----------------------------------------------------------------------------- if(MITK_USE_Qt5) list(APPEND additional_mitk_cmakevars "-DCMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH}") endif() if(MITK_USE_CTK) list(APPEND additional_mitk_cmakevars "-DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE}") endif() if(MITK_INITIAL_CACHE_FILE) list(APPEND additional_mitk_cmakevars "-DMITK_INITIAL_CACHE_FILE:INTERNAL=${MITK_INITIAL_CACHE_FILE}") endif() if(MITK_USE_SUPERBUILD) set(MITK_BINARY_DIR ${proj}-superbuild) else() set(MITK_BINARY_DIR ${proj}-build) endif() set(proj_DEPENDENCIES) set(MITK_DEPENDS ${proj}) # Configure the MITK souce code location if(NOT MITK_SOURCE_DIR) set(mitk_source_location SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} GIT_REPOSITORY ${MITK_GIT_REPOSITORY} GIT_TAG ${MITK_GIT_TAG} ) else() set(mitk_source_location SOURCE_DIR ${MITK_SOURCE_DIR} ) endif() ExternalProject_Add(${proj} ${mitk_source_location} BINARY_DIR ${MITK_BINARY_DIR} PREFIX ${proj}${ep_suffix} INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${mitk_boolean_args} ${additional_mitk_cmakevars} -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_TESTING:BOOL=${MITK_BUILD_TESTING} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) if(MITK_USE_SUPERBUILD) set(MITK_DIR "${CMAKE_CURRENT_BINARY_DIR}/${MITK_BINARY_DIR}/MITK-build") else() set(MITK_DIR "${CMAKE_CURRENT_BINARY_DIR}/${MITK_BINARY_DIR}") endif() else() # The project is provided using MITK_DIR, nevertheless since other # projects may depend on MITK, let's add an 'empty' one MacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") # Further, do some sanity checks in the case of a pre-built MITK set(my_itk_dir ${ITK_DIR}) set(my_vtk_dir ${VTK_DIR}) find_package(MITK REQUIRED) if(my_itk_dir AND NOT my_itk_dir STREQUAL ${ITK_DIR}) message(FATAL_ERROR "ITK packages do not match:\n ${MY_PROJECT_NAME}: ${my_itk_dir}\n MITK: ${ITK_DIR}") endif() if(my_vtk_dir AND NOT my_vtk_dir STREQUAL ${VTK_DIR}) message(FATAL_ERROR "VTK packages do not match:\n ${MY_PROJECT_NAME}: ${my_vtk_dir}\n MITK: ${VTK_DIR}") endif() endif() diff --git a/CMake/PackageDepends/MITK_Boost_Config.cmake b/CMake/PackageDepends/MITK_Boost_Config.cmake index 04243ce630..7275754c8a 100644 --- a/CMake/PackageDepends/MITK_Boost_Config.cmake +++ b/CMake/PackageDepends/MITK_Boost_Config.cmake @@ -1,15 +1,15 @@ -set(Boost_ADDITIONAL_VERSIONS "1.78.0" "1.78") +set(Boost_ADDITIONAL_VERSIONS "1.80.0" "1.80") find_package(Boost REQUIRED COMPONENTS ${Boost_REQUIRED_COMPONENTS_BY_MODULE}) if(Boost_REQUIRED_COMPONENTS_BY_MODULE) foreach(boost_component ${Boost_REQUIRED_COMPONENTS_BY_MODULE}) list(APPEND ALL_LIBRARIES "Boost::${boost_component}") endforeach() endif() list(APPEND ALL_LIBRARIES "Boost::boost") if(MSVC) list(APPEND ALL_LIBRARIES "Boost::dynamic_linking" "bcrypt") endif() diff --git a/CMake/PackageDepends/MITK_DCMTK_Config.cmake b/CMake/PackageDepends/MITK_DCMTK_Config.cmake index c331c55e9a..dc4d5610b7 100644 --- a/CMake/PackageDepends/MITK_DCMTK_Config.cmake +++ b/CMake/PackageDepends/MITK_DCMTK_Config.cmake @@ -1,10 +1,10 @@ -if(NOT WIN32 AND NOT APPLE) - set(MISSING_LIBS_REQUIRED_BY_DCMTK tiff z) -endif() +foreach(dcmtk_component ${DCMTK_REQUIRED_COMPONENTS_BY_MODULE}) + set(dcmtk_component "DCMTK::${dcmtk_component}") + list(APPEND _dcmtk_required_components_by_module ${dcmtk_component}) +endforeach() -if(NOT DCMTK_FOUND) - find_package(DCMTK REQUIRED) -endif() +find_package(DCMTK COMPONENTS ${_dcmtk_required_components_by_module} REQUIRED) -list(APPEND ALL_INCLUDE_DIRECTORIES ${DCMTK_INCLUDE_DIRS}) -list(APPEND ALL_LIBRARIES ${DCMTK_LIBRARIES} ${MISSING_LIBS_REQUIRED_BY_DCMTK}) +foreach(dcmtk_component ${_dcmtk_required_components_by_module}) + list(APPEND ALL_LIBRARIES ${dcmtk_component}) +endforeach() diff --git a/CMake/PackageDepends/MITK_GDCM_Config.cmake b/CMake/PackageDepends/MITK_GDCM_Config.cmake deleted file mode 100644 index 3a85869601..0000000000 --- a/CMake/PackageDepends/MITK_GDCM_Config.cmake +++ /dev/null @@ -1,10 +0,0 @@ -foreach(gdcm_component ${GDCM_REQUIRED_COMPONENTS_BY_MODULE}) - if(NOT gdcm_component MATCHES "^gdcm") - set(gdcm_component "gdcm${gdcm_component}") - endif() - list(APPEND _gdcm_required_components_by_module ${gdcm_component}) -endforeach() - -find_package(GDCM COMPONENTS ${_gdcm_required_components_by_module} REQUIRED) - -list(APPEND ALL_LIBRARIES ${_gdcm_required_components_by_module}) diff --git a/CMake/PackageDepends/MITK_OpenCV_Config.cmake b/CMake/PackageDepends/MITK_OpenCV_Config.cmake index e8e59a903c..32b3c5888a 100644 --- a/CMake/PackageDepends/MITK_OpenCV_Config.cmake +++ b/CMake/PackageDepends/MITK_OpenCV_Config.cmake @@ -1,7 +1,12 @@ -list(APPEND ALL_LIBRARIES ${OpenCV_LIBS}) -list(APPEND ALL_INCLUDE_DIRECTORIES ${OpenCV_INCLUDE_DIRS}) +foreach(opencv_module ${OpenCV_REQUIRED_COMPONENTS_BY_MODULE}) + if(NOT opencv_module MATCHES "^opencv_") + set(opencv_module "opencv_${opencv_module}") + endif() + list(APPEND _opencv_required_components_by_module ${opencv_module}) +endforeach() -# adding option for videoinput library on windows (for directshow based frame grabbing) -if(WIN32) - option(MITK_USE_videoInput "Use videoInput (DirectShow wrapper) library" OFF) -endif(WIN32) +find_package(OpenCV COMPONENTS ${_opencv_required_components_by_module} REQUIRED) + +foreach(opencv_module ${_opencv_required_components_by_module}) + list(APPEND ALL_LIBRARIES ${opencv_module}) +endforeach() diff --git a/CMake/mitkFunctionCreateBlueBerryApplication.cmake b/CMake/mitkFunctionCreateBlueBerryApplication.cmake index 7c1b5a730e..ebbcaaade2 100644 --- a/CMake/mitkFunctionCreateBlueBerryApplication.cmake +++ b/CMake/mitkFunctionCreateBlueBerryApplication.cmake @@ -1,235 +1,235 @@ #! #! Create a BlueBerry application. #! #! \brief This function will create a BlueBerry application together with all #! necessary provisioning and configuration data and install support. #! #! \param NAME (required) The name of the executable. #! \param DESCRIPTION (optional) A human-readable description of your application. #! The usage depends on the CPack generator (on Windows, this is a descriptive #! text for the created shortcuts). #! \param SOURCES (optional) A list of source files to compile into your executable. Defaults #! to .cpp. #! \param PLUGINS (optional) A list of required plug-ins. Defaults to all known plug-ins. #! \param EXCLUDE_PLUGINS (optional) A list of plug-ins which should not be used. Mainly #! useful if PLUGINS was not used. #! \param LINK_LIBRARIES A list of libraries to be linked with the executable. #! \param LIBRARY_DIRS A list of directories to pass through to MITK_INSTALL_TARGETS #! \param NO_PROVISIONING (option) Do not create provisioning files. #! \param NO_INSTALL (option) Do not install this executable #! #! Assuming that there exists a file called MyApp.cpp, an example call looks like: #! \code #! mitkFunctionCreateBlueBerryApplication( #! NAME MyApp #! DESCRIPTION "MyApp - New ways to explore medical data" #! EXCLUDE_PLUGINS org.mitk.gui.qt.extapplication #! ) #! \endcode #! function(mitkFunctionCreateBlueBerryApplication) cmake_parse_arguments(_APP "NO_PROVISIONING;NO_INSTALL" "NAME;DESCRIPTION" "SOURCES;PLUGINS;EXCLUDE_PLUGINS;LINK_LIBRARIES;LIBRARY_DIRS" ${ARGN}) if(NOT _APP_NAME) message(FATAL_ERROR "NAME argument cannot be empty.") endif() if(NOT _APP_SOURCES) set(_APP_SOURCES ${_APP_NAME}.cpp) endif() if(NOT _APP_PLUGINS) ctkFunctionGetAllPluginTargets(_APP_PLUGINS) else() set(_plugins ${_APP_PLUGINS}) set(_APP_PLUGINS) foreach(_plugin ${_plugins}) string(REPLACE "." "_" _plugin_target ${_plugin}) list(APPEND _APP_PLUGINS ${_plugin_target}) endforeach() # get all plug-in dependencies ctkFunctionGetPluginDependencies(_plugin_deps PLUGINS ${_APP_PLUGINS} ALL) # add the dependencies to the list of application plug-ins list(APPEND _APP_PLUGINS ${_plugin_deps}) endif() # ----------------------------------------------------------------------- # Set up include and link dirs for the executable # ----------------------------------------------------------------------- include_directories( ${org_blueberry_core_runtime_INCLUDE_DIRS} ) # ----------------------------------------------------------------------- # Add executable icon (Windows) # ----------------------------------------------------------------------- set(WINDOWS_ICON_RESOURCE_FILE "") if(WIN32) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") set(WINDOWS_ICON_RESOURCE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/icons/${_APP_NAME}.rc") endif() endif() # ----------------------------------------------------------------------- # Create the executable and link libraries # ----------------------------------------------------------------------- set(_app_compile_flags ) if(WIN32) - set(_app_compile_flags "${_app_compile_flags} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN") + set(_app_compile_flags "${_app_compile_flags} -DWIN32_LEAN_AND_MEAN") endif() if(MITK_SHOW_CONSOLE_WINDOW) add_executable(${_APP_NAME} MACOSX_BUNDLE ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) else() add_executable(${_APP_NAME} MACOSX_BUNDLE WIN32 ${_APP_SOURCES} ${WINDOWS_ICON_RESOURCE_FILE}) endif() if(NOT CMAKE_CURRENT_SOURCE_DIR MATCHES "^${CMAKE_SOURCE_DIR}/.*") foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) if("${CMAKE_CURRENT_SOURCE_DIR}/" MATCHES "^${MITK_EXTENSION_DIR}/.*") get_filename_component(MITK_EXTENSION_ROOT_FOLDER "${MITK_EXTENSION_DIR}" NAME) set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_EXTENSION_ROOT_FOLDER}/Applications") break() endif() endforeach() else() set_property(TARGET ${_APP_NAME} PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Applications") endif() mitk_use_modules(TARGET ${_APP_NAME} MODULES MitkAppUtil) set_target_properties(${_APP_NAME} PROPERTIES COMPILE_FLAGS "${_app_compile_flags}") target_link_libraries(${_APP_NAME} PRIVATE org_blueberry_core_runtime ${_APP_LINK_LIBRARIES}) if(WIN32) target_link_libraries(${_APP_NAME} PRIVATE ${QT_QTMAIN_LIBRARY}) endif() if(WIN32 AND MITK_UTF8) mitk_add_manifest(${_APP_NAME}) endif() # ----------------------------------------------------------------------- # Add executable icon and bundle name (Mac) # ----------------------------------------------------------------------- if(APPLE) if( _APP_DESCRIPTION) set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_DESCRIPTION}") else() set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_NAME "${_APP_NAME}") endif() set(icon_name "icon.icns") set(icon_full_path "${CMAKE_CURRENT_SOURCE_DIR}/icons/${icon_name}") if(EXISTS "${icon_full_path}") set_target_properties(${_APP_NAME} PROPERTIES MACOSX_BUNDLE_ICON_FILE "${icon_name}") file(COPY ${icon_full_path} DESTINATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.app/Contents/Resources/") INSTALL (FILES ${icon_full_path} DESTINATION "${_APP_NAME}.app/Contents/Resources/") endif() endif() # ----------------------------------------------------------------------- # Set build time dependencies # ----------------------------------------------------------------------- # This ensures that all enabled plug-ins are up-to-date when the # executable is build. if(_APP_PLUGINS) ctkMacroGetAllProjectTargetLibraries("${_APP_PLUGINS}" _project_plugins) if(_APP_EXCLUDE_PLUGINS AND _project_plugins) set(_exclude_targets) foreach(_exclude_plugin ${_APP_EXCLUDE_PLUGINS}) string(REPLACE "." "_" _exclude_target ${_exclude_plugin}) list(APPEND _exclude_targets ${_exclude_target}) endforeach() list(REMOVE_ITEM _project_plugins ${_exclude_targets}) endif() if(_project_plugins) add_dependencies(${_APP_NAME} ${_project_plugins}) endif() endif() # ----------------------------------------------------------------------- # Additional files needed for the executable # ----------------------------------------------------------------------- if(NOT _APP_NO_PROVISIONING) # Create a provisioning file, listing all plug-ins set(_prov_file "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.provisioning") mitkFunctionCreateProvisioningFile(FILE ${_prov_file} PLUGINS ${_APP_PLUGINS} EXCLUDE_PLUGINS ${_APP_EXCLUDE_PLUGINS} ) endif() # Create a .ini file for initial parameters if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_APP_NAME}.ini") configure_file(${_APP_NAME}.ini ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${_APP_NAME}.ini) endif() # Create batch and VS user files for Windows platforms include(mitkFunctionCreateWindowsBatchScript) if(WIN32) set(template_name "start${_APP_NAME}.bat.in") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${template_name}") foreach(BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript(${template_name} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/start${_APP_NAME}_${BUILD_TYPE}.bat ${BUILD_TYPE}) endforeach() endif() mitkFunctionConfigureVisualStudioUserProjectFile( NAME ${_APP_NAME} ) endif(WIN32) # ----------------------------------------------------------------------- # Install support # ----------------------------------------------------------------------- if(NOT _APP_NO_INSTALL) # This installs all third-party CTK plug-ins mitkFunctionInstallThirdPartyCTKPlugins(${_APP_PLUGINS} EXCLUDE ${_APP_EXCLUDE_PLUGINS}) if(COMMAND BlueBerryApplicationInstallHook) set(_real_app_plugins ${_APP_PLUGINS}) if(_APP_EXCLUDE_PLUGINS) list(REMOVE_ITEM _real_app_plugins ${_APP_EXCLUDE_PLUGINS}) endif() BlueBerryApplicationInstallHook(APP_NAME ${_APP_NAME} PLUGINS ${_real_app_plugins}) endif() # Install the executable MITK_INSTALL_TARGETS(EXECUTABLES ${_APP_NAME} LIBRARY_DIRS ${_APP_LIBRARY_DIRS} GLOB_PLUGINS ) if(NOT _APP_NO_PROVISIONING) # Install the provisioning file mitkFunctionInstallProvisioningFiles(${_prov_file}) endif() # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME "${_APP_NAME}.sh") elseif(WIN32) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledWin32App.bat" DESTINATION "." RENAME "${_APP_NAME}.bat") endif() # Tell cpack the executables that you want in the start menu as links set(MITK_CPACK_PACKAGE_EXECUTABLES ${MITK_CPACK_PACKAGE_EXECUTABLES} "${_APP_NAME};${_APP_DESCRIPTION}" CACHE INTERNAL "Collecting windows shortcuts to executables") endif() endfunction() function(FunctionCreateBlueBerryApplication) message(SEND_ERROR "The function FunctionCreateBlueBerryApplication was renamed to mitkFunctionCreateBlueBerryApplication in MITK 2015.05") endfunction() diff --git a/CMakeExternals/ANN.cmake b/CMakeExternals/ANN.cmake index 25822784e8..b5256cf40c 100644 --- a/CMakeExternals/ANN.cmake +++ b/CMakeExternals/ANN.cmake @@ -1,56 +1,50 @@ #----------------------------------------------------------------------------- # ANN #----------------------------------------------------------------------------- if(MITK_USE_ANN) # Sanity checks if(DEFINED ANN_DIR AND NOT EXISTS ${ANN_DIR}) message(FATAL_ERROR "ANN_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ANN) set(proj_DEPENDENCIES ) set(ANN_DEPENDS ${proj}) if(NOT DEFINED ANN_DIR) set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() - set(patch_cmd - ${CMAKE_COMMAND} -Dproj:STRING=${proj} -Dproj_target:STRING=ann -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake - COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ANN.patch - ) - ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/ann_1.1.2.tar.gz - URL_MD5 7ffaacc7ea79ca39d4958a6378071365 - PATCH_COMMAND ${patch_cmd} + GIT_REPOSITORY https://github.com/MITK/ANN.git + GIT_TAG v1.1.2-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(ANN_DIR ${ep_prefix}/lib/cmake/ANN) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ANN.patch b/CMakeExternals/ANN.patch deleted file mode 100644 index fb191edf81..0000000000 --- a/CMakeExternals/ANN.patch +++ /dev/null @@ -1,148 +0,0 @@ -diff -urNb ann_1.1.2/src/ANN.cpp ANN/src/ANN.cpp ---- ann_1.1.2/src/ANN.cpp 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/ANN.cpp 2022-03-17 21:55:57.011720500 +0100 -@@ -48,9 +48,9 @@ - ANNpoint p, - ANNpoint q) - { -- register int d; -- register ANNcoord diff; -- register ANNcoord dist; -+ int d; -+ ANNcoord diff; -+ ANNcoord dist; - - dist = 0; - for (d = 0; d < dim; d++) { -diff -urNb ann_1.1.2/src/kd_fix_rad_search.cpp ANN/src/kd_fix_rad_search.cpp ---- ann_1.1.2/src/kd_fix_rad_search.cpp 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/kd_fix_rad_search.cpp 2022-03-17 21:56:09.257624400 +0100 -@@ -147,11 +147,11 @@ - - void ANNkd_leaf::ann_FR_search(ANNdist box_dist) - { -- register ANNdist dist; // distance to data point -- register ANNcoord* pp; // data coordinate pointer -- register ANNcoord* qq; // query coordinate pointer -- register ANNcoord t; -- register int d; -+ ANNdist dist; // distance to data point -+ ANNcoord* pp; // data coordinate pointer -+ ANNcoord* qq; // query coordinate pointer -+ ANNcoord t; -+ int d; - - for (int i = 0; i < n_pts; i++) { // check points in bucket - -diff -urNb ann_1.1.2/src/kd_pr_search.cpp ANN/src/kd_pr_search.cpp ---- ann_1.1.2/src/kd_pr_search.cpp 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/kd_pr_search.cpp 2022-03-17 21:56:20.260622500 +0100 -@@ -180,12 +180,12 @@ - - void ANNkd_leaf::ann_pri_search(ANNdist box_dist) - { -- register ANNdist dist; // distance to data point -- register ANNcoord* pp; // data coordinate pointer -- register ANNcoord* qq; // query coordinate pointer -- register ANNdist min_dist; // distance to k-th closest point -- register ANNcoord t; -- register int d; -+ ANNdist dist; // distance to data point -+ ANNcoord* pp; // data coordinate pointer -+ ANNcoord* qq; // query coordinate pointer -+ ANNdist min_dist; // distance to k-th closest point -+ ANNcoord t; -+ int d; - - min_dist = ANNprPointMK->max_key(); // k-th smallest distance so far - -diff -urNb ann_1.1.2/src/kd_search.cpp ANN/src/kd_search.cpp ---- ann_1.1.2/src/kd_search.cpp 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/kd_search.cpp 2022-03-17 21:56:28.132124600 +0100 -@@ -171,12 +171,12 @@ - - void ANNkd_leaf::ann_search(ANNdist box_dist) - { -- register ANNdist dist; // distance to data point -- register ANNcoord* pp; // data coordinate pointer -- register ANNcoord* qq; // query coordinate pointer -- register ANNdist min_dist; // distance to k-th closest point -- register ANNcoord t; -- register int d; -+ ANNdist dist; // distance to data point -+ ANNcoord* pp; // data coordinate pointer -+ ANNcoord* qq; // query coordinate pointer -+ ANNdist min_dist; // distance to k-th closest point -+ ANNcoord t; -+ int d; - - min_dist = ANNkdPointMK->max_key(); // k-th smallest distance so far - -diff -urNb ann_1.1.2/src/kd_util.cpp ANN/src/kd_util.cpp ---- ann_1.1.2/src/kd_util.cpp 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/kd_util.cpp 2022-03-17 21:56:34.316330300 +0100 -@@ -127,10 +127,10 @@ - const ANNpoint hi, // high point of box - int dim) // dimension of space - { -- register ANNdist dist = 0.0; // sum of squared distances -- register ANNdist t; -+ ANNdist dist = 0.0; // sum of squared distances -+ ANNdist t; - -- for (register int d = 0; d < dim; d++) { -+ for (int d = 0; d < dim; d++) { - if (q[d] < lo[d]) { // q is left of box - t = ANNdist(lo[d]) - ANNdist(q[d]); - dist = ANN_SUM(dist, ANN_POW(t)); -@@ -238,8 +238,8 @@ - int l = 0; // left end of current subarray - int r = n-1; // right end of current subarray - while (l < r) { -- register int i = (r+l)/2; // select middle as pivot -- register int k; -+ int i = (r+l)/2; // select middle as pivot -+ int k; - - if (PA(i,d) > PA(r,d)) // make sure last > pivot - PASWAP(i,r) -diff -urNb ann_1.1.2/src/pr_queue.h ANN/src/pr_queue.h ---- ann_1.1.2/src/pr_queue.h 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/pr_queue.h 2022-03-17 21:56:44.266327900 +0100 -@@ -86,9 +86,9 @@ - PQinfo inf) // item info - { - if (++n > max_size) annError("Priority queue overflow.", ANNabort); -- register int r = n; -+ int r = n; - while (r > 1) { // sift up new item -- register int p = r/2; -+ int p = r/2; - ANN_FLOP(1) // increment floating ops - if (pq[p].key <= kv) // in proper order - break; -@@ -105,9 +105,9 @@ - { - kv = pq[1].key; // key of min item - inf = pq[1].info; // information of min item -- register PQkey kn = pq[n--].key;// last item in queue -- register int p = 1; // p points to item out of position -- register int r = p<<1; // left child of p -+ PQkey kn = pq[n--].key;// last item in queue -+ int p = 1; // p points to item out of position -+ int r = p<<1; // left child of p - while (r <= n) { // while r is still within the heap - ANN_FLOP(2) // increment floating ops - // set r to smaller child of p -diff -urNb ann_1.1.2/src/pr_queue_k.h ANN/src/pr_queue_k.h ---- ann_1.1.2/src/pr_queue_k.h 2010-01-28 05:40:01.000000000 +0100 -+++ ANN/src/pr_queue_k.h 2022-03-17 21:56:55.450345900 +0100 -@@ -100,7 +100,7 @@ - PQKkey kv, // key value - PQKinfo inf) // item info - { -- register int i; -+ int i; - // slide larger values up - for (i = n; i > 0; i--) { - if (mk[i-1].key > kv) diff --git a/CMakeExternals/ANNCMakeLists.txt b/CMakeExternals/ANNCMakeLists.txt deleted file mode 100644 index b65ec9384e..0000000000 --- a/CMakeExternals/ANNCMakeLists.txt +++ /dev/null @@ -1,80 +0,0 @@ -cmake_minimum_required(VERSION 3.1) - -project(ANN) - -set(${PROJECT_NAME}_MAJOR_VERSION 1) -set(${PROJECT_NAME}_MINOR_VERSION 1) -set(${PROJECT_NAME}_PATCH_VERSION 2) -set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) - -set(ANN_HEADERS - include/ANN/ANN.h - include/ANN/ANNperf.h - include/ANN/ANNx.h -) - -set(ANN_SOURCES - src/ANN.cpp - src/bd_fix_rad_search.cpp - src/bd_pr_search.cpp - src/bd_search.cpp - src/bd_tree.cpp - src/brute.cpp - src/kd_dump.cpp - src/kd_fix_rad_search.cpp - src/kd_pr_search.cpp - src/kd_search.cpp - src/kd_split.cpp - src/kd_tree.cpp - src/kd_util.cpp - src/perf.cpp -) - -add_library(ann SHARED ${ANN_HEADERS} ${ANN_SOURCES}) -target_include_directories(ann - PUBLIC "$" - "$" -) -target_compile_definitions(ann PRIVATE $<$:DLL_EXPORTS>) -set_target_properties(ann PROPERTIES - SOVERSION ${${PROJECT_NAME}_VERSION}) - -set(${PROJECT_NAME}_LIBRARIES ann) - -# Install support - -install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin -) -install(FILES ${ANN_HEADERS} - DESTINATION include/${PROJECT_NAME} -) - -# Config files -configure_file( - ${PROJECT_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - @ONLY -) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - @ONLY -) - -export(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake -) - -set(config_package_location lib/cmake/${PROJECT_NAME}) -install(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${PROJECT_NAME}Targets.cmake - DESTINATION ${config_package_location} -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION ${config_package_location} -) diff --git a/CMakeExternals/Boost.cmake b/CMakeExternals/Boost.cmake index 9c086d7ef2..dcebc7c38b 100644 --- a/CMakeExternals/Boost.cmake +++ b/CMakeExternals/Boost.cmake @@ -1,342 +1,343 @@ #----------------------------------------------------------------------------- # Boost #----------------------------------------------------------------------------- include(mitkFunctionGetMSVCVersion) #[[ Sanity checks ]] if(DEFINED BOOST_ROOT AND NOT EXISTS ${BOOST_ROOT}) message(FATAL_ERROR "BOOST_ROOT variable is defined but corresponds to non-existing directory") endif() string(REPLACE "^^" ";" MITK_USE_Boost_LIBRARIES "${MITK_USE_Boost_LIBRARIES}") set(proj Boost) set(proj_DEPENDENCIES ) set(Boost_DEPENDS ${proj}) if(NOT DEFINED BOOST_ROOT AND NOT MITK_USE_SYSTEM_Boost) #[[ Reset variables. ]] set(patch_cmd "") set(configure_cmd "") set(install_cmd "") set(BOOST_ROOT ${ep_prefix}) + set(Boost_DIR "${BOOST_ROOT}/lib/cmake/Boost-1.80.0") if(WIN32) set(BOOST_LIBRARYDIR "${BOOST_ROOT}/lib") endif() #[[ If you update Boost, make sure that the FindBoost module of the minimum required version of CMake supports the new version of Boost. In case you are using a higher version of CMake, download at least the source code of the minimum required version of CMake to look into the right version of the FindBoost module: /share/cmake-/Modules/FindBoost.cmake Search for a list called _Boost_KNOWN_VERSIONS. If the new version is not included in this list, you have three options: * Update the minimum required version of CMake. This may require adaptions of other parts of our CMake scripts and has the most impact on other MITK developers. Yet this is the safest and cleanest option. * Set Boost_ADDITIONAL_VERSIONS (see the documentation of the FindBoost module). As Boost libraries and dependencies between them are hard-coded in the FindBoost module only for known versions, this may cause trouble for other MITK developers relying on new components of Boost or components with changed dependencies. * Copy a newer version of the FindBoost module into our CMake directory. Our CMake directory has a higher precedence than the default CMake module directory. Doublecheck if the minimum required version of CMake is able to process the newer version of the FindBoost module. Also, DO NOT FORGET to mention this option right above the call of cmake_minimum_required() in the top-level CMakeLists.txt file AND in this file right above the set(url) command below so if we update the minimum required version of CMake or use another option in the future, we do not forget to remove our copy of the FindBoost module again. ]] - set(url "${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_78_0_b1.tar.gz") - set(md5 bbaa634603e3789d7dd0c21d0bdf4f09) + set(url "${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/boost_1_80_0.tar.gz") + set(md5 077f074743ea7b0cb49c6ed43953ae95) if(MITK_USE_Boost_LIBRARIES) #[[ Boost has a two-step build process. In the first step, a bootstrap script is called to build b2, an executable that is used to actually build Boost in the second step. The bootstrap script expects a toolset (compiler) argument that is used to build the b2 executable. The scripts and their expected argument format differ between Windows and Unix. ]] if(WIN32) mitkFunctionGetMSVCVersion() if(VISUAL_STUDIO_VERSION_MINOR EQUAL 0) #[[ Use just the major version in the toolset name. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 20) #[[ Assume Visual Studio 2017. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}1) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 30) #[[ Assume Visual Studio 2019. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}2) elseif(VISUAL_STUDIO_VERSION_MAJOR EQUAL 14 AND VISUAL_STUDIO_VERSION_MINOR LESS 40) #[[ Assume Visual Studio 2022. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}3) else() #[[ Fallback to the generic case. Be prepared to add another elseif branch above for future versions of Visual Studio. ]] set(bootstrap_args vc${VISUAL_STUDIO_VERSION_MAJOR}) endif() else() #[[ We support GCC and Clang on Unix. On macOS, the toolset must be set to clang. The actual compiler for all of these toolkits is set further below, after the bootstrap script but before b2. ]] if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) set(toolset gcc) elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR APPLE) set(toolset clang) endif() if(toolset) set(bootstrap_args --with-toolset=${toolset}) endif() #[[ At least give it a shot if the toolset is something else and let the bootstrap script decide on the toolset by not passing any argument. ]] endif() #[[ The call of b2 is more complex. b2 arguments are grouped into options and properties. Options follow the standard format for arguments while properties are plain key-value pairs. ]] set(b2_options --build-dir= --stagedir= --ignore-site-config #[[ Build independent of any site.config file ]] -q #[[ Stop at first error ]] ) if(APPLE AND CMAKE_OSX_SYSROOT) #[[ Specify the macOS platform SDK to be used. ]] list(APPEND b2_options --sysroot=${CMAKE_OSX_SYSROOT}) endif() foreach(lib ${MITK_USE_Boost_LIBRARIES}) list(APPEND b2_options --with-${lib}) endforeach() set(b2_properties threading=multi runtime-link=shared "cxxflags=${MITK_CXX${MITK_CXX_STANDARD}_FLAG} ${CMAKE_CXX_FLAGS}" ) if(CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND b2_properties address-model=64) else() list(APPEND b2_properties address-model=32) endif() if(BUILD_SHARED_LIBS) list(APPEND b2_properties link=shared) else() list(APPEND b2_properties link=static) endif() list(APPEND b2_properties "\ $<$:variant=debug>\ $<$:variant=release>\ $<$:variant=release>\ $<$:variant=release>") if(WIN32) set(bootstrap_cmd if not exist b2.exe \( call bootstrap.bat ${bootstrap_args} \)) set(b2_cmd b2 ${b2_options} ${b2_properties} stage) else() set(bootstrap_cmd #[[ test -e ./b2 || ]] ./bootstrap.sh ${bootstrap_args}) set(b2_cmd ./b2 ${b2_options} ${b2_properties} stage) #[[ We already told Boost if we want to use GCC or Clang but so far we were not able to specify the exact same compiler we set in CMake when configuring the MITK superbuild for the first time. For example, this can be different from the system default when multiple versions of the same compiler are installed at the same time. The bootstrap script creates a configuration file for b2 that should be modified if necessary before b2 is called. We look for a line like using gcc ; and replace it with something more specific like using gcc : : /usr/bin/gcc-7.3 ; We use the stream editor sed for the replacement but since macOS is based on BSD Unix, we use the limited but portable BSD syntax instead of the more powerful GNU syntax. We also use | instead of the more commonly used / separator for sed because the replacement contains slashes. 2021/06/15: The custom project-config.jam does not work well with SDK paths on macOS anymore, so we use a custom project-config.jam only on Linux for now. ]] if(toolset AND NOT APPLE) set(configure_cmd sed -i.backup "\ s|\ using[[:space:]][[:space:]]*${toolset}[[:space:]]*$|\ using ${toolset} : : ${CMAKE_CXX_COMPILER} $|\ g" /project-config.jam ) endif() endif() endif() if(WIN32) set(dummy_cmd cd .) else() set(dummy_cmd true) #[[ "cd ." does not work reliably ]] endif() if(NOT patch_cmd) set(patch_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(NOT configure_cmd) set(configure_cmd ${dummy_cmd}) #[[ Do nothing ]] endif() if(WIN32) set(install_cmd if not exist $ \( ${CMAKE_COMMAND} -E copy_directory /boost /include/boost \) ) else() set(install_cmd # test -e /include/boost/config.hpp || ${CMAKE_COMMAND} -E copy_directory /boost /include/boost ) endif() ExternalProject_Add(${proj} URL ${url} URL_MD5 ${md5} PATCH_COMMAND ${patch_cmd} CONFIGURE_COMMAND ${configure_cmd} BUILD_COMMAND "" INSTALL_COMMAND ${install_cmd} ) ExternalProject_Add_Step(${proj} bootstrap COMMAND ${bootstrap_cmd} DEPENDEES patch DEPENDERS configure WORKING_DIRECTORY ) ExternalProject_Add_Step(${proj} b2 COMMAND ${b2_cmd} DEPENDEES bootstrap DEPENDERS build WORKING_DIRECTORY ) if(WIN32) #[[ Reuse already extracted files. ]] set(stamp_dir ${ep_prefix}/src/Boost-stamp) configure_file( ${CMAKE_CURRENT_LIST_DIR}/extract-Boost.replacement.cmake ${stamp_dir}/extract-Boost.replacement.cmake COPYONLY) ExternalProject_Add_Step(${proj} pre_download COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-pre_download.cmake DEPENDEES mkdir DEPENDERS download WORKING_DIRECTORY ${stamp_dir} ) endif() set(install_manifest_dependees install) if(MITK_USE_Boost_LIBRARIES) if(WIN32) #[[ Move DLLs from lib to bin directory. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-WIN32.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) elseif(APPLE) #[[ Boost does not follow the common practice of either using rpath or absolute paths for referencing dependencies. We have to use the install_name_tool to fix this. ]] ExternalProject_Add_Step(${proj} post_install COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-post_install-APPLE.cmake DEPENDEES install WORKING_DIRECTORY /lib ) set(install_manifest_dependees post_install) endif() endif() ExternalProject_Add_Step(${proj} install_manifest COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/Boost-install_manifest.cmake DEPENDEES ${install_manifest_dependees} WORKING_DIRECTORY ${ep_prefix} ) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index ed64006736..a14e888731 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,100 +1,102 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES DCMTK) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) - set(revision_tag "7210c5bc") - set(ctk_optional_cache_args ) if(MITK_USE_Python3) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF "-DPYTHON_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIRS}" "-DPYTHON_LIBRARY:FILEPATH=${Python3_LIBRARY_RELEASE}" ) else() list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=OFF -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=d ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND ctk_optional_cache_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() FOREACH(type RUNTIME ARCHIVE LIBRARY) IF(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) LIST(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) ENDIF() ENDFOREACH() mitk_query_custom_ep_vars() + set(pythonqt_location_args + "-DPythonQt_GIT_REPOSITORY:STRING=https://github.com/MITK/PythonQt.git" + -DPythonQt_REVISION_TAG:STRING=patched-10-patched + ) + ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - GIT_REPOSITORY https://github.com/commontk/CTK - GIT_TAG ${revision_tag} + GIT_REPOSITORY https://github.com/MITK/CTK.git + GIT_TAG ec816cbb-patched UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} # The CTK PluginFramework cannot cope with # a non-empty CMAKE_DEBUG_POSTFIX for the plugin # libraries yet. -DCMAKE_DEBUG_POSTFIX:STRING= -DCTK_QT_VERSION:STRING=5 -DQt5_DIR=${Qt5_DIR} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DCTK_BUILD_QTDESIGNER_PLUGINS:BOOL=ON -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_LIB_XNAT/Core:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON - -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} - -DPythonQt_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/PythonQt_fae23012.tar.gz + ${pythonqt_location_args} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(CTK_DIR ${binary_dir}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/ChangeHDF5LibsInstallNameForMac.cmake.in b/CMakeExternals/ChangeHDF5LibsInstallNameForMac.cmake.in deleted file mode 100644 index ebe1f89651..0000000000 --- a/CMakeExternals/ChangeHDF5LibsInstallNameForMac.cmake.in +++ /dev/null @@ -1,17 +0,0 @@ -# Get all the shared libraries which are located in the HDF5-install/lib directory -file(GLOB dylibFiles @HDF5_DIR@/lib/*.dylib) - -# For each shared library call the install_name_tool in order to change the install name of the according library -foreach(_dylib ${dylibFiles}) - message("Fixing HDF5 install name for lib: ${_dylib}") - execute_process(COMMAND install_name_tool -id ${_dylib} ${_dylib}) - foreach(_dep_dylib ${dylibFiles}) - get_filename_component(_dep_dylib_name ${_dep_dylib} NAME) - execute_process(COMMAND install_name_tool -change ${_dep_dylib_name} \@loader_path/${_dep_dylib_name} ${_dylib}) - endforeach() -endforeach() - - - - - diff --git a/CMakeExternals/CppUnit.cmake b/CMakeExternals/CppUnit.cmake index 7ebf18c970..6fef5798d4 100644 --- a/CMakeExternals/CppUnit.cmake +++ b/CMakeExternals/CppUnit.cmake @@ -1,49 +1,46 @@ #----------------------------------------------------------------------------- # CppUnit #----------------------------------------------------------------------------- # Sanity checks if(DEFINED CppUnit_DIR AND NOT EXISTS ${CppUnit_DIR}) message(FATAL_ERROR "CppUnit_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CppUnit) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED CppUnit_DIR) set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/cppunit-1.15.1.tar.gz - URL_MD5 9dc669e6145cadd9674873e24943e6dd - PATCH_COMMAND - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/${proj}config.h.cmake /config/config.h.cmake - COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=cppunit -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake + GIT_REPOSITORY https://github.com/MITK/CppUnit.git + GIT_TAG v1.15.1-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}/lib/cmake/CppUnit) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/CppUnitCMakeLists.txt b/CMakeExternals/CppUnitCMakeLists.txt deleted file mode 100644 index 34577fe5f0..0000000000 --- a/CMakeExternals/CppUnitCMakeLists.txt +++ /dev/null @@ -1,223 +0,0 @@ -cmake_minimum_required(VERSION 3.18) - -project(CppUnit) - -set(${PROJECT_NAME}_MAJOR_VERSION 1) -set(${PROJECT_NAME}_MINOR_VERSION 15) -set(${PROJECT_NAME}_PATCH_VERSION 1) -set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) - -# Generates include/cppunit/config-auto.h -# This is originally done by autoconf - -include(CheckIncludeFile) -include(CheckIncludeFileCXX) -include(CheckCXXSourceCompiles) -include(CheckCSourceCompiles) -include(CheckLibraryExists) -include(CheckFunctionExists) - -#Not used == not seen in any *.h *.cpp files -#Not used FUNC_STRING_COMPARE_STRING_FIRST - -check_include_file_cxx(sstream CPPUNIT_HAVE_SSTREAM) -check_include_file_cxx(strstream CPPUNIT_HAVE_STRSTREAM) -set (CMAKE_REQUIRED_DEFINITIONS -DHAVE_STRSTREAM=CPPUNIT_HAVE_STRSTREAM) -check_cxx_source_compiles( -"#ifdef HAVE_STRSTREAM -#include -#else -#include -#endif -int main() { - std::ostrstream message; - message << \"Hello\"; - return 0; -}" CPPUNIT_HAVE_CLASS_STRSTREAM) - -check_include_file_cxx(cmath CPPUNIT_HAVE_CMATH) -#Not used, dld library is obsolete anyway HAVE_DLD -#Not used HAVE_DLERROR -check_include_file(dlfcn.h CPPUNIT_HAVE_DLFCN_H) - -check_c_source_compiles( -"#include -int main() { - return finite(3); -}" CPPUNIT_HAVE_FINITE) - -check_c_source_compiles( -"#include -int main() { - return _finite(3); -}" CPPUNIT_HAVE__FINITE) - -check_include_file_cxx(cxxabi.h CPPUNIT_HAVE_GCC_ABI_DEMANGLE) -#Not used HAVE_INTTYPES_H - -check_c_source_compiles( -"#include -int main() { - return isfinite(3); -}" CPPUNIT_HAVE_ISFINITE) - -check_library_exists(dl dlopen "" CPPUNIT_HAVE_LIBDL) -#Not used HAVE_MEMORY_H - -check_cxx_source_compiles( -"namespace Outer { - namespace Inner { - int i = 0; - } -} -using namespace Outer::Inner; -int main() { - return i; -}" CPPUNIT_HAVE_NAMESPACES) - -check_cxx_source_compiles( -"#include -class Base { -public: - Base() {} - virtual int f() { return 0; } -}; -class Derived : public Base { -public: - Derived() {} - virtual int f() { return 1; } -}; -int main() { - Derived d; - Base * ptr = &d; - return typeid(*ptr) == typeid(Derived); -}" CPPUNIT_HAVE_RTTI) - -check_library_exists(dl shl_load "" CPPUNIT_HAVE_SHL_LOAD) - -#Not used HAVE_STDINT_H -#Not used HAVE_STDLIB_H -#Not used HAVE_STRINGS_H -#Not used HAVE_STRING_H -#Not used HAVE_SYS_STAT_H -#Not used HAVE_SYS_TYPES_H -#Not used HAVE_UNISTD_H -#Not used PACKAGE -#Not used PACKAGE_BUGREPORT -#Not used PACKAGE_NAME -#Not used PACKAGE_STRING -#Not used PACKAGE_TARNAME -#Not used PACKAGE_VERSION -#Not used STDC_HEADERS -check_include_file_cxx(typeinfo CPPUNIT_USE_TYPEINFO_NAME) -#CPPUNIT_VERSION ok - -configure_file(config/config.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/include/cppunit/config-auto.h) -## - - -set(cppunit_SRCS - src/cppunit/AdditionalMessage.cpp - src/cppunit/Asserter.cpp - src/cppunit/BriefTestProgressListener.cpp - src/cppunit/CompilerOutputter.cpp - src/cppunit/DefaultProtector.h - src/cppunit/DefaultProtector.cpp - src/cppunit/DynamicLibraryManager.cpp - src/cppunit/DynamicLibraryManagerException.cpp - src/cppunit/Exception.cpp - src/cppunit/Message.cpp - src/cppunit/PlugInManager.cpp - src/cppunit/PlugInParameters.cpp - src/cppunit/Protector.cpp - src/cppunit/ProtectorChain.h - src/cppunit/ProtectorContext.h - src/cppunit/ProtectorChain.cpp - src/cppunit/RepeatedTest.cpp - src/cppunit/ShlDynamicLibraryManager.cpp - src/cppunit/SourceLine.cpp - src/cppunit/StringTools.cpp - src/cppunit/SynchronizedObject.cpp - src/cppunit/Test.cpp - src/cppunit/TestAssert.cpp - src/cppunit/TestCase.cpp - src/cppunit/TestCaseDecorator.cpp - src/cppunit/TestComposite.cpp - src/cppunit/TestDecorator.cpp - src/cppunit/TestFactoryRegistry.cpp - src/cppunit/TestFailure.cpp - src/cppunit/TestLeaf.cpp - src/cppunit/TestNamer.cpp - src/cppunit/TestPath.cpp - src/cppunit/TestPlugInDefaultImpl.cpp - src/cppunit/TestResult.cpp - src/cppunit/TestResultCollector.cpp - src/cppunit/TestRunner.cpp - src/cppunit/TestSetUp.cpp - src/cppunit/TestSuccessListener.cpp - src/cppunit/TestSuite.cpp - src/cppunit/TestSuiteBuilderContext.cpp - src/cppunit/TextOutputter.cpp - src/cppunit/TextTestProgressListener.cpp - src/cppunit/TextTestResult.cpp - src/cppunit/TextTestRunner.cpp - src/cppunit/TypeInfoHelper.cpp - src/cppunit/UnixDynamicLibraryManager.cpp - src/cppunit/Win32DynamicLibraryManager.cpp - src/cppunit/XmlDocument.cpp - src/cppunit/XmlElement.cpp - src/cppunit/XmlOutputter.cpp - src/cppunit/XmlOutputterHook.cpp -) - -add_library(cppunit SHARED ${cppunit_SRCS}) -target_include_directories(cppunit - PUBLIC "$" - "$" -) -target_compile_definitions(cppunit PRIVATE CPPUNIT_BUILD_DLL) - -set_target_properties(cppunit PROPERTIES - VERSION ${${PROJECT_NAME}_VERSION} - SOVERSION ${${PROJECT_NAME}_VERSION} -) - -set(${PROJECT_NAME}_LIBRARIES cppunit) - -# Install support - -install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin -) -install(DIRECTORY include/cppunit - DESTINATION include -) - -# Config files -configure_file( - ${PROJECT_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - @ONLY -) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - @ONLY -) - -export(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake -) - -set(config_package_location lib/cmake/${PROJECT_NAME}) -install(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${PROJECT_NAME}Targets.cmake - DESTINATION ${config_package_location} -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION ${config_package_location} -) diff --git a/CMakeExternals/CppUnitconfig.h.cmake b/CMakeExternals/CppUnitconfig.h.cmake deleted file mode 100644 index 4d7ba00387..0000000000 --- a/CMakeExternals/CppUnitconfig.h.cmake +++ /dev/null @@ -1,103 +0,0 @@ -/* Inspired by config/config.h.in, config.h.cmake is used by CMake. */ - -/* define if library uses std::string::compare(string,pos,n) */ -//Not used #undef FUNC_STRING_COMPARE_STRING_FIRST - -/* define to 1 if the library defines strstream */ -#cmakedefine01 CPPUNIT_HAVE_CLASS_STRSTREAM - -/* Define to 1 if you have the header file. */ -#cmakedefine01 CPPUNIT_HAVE_CMATH - -/* Define if you have the GNU dld library. */ -//Not used, dld library is obsolete anyway #undef HAVE_DLD - -/* Define to 1 if you have the `dlerror' function. */ -//Not used #undef HAVE_DLERROR - -/* Define to 1 if you have the header file. */ -#cmakedefine01 CPPUNIT_HAVE_DLFCN_H - -/* Define to 1 if you have the `finite' function. */ -#cmakedefine01 CPPUNIT_HAVE_FINITE - -/* Define to 1 if you have the `_finite' function. */ -#cmakedefine01 CPPUNIT_HAVE__FINITE - -/* define to 1 if the compiler supports GCC C ABI name demangling */ -#cmakedefine01 CPPUNIT_HAVE_GCC_ABI_DEMANGLE - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_INTTYPES_H - -/* define if compiler has isfinite */ -#cmakedefine CPPUNIT_HAVE_ISFINITE - -/* Define if you have the libdl library or equivalent. */ -#cmakedefine CPPUNIT_HAVE_LIBDL - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_MEMORY_H - -/* define to 1 if the compiler implements namespaces */ -#cmakedefine01 CPPUNIT_HAVE_NAMESPACES - -/* define to 1 if the compiler supports Run-Time Type Identification */ -#cmakedefine01 CPPUNIT_HAVE_RTTI - -/* Define if you have the shl_load function. */ -#cmakedefine CPPUNIT_HAVE_SHL_LOAD - -/* define to 1 if the compiler has stringstream */ -#cmakedefine01 CPPUNIT_HAVE_SSTREAM - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_STRING_H - -/* Define to 1 if you have the header file. */ -#cmakedefine01 CPPUNIT_HAVE_STRSTREAM - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -//Not used #undef HAVE_UNISTD_H - -/* Name of package */ -//Not used #undef PACKAGE - -/* Define to the address where bug reports for this package should be sent. */ -//Not used #undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -//Not used #undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -//Not used #undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -//Not used #undef PACKAGE_TARNAME - -/* Define to the version of this package. */ -//Not used #undef PACKAGE_VERSION - -/* Define to 1 if you have the ANSI C header files. */ -//Not used #undef STDC_HEADERS - -/* Define to 1 to use type_info::name() for class names */ -#cmakedefine01 CPPUNIT_USE_TYPEINFO_NAME - -/* Version number of package */ -#define CPPUNIT_VERSION @CppUnit_VERSION@ diff --git a/CMakeExternals/DCMTK.cmake b/CMakeExternals/DCMTK.cmake index 5c2cec181a..8564e8ca01 100644 --- a/CMakeExternals/DCMTK.cmake +++ b/CMakeExternals/DCMTK.cmake @@ -1,71 +1,70 @@ #----------------------------------------------------------------------------- # DCMTK #----------------------------------------------------------------------------- if(MITK_USE_DCMTK) # Sanity checks if(DEFINED DCMTK_DIR AND NOT EXISTS ${DCMTK_DIR}) message(FATAL_ERROR "DCMTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMTK) set(proj_DEPENDENCIES ) set(DCMTK_DEPENDS ${proj}) if(NOT DEFINED DCMTK_DIR) if(DCMTK_DICOM_ROOT_ID) set(DCMTK_CXX_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") set(DCMTK_C_FLAGS "${DCMTK_CXX_FLAGS} -DSITE_UID_ROOT=\\\"${DCMTK_DICOM_ROOT_ID}\\\"") endif() set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmtk-3.6.6.tar.gz - URL_MD5 f815879d315b916366a9da71339c7575 + GIT_REPOSITORY https://github.com/DCMTK/dcmtk.git + GIT_TAG DCMTK-3.6.7 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${DCMTK_CXX_FLAGS}" "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${DCMTK_C_FLAGS}" - -DDCMTK_ENABLE_BUILTIN_DICTIONARY:BOOL=ON + -DDCMTK_DEFAULT_DICT:STRING=builtin -DDCMTK_ENABLE_CXX11:BOOL=ON - -DDCMTK_CXX11_FLAGS:STRING=-std=c++${MITK_CXX_STANDARD} -DDCMTK_ENABLE_STL:BOOL=ON -DDCMTK_WITH_DOXYGEN:BOOL=OFF -DDCMTK_WITH_ZLIB:BOOL=OFF # see bug #9894 -DDCMTK_WITH_OPENSSL:BOOL=OFF # see bug #9894 -DDCMTK_WITH_PNG:BOOL=OFF # see bug #9894 -DDCMTK_WITH_TIFF:BOOL=OFF # see bug #9894 -DDCMTK_WITH_XML:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICONV:BOOL=OFF # see bug #9894 -DDCMTK_WITH_ICU:BOOL=OFF # see T26438 ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(DCMTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/Eigen.cmake b/CMakeExternals/Eigen.cmake index d54af9fdd2..a39df68097 100644 --- a/CMakeExternals/Eigen.cmake +++ b/CMakeExternals/Eigen.cmake @@ -1,43 +1,43 @@ #----------------------------------------------------------------------------- # Eigen #----------------------------------------------------------------------------- if(MITK_USE_Eigen) # Sanity checks if(DEFINED Eigen_DIR AND NOT EXISTS ${Eigen_DIR}) message(FATAL_ERROR "Eigen_DIR variable is defined but corresponds to non-existing directory") endif() set(proj Eigen) set(proj_DEPENDENCIES ) set(Eigen_DEPENDS ${proj}) if(NOT DEFINED Eigen_DIR) ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/eigen-3.4.0.tar.gz - URL_MD5 4c527a9171d71a72a9d4186e65bea559 + GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git + GIT_TAG 3.4.0 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} -DBUILD_TESTING:BOOL=ON -DEIGEN_BUILD_PKGCONFIG:BOOL=OFF CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ) set(Eigen_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/EmptyFileForPatching.dummy b/CMakeExternals/EmptyFileForPatching.dummy deleted file mode 100644 index d20bf55bfb..0000000000 --- a/CMakeExternals/EmptyFileForPatching.dummy +++ /dev/null @@ -1 +0,0 @@ -@CONTENTS@ diff --git a/CMakeExternals/ExternalProjectList.cmake b/CMakeExternals/ExternalProjectList.cmake index f35f0a1975..ec089a198d 100644 --- a/CMakeExternals/ExternalProjectList.cmake +++ b/CMakeExternals/ExternalProjectList.cmake @@ -1,33 +1,32 @@ mitkFunctionAddExternalProject(NAME Poco ON COMPONENTS Foundation Net Util XML Zip) mitkFunctionAddExternalProject(NAME DCMTK ON DOC "EXPERIMENTAL, superbuild only: Use DCMTK in MITK") mitkFunctionAddExternalProject(NAME OpenIGTLink OFF) mitkFunctionAddExternalProject(NAME tinyxml2 ON ADVANCED) -mitkFunctionAddExternalProject(NAME GDCM ON ADVANCED) mitkFunctionAddExternalProject(NAME Eigen ON ADVANCED DOC "Use the Eigen library") mitkFunctionAddExternalProject(NAME ANN ON ADVANCED DOC "Use Approximate Nearest Neighbor Library") mitkFunctionAddExternalProject(NAME CppUnit ON ADVANCED DOC "Use CppUnit for unit tests") mitkFunctionAddExternalProject(NAME HDF5 ON ADVANCED) mitkFunctionAddExternalProject(NAME OpenCV OFF) mitkFunctionAddExternalProject(NAME Vigra OFF DEPENDS HDF5) mitkFunctionAddExternalProject(NAME ITK ON NO_CACHE DEPENDS HDF5) mitkFunctionAddExternalProject(NAME VTK ON NO_CACHE) mitkFunctionAddExternalProject(NAME Boost ON NO_CACHE) mitkFunctionAddExternalProject(NAME ZLIB OFF ADVANCED) mitkFunctionAddExternalProject(NAME lz4 ON ADVANCED) mitkFunctionAddExternalProject(NAME cpprestsdk OFF DEPENDS Boost ZLIB ADVANCED) mitkFunctionAddExternalProject(NAME ACVD OFF DOC "Use Approximated Centroidal Voronoi Diagrams") mitkFunctionAddExternalProject(NAME CTK ON DEPENDS Qt5 DCMTK DOC "Use CTK in MITK") mitkFunctionAddExternalProject(NAME DCMQI ON DEPENDS DCMTK ITK DOC "Use dcmqi in MITK") -mitkFunctionAddExternalProject(NAME MatchPoint OFF ADVANCED DEPENDS ITK DOC "Use the MatchPoint translation image registration library") +mitkFunctionAddExternalProject(NAME MatchPoint OFF ADVANCED DEPENDS Boost ITK DOC "Use the MatchPoint translation image registration library") mitkFunctionAddExternalProject(NAME nlohmann_json ON ADVANCED) if(MITK_USE_Qt5) mitkFunctionAddExternalProject(NAME Qwt ON ADVANCED DEPENDS Qt5) endif() if(UNIX AND NOT APPLE) mitkFunctionAddExternalProject(NAME PCRE OFF ADVANCED NO_PACKAGE) mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE DEPENDS PCRE) elseif(WIN32) mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE) endif() diff --git a/CMakeExternals/GDCM.cmake b/CMakeExternals/GDCM.cmake deleted file mode 100644 index 5d09b10c61..0000000000 --- a/CMakeExternals/GDCM.cmake +++ /dev/null @@ -1,71 +0,0 @@ -#----------------------------------------------------------------------------- -# GDCM -#----------------------------------------------------------------------------- - -# Sanity checks -if(DEFINED GDCM_DIR AND NOT EXISTS ${GDCM_DIR}) - message(FATAL_ERROR "GDCM_DIR variable is defined but corresponds to non-existing directory") -endif() - -# Check if an external ITK build tree was specified. -# If yes, use the GDCM from ITK, otherwise ITK will complain -if(ITK_DIR) - find_package(ITK) - if(ITK_GDCM_DIR) - set(GDCM_DIR ${ITK_GDCM_DIR}) - endif() -endif() - - -set(proj GDCM) -set(proj_DEPENDENCIES ) -set(GDCM_DEPENDS ${proj}) - -if(NOT DEFINED GDCM_DIR) - - set(additional_args ) - if(CTEST_USE_LAUNCHERS) - list(APPEND additional_args - "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" - ) - endif() - - # On Mac some assertions fail that prevent reading certain DICOM files. Bug #19995 - if(APPLE) - list(APPEND additional_args - "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} -DNDEBUG" - ) - endif() - - mitk_query_custom_ep_vars() - - ExternalProject_Add(${proj} - LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/gdcm-3.0.10.tar.gz - URL_MD5 28c70d02c2005a8c9d2a5847c8ba3c00 - CMAKE_GENERATOR ${gen} - CMAKE_GENERATOR_PLATFORM ${gen_platform} - CMAKE_ARGS - ${ep_common_args} - ${additional_args} - -DGDCM_BUILD_SHARED_LIBS:BOOL=ON - -DGDCM_BUILD_DOCBOOK_MANPAGES:BOOL=OFF - ${${proj}_CUSTOM_CMAKE_ARGS} - CMAKE_CACHE_ARGS - ${ep_common_cache_args} - ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} - CMAKE_CACHE_DEFAULT_ARGS - ${ep_common_cache_default_args} - ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} - DEPENDS ${proj_DEPENDENCIES} - ) - set(GDCM_DIR ${ep_prefix}) - mitkFunctionInstallExternalCMakeProject(${proj}) - -else() - - mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") - - find_package(GDCM) - -endif() diff --git a/CMakeExternals/GenerateDefaultCMakeBuildSystem.cmake b/CMakeExternals/GenerateDefaultCMakeBuildSystem.cmake deleted file mode 100644 index 0aa7d7df91..0000000000 --- a/CMakeExternals/GenerateDefaultCMakeBuildSystem.cmake +++ /dev/null @@ -1,49 +0,0 @@ -set(ProjConfig.cmake.in " -set(${proj}_LIBRARIES @${proj}_LIBRARIES@) - -if(NOT TARGET ${proj_target}) - include(\"\${CMAKE_CURRENT_LIST_DIR}/${proj}Targets.cmake\") -endif() -") - -set(ProjConfigVersion.cmake.in " -# The created file sets PACKAGE_VERSION_EXACT if the current version string and -# the requested version string are exactly the same and it sets -# PACKAGE_VERSION_COMPATIBLE if the current version major number == requested version major number -# and the current version minor number >= requested version minor number - -set(PACKAGE_VERSION_MAJOR @${proj}_MAJOR_VERSION@) -set(PACKAGE_VERSION_MINOR @${proj}_MINOR_VERSION@) -set(PACKAGE_VERSION_PATCH @${proj}_PATCH_VERSION@) -set(PACKAGE_VERSION \"@${proj}_VERSION@\") - -if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) - set(PACKAGE_VERSION_EXACT TRUE) -else() - set(PACKAGE_VERSION_EXACT FALSE) - if(NOT PACKAGE_VERSION_MAJOR EQUAL PACKAGE_FIND_VERSION_MAJOR) - set(PACKAGE_VERSION_COMPATIBLE FALSE) - elseif(PACKAGE_VERSION_MINOR LESS PACKAGE_FIND_VERSION_MINOR) - set(PACKAGE_VERSION_COMPATIBLE FALSE) - else() - set(PACKAGE_VERSION_CcOMPATIBLE TRUE) - endif() -endif() - -# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: -if(\"\${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"\" OR \"@CMAKE_SIZEOF_VOID_P@\" STREQUAL \"\") - return() -endif() - -# check that the installed version has the same 32/64bit-ness as the one which is currently searching: -if(NOT \"\${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"@CMAKE_SIZEOF_VOID_P@\") - math(EXPR installedBits \"@CMAKE_SIZEOF_VOID_P@ * 8\") - set(PACKAGE_VERSION \"\${PACKAGE_VERSION} (\${installedBits}bit)\") - set(PACKAGE_VERSION_UNSUITABLE TRUE) -endif() -") - -configure_file(${CMAKE_CURRENT_LIST_DIR}/${proj}CMakeLists.txt "${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.txt" COPYONLY) - -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${proj}Config.cmake.in "${ProjConfig.cmake.in}") -file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${proj}ConfigVersion.cmake.in "${ProjConfigVersion.cmake.in}") diff --git a/CMakeExternals/HDF5.cmake b/CMakeExternals/HDF5.cmake index b336c0cd5b..bc0d68bba7 100644 --- a/CMakeExternals/HDF5.cmake +++ b/CMakeExternals/HDF5.cmake @@ -1,59 +1,59 @@ #----------------------------------------------------------------------------- # HDF5 #----------------------------------------------------------------------------- if(MITK_USE_HDF5) # Sanity checks if(DEFINED HDF5_DIR AND NOT EXISTS ${HDF5_DIR}) message(FATAL_ERROR "HDF5_DIR variable is defined but corresponds to non-existing directory") endif() set(proj HDF5) set(proj_DEPENDENCIES ) set(HDF5_DEPENDS ${proj}) if(NOT DEFINED HDF5_DIR) set(additional_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() # We might build static libs with -DBUILD_SHARED_LIBS=0 but this conflicts with # the in ITK integrated version! So we need to go the way with dynamic libs. Too # bad :( This would be fixed by using an external HDF-Installation with ITK/VTK ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/hdf5-1.8.17.tar.gz - URL_MD5 7d572f8f3b798a628b8245af0391a0ca + GIT_REPOSITORY https://github.com/HDFGroup/hdf5.git + GIT_TAG hdf5-1_8_17 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_args} -DHDF5_BUILD_HL_LIB:BOOL=ON -DHDF5_BUILD_CPP_LIB:BOOL=ON -DCMAKE_INSTALL_PREFIX:PATH= CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} install_dir) if(WIN32) set(HDF5_DIR ${install_dir}/cmake/) else() set(HDF5_DIR ${install_dir}/share/cmake) endif() else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif(MITK_USE_HDF5) diff --git a/CMakeExternals/ITK-5.2.1.patch b/CMakeExternals/ITK-5.2.1.patch deleted file mode 100644 index 8ad1cb5184..0000000000 --- a/CMakeExternals/ITK-5.2.1.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/Modules/Video/BridgeOpenCV/include/itkOpenCVVideoIO.h b/Modules/Video/BridgeOpenCV/include/itkOpenCVVideoIO.h -index 1570a182..96a70f17 100644 ---- a/Modules/Video/BridgeOpenCV/include/itkOpenCVVideoIO.h -+++ b/Modules/Video/BridgeOpenCV/include/itkOpenCVVideoIO.h -@@ -168,7 +168,7 @@ public: - const std::vector & dim, - const char * fourCC, - unsigned int nChannels, -- IOComponentType componentType); -+ IOComponentEnum componentType); - - protected: - OpenCVVideoIO(); -diff --git a/Modules/Video/BridgeOpenCV/src/itkOpenCVVideoIO.cxx b/Modules/Video/BridgeOpenCV/src/itkOpenCVVideoIO.cxx -index 7d7db3b8..8ce71c8f 100644 ---- a/Modules/Video/BridgeOpenCV/src/itkOpenCVVideoIO.cxx -+++ b/Modules/Video/BridgeOpenCV/src/itkOpenCVVideoIO.cxx -@@ -436,7 +436,7 @@ OpenCVVideoIO::SetWriterParameters(TemporalRatioType fps, - const std::vector & dim, - const char * fourCC, - unsigned int nChannels, -- IOComponentType componentType) -+ IOComponentEnum componentType) - { - if (this->m_ReaderOpen || this->m_WriterOpen) - { -@@ -444,7 +444,7 @@ OpenCVVideoIO::SetWriterParameters(TemporalRatioType fps, - } - - // Make sure componentType is acceptable (right now we only support char) -- if (componentType != UCHAR) -+ if (componentType != IOComponentEnum::UCHAR) - { - itkExceptionMacro("OpenCV IO only supports writing video with pixels of UCHAR"); - } diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake index b93d27df57..7fee8515d0 100644 --- a/CMakeExternals/ITK.cmake +++ b/CMakeExternals/ITK.cmake @@ -1,89 +1,86 @@ #----------------------------------------------------------------------------- # ITK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED ITK_DIR AND NOT EXISTS ${ITK_DIR}) message(FATAL_ERROR "ITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ITK) -set(proj_DEPENDENCIES GDCM) +set(proj_DEPENDENCIES ) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() set(ITK_DEPENDS ${proj}) if(NOT DEFINED ITK_DIR) set(additional_cmake_args -DUSE_WRAP_ITK:BOOL=OFF) list(APPEND additional_cmake_args -DITKV4_COMPATIBILITY:BOOL=OFF -DITK_LEGACY_REMOVE:BOOL=ON ) if(MITK_USE_OpenCV) list(APPEND additional_cmake_args -DModule_ITKVideoBridgeOpenCV:BOOL=ON -DOpenCV_DIR:PATH=${OpenCV_DIR} "-DCMAKE_CONFIGURATION_TYPES:STRING=Debug$Release" ) endif() # Keep the behaviour of ITK 4.3 which by default turned on ITK Review # see MITK bug #17338 list(APPEND additional_cmake_args -DModule_ITKReview:BOOL=ON -DModule_ITKOpenJPEG:BOOL=ON # for 4.7, the OpenJPEG is needed by review but the variable must be set -DModule_IsotropicWavelets:BOOL=ON ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} UPDATE_COMMAND "" - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/InsightToolkit-5.2.1.tar.gz - URL_MD5 48c1fe49f75fdaa91b31bbf9dda01a42 - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ITK-5.2.1.patch + GIT_REPOSITORY https://github.com/MITK/ITK.git + GIT_TAG v5.2.1-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF - -DITK_USE_SYSTEM_GDCM:BOOL=ON - -DGDCM_DIR:PATH=${GDCM_DIR} -DITK_USE_SYSTEM_HDF5:BOOL=ON -DHDF5_DIR:PATH=${HDF5_DIR} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(ITK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/MatchPoint.cmake b/CMakeExternals/MatchPoint.cmake index 85d8a0556f..d7b84cbc9d 100644 --- a/CMakeExternals/MatchPoint.cmake +++ b/CMakeExternals/MatchPoint.cmake @@ -1,75 +1,74 @@ #----------------------------------------------------------------------------- # MatchPoint #----------------------------------------------------------------------------- if(MITK_USE_MatchPoint) set(MatchPoint_SOURCE_DIR "" CACHE PATH "Location of the MatchPoint source directory") mark_as_advanced(MatchPoint_SOURCE_DIR) # Sanity checks if(DEFINED MatchPoint_DIR AND NOT EXISTS ${MatchPoint_DIR}) message(FATAL_ERROR "MatchPoint_DIR variable is defined but corresponds to non-existing directory") endif() if(NOT MatchPoint_DIR AND MatchPoint_SOURCE_DIR AND NOT EXISTS ${MatchPoint_SOURCE_DIR}) message(FATAL_ERROR "MatchPoint_SOURCE_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MatchPoint) - set(proj_DEPENDENCIES ITK) + set(proj_DEPENDENCIES Boost ITK) set(MatchPoint_DEPENDS ${proj}) if(NOT MatchPoint_DIR) set(additional_cmake_args) if(MITK_USE_OpenCV) list(APPEND additional_cmake_args "-DCMAKE_CONFIGURATION_TYPES:STRING=Debug$Release") endif() if(MatchPoint_SOURCE_DIR) set(download_step SOURCE_DIR ${MatchPoint_SOURCE_DIR}) else() set(download_step - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MatchPoint_rev_f7699d1e.tar.gz - URL_MD5 8a24fbdccd6f18f158f49a0ad4fa3faa + GIT_REPOSITORY https://github.com/MIC-DKFZ/MatchPoint.git + GIT_TAG e63dfdbb ) endif() string(REPLACE "-DBOOST_ALL_DYN_LINK" "" modified_ep_common_args "${ep_common_args}") ExternalProject_Add(${proj} ${download_step} # INSTALL_COMMAND "${CMAKE_COMMAND} -P cmake_install.cmake" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${modified_ep_common_args} ${additional_cmake_args} -DBUILD_TESTING:BOOL=OFF -DITK_DIR:PATH=${ITK_DIR} #/src/ITK-build - -DMAP_USE_SYSTEM_GDCM:BOOL=ON + "-DBoost_DIR:PATH=${Boost_DIR}" -DMAP_USE_SYSTEM_HDF5:BOOL=ON -DMAP_DISABLE_ITK_IO_FACTORY_AUTO_REGISTER:BOOL=ON -DMAP_WRAP_Plastimatch:BOOL=ON -DMAP_BUILD_Ontology:BOOL=ON -DMAP_BUILD_Ontology_simple:BOOL=ON - -DGDCM_DIR:PATH=${GDCM_DIR} -DHDF5_DIR:PATH=${HDF5_DIR} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(${proj}_DIR ${binary_dir}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif(MITK_USE_MatchPoint) diff --git a/CMakeExternals/OpenCV.cmake b/CMakeExternals/OpenCV.cmake index 36aacee775..65d61e2f88 100644 --- a/CMakeExternals/OpenCV.cmake +++ b/CMakeExternals/OpenCV.cmake @@ -1,85 +1,72 @@ #----------------------------------------------------------------------------- # OpenCV #----------------------------------------------------------------------------- if(MITK_USE_OpenCV) # Sanity checks if(DEFINED OpenCV_DIR AND NOT EXISTS ${OpenCV_DIR}) message(FATAL_ERROR "OpenCV_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenCV) set(proj_DEPENDENCIES) set(OpenCV_DEPENDS ${proj}) if(NOT DEFINED OpenCV_DIR) - set(additional_cmake_args - -DBUILD_opencv_java:BOOL=OFF - -DBUILD_opencv_ts:BOOL=OFF - -DBUILD_PERF_TESTS:BOOL=OFF - -DBUILD_opencv_python:BOOL=OFF - -DBUILD_opencv_python3:BOOL=OFF - -DBUILD_opencv_python_bindings_generator:BOOL=OFF - #-DBUILD_NEW_PYTHON_SUPPORT:BOOL=OFF - ) - - if(MITK_USE_Qt5) - list(APPEND additional_cmake_args - -DWITH_QT:BOOL=OFF - -DWITH_QT_OPENGL:BOOL=OFF - -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} - ) - endif() + set(additional_cmake_args) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" - ) + ) endif() mitk_query_custom_ep_vars() - set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/opencv-3.4.16.tar.gz) - set(opencv_url_md5 ce69441a75d3358e22fbfb579fab52a9) - ExternalProject_Add(${proj} + GIT_REPOSITORY https://github.com/opencv/opencv.git + GIT_TAG 4.6.0 LIST_SEPARATOR ${sep} - URL ${opencv_url} - URL_MD5 ${opencv_url_md5} CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} + -DBUILD_JAVA:BOOL=OFF + -DBUILD_opencv_ts:BOOL=OFF + -DBUILD_PERF_TESTS:BOOL=OFF + -DBUILD_opencv_python3:BOOL=OFF + -DBUILD_opencv_python_bindings_generator:BOOL=OFF + -DBUILD_opencv_python_tests:BOOL=OFF + -DWITH_QT:BOOL=OFF -DBUILD_TESTS:BOOL=OFF -DBUILD_DOCS:BOOL=OFF -DBUILD_EXAMPLES:BOOL=OFF - -DBUILD_DOXYGEN_DOCS:BOOL=OFF -DWITH_CUDA:BOOL=OFF -DWITH_VTK:BOOL=OFF -DENABLE_CXX11:BOOL=ON -DWITH_IPP:BOOL=OFF -DBUILD_IPP_IW:BOOL=OFF -DENABLE_PRECOMPILED_HEADERS:BOOL=OFF ${additional_cmake_args} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(OpenCV_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/OpenIGTLink-92bc3d7b.patch b/CMakeExternals/OpenIGTLink-92bc3d7b.patch deleted file mode 100644 index 314b33090e..0000000000 --- a/CMakeExternals/OpenIGTLink-92bc3d7b.patch +++ /dev/null @@ -1,65 +0,0 @@ ---- OpenIGTLink/Source/CMakeLists.txt.original 2017-06-28 12:28:12.000000000 +0200 -+++ OpenIGTLink/Source/CMakeLists.txt 2019-03-31 04:04:46.392945177 +0200 -@@ -71,12 +71,11 @@ - igtlTransformMessage.cxx - ) - --SET(OpenIGTLink_INCLUDE_FILES) --IF( MSVC OR ${CMAKE_GENERATOR} MATCHES "Xcode" ) -- LIST(APPEND OpenIGTLink_INCLUDE_FILES -+SET(OpenIGTLink_INCLUDE_FILES - igtlutil/igtl_header.h - igtlutil/igtl_image.h - igtlutil/igtl_position.h -+ igtlutil/igtl_status.h - igtlutil/igtl_transform.h - igtlutil/igtl_types.h - igtlutil/igtl_util.h -@@ -117,7 +116,6 @@ - igtlWindows.h - igtlCommon.h - ) --ENDIF() - - # Add support for OpenIGTLink version 2 - IF (${OpenIGTLink_PROTOCOL_VERSION} GREATER "1" ) -@@ -150,7 +148,7 @@ - igtlBindMessage.cxx - igtlNDArrayMessage.cxx - ) -- IF( MSVC OR ${CMAKE_GENERATOR} MATCHES "Xcode" ) -+ - LIST(APPEND OpenIGTLink_INCLUDE_FILES - igtlutil/igtl_colortable.h - igtlutil/igtl_imgmeta.h -@@ -180,7 +178,6 @@ - igtlBindMessage.h - igtlNDArrayMessage.h - ) -- ENDIF() - ENDIF() - - # Add support for OpenIGTLink version 3 -@@ -191,14 +188,13 @@ - igtlutil/igtl_command.c - igtlutil/igtl_query.c - ) -- IF( MSVC OR ${CMAKE_GENERATOR} MATCHES "Xcode" ) -+ - LIST(APPEND OpenIGTLink_INCLUDE_FILES - igtlCommandMessage.h - igtlQueryMessage.h - igtlutil/igtl_command.h - igtlutil/igtl_query.h - ) -- ENDIF() - ENDIF() - - ADD_LIBRARY(OpenIGTLink ${OpenIGTLink_SOURCES} ${OpenIGTLink_INCLUDE_FILES}) -@@ -227,4 +223,4 @@ - INSTALL(TARGETS OpenIGTLink EXPORT OpenIGTLink - RUNTIME DESTINATION ${OpenIGTLink_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries - LIBRARY DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT RuntimeLibraries -- ARCHIVE DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT Development) -\ No newline at end of file -+ ARCHIVE DESTINATION ${OpenIGTLink_INSTALL_LIB_DIR} COMPONENT Development) diff --git a/CMakeExternals/OpenIGTLink.cmake b/CMakeExternals/OpenIGTLink.cmake index 62611eafa8..086f2ccce7 100644 --- a/CMakeExternals/OpenIGTLink.cmake +++ b/CMakeExternals/OpenIGTLink.cmake @@ -1,58 +1,57 @@ #----------------------------------------------------------------------------- # OpenIGTLink #----------------------------------------------------------------------------- if(MITK_USE_OpenIGTLink) # Sanity checks if(DEFINED OpenIGTLink_DIR AND NOT EXISTS ${OpenIGTLink_DIR}) message(FATAL_ERROR "OpenIGTLink_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenIGTLink) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED OpenIGTLink_DIR) set(additional_cmake_args ) if(CTEST_USE_LAUNCHERS) set(additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenIGTLink-release-3.0.tar.gz - URL_MD5 0a759655da037f6df2087dd2690d1ae2 - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/OpenIGTLink-92bc3d7b.patch + GIT_REPOSITORY https://github.com/openigtlink/OpenIGTLink.git + GIT_TAG d4eaae93 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DOpenIGTLink_PROTOCOL_VERSION_2:BOOL=ON -DOpenIGTLink_INSTALL_LIB_DIR:STRING=lib -DOpenIGTLink_INSTALL_PACKAGE_DIR:STRING=lib/cmake/OpenIGTLink -DOpenIGTLink_INSTALL_NO_DOCUMENTATION:BOOL=ON ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(OpenIGTLink_DIR "${ep_prefix}/lib/cmake/OpenIGTLink") else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/Poco.cmake b/CMakeExternals/Poco.cmake index dd5d7bcd72..22b544244f 100644 --- a/CMakeExternals/Poco.cmake +++ b/CMakeExternals/Poco.cmake @@ -1,93 +1,103 @@ #----------------------------------------------------------------------------- # Poco #----------------------------------------------------------------------------- if(MITK_USE_Poco) # Sanity checks if(DEFINED Poco_DIR AND NOT EXISTS ${Poco_DIR}) message(FATAL_ERROR "Poco_DIR variable is defined but corresponds to non-existing directory") endif() set(proj Poco) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED ${proj}_DIR) set(additional_cmake_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() set(ssl_args -DENABLE_CRYPTO:BOOL=OFF -DENABLE_NETSSL:BOOL=OFF -DENABLE_NETSSL_WIN:BOOL=OFF ) if(OpenSSL_FOUND) set(ssl_args -DENABLE_CRYPTO:BOOL=ON -DENABLE_NETSSL:BOOL=ON -DFORCE_OPENSSL:BOOL=ON ) if(OPENSSL_ROOT_DIR) list(APPEND ssl_args "-DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR}" ) endif() endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/poco-1.9.0.tar.gz - URL_MD5 1011839033f72de138f0c523c2caa121 + GIT_REPOSITORY https://github.com/pocoproject/poco.git + GIT_TAG poco-1.12.2-release CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} ${ssl_args} - -DENABLE_XML:BOOL=ON - -DENABLE_JSON:BOOL=ON - -DENABLE_MONGODB:BOOL=OFF - -DENABLE_PDF:BOOL=OFF - -DENABLE_UTIL:BOOL=ON - -DENABLE_NET:BOOL=ON + -DENABLE_ACTIVERECORD:BOOL=OFF + -DENABLE_ACTIVERECORD_COMPILER:BOOL=OFF + -DENABLE_APACHECONNECTOR:BOOL=OFF + -DENABLE_CPPPARSER:BOOL=OFF -DENABLE_DATA:BOOL=OFF - -DENABLE_DATA_SQLITE:BOOL=OFF -DENABLE_DATA_MYSQL:BOOL=OFF -DENABLE_DATA_ODBC:BOOL=OFF - -DENABLE_SEVENZIP:BOOL=OFF - -DENABLE_ZIP:BOOL=ON - -DENABLE_APACHECONNECTOR:BOOL=OFF - -DENABLE_CPPPARSER:BOOL=OFF - -DENABLE_POCODOC:BOOL=OFF + -DENABLE_DATA_POSTGRESQL:BOOL=OFF + -DENABLE_DATA_SQLITE:BOOL=OFF + -DENABLE_ENCODINGS:BOOL=OFF + -DENABLE_ENCODINGS_COMPILER:BOOL=OFF + -DENABLE_FOUNDATION:BOOL=ON + -DENABLE_JSON:BOOL=ON + -DENABLE_JWT:BOOL=OFF + -DENABLE_MONGODB:BOOL=OFF + -DENABLE_NET:BOOL=ON -DENABLE_PAGECOMPILER:BOOL=OFF -DENABLE_PAGECOMPILER_FILE2PAGE:BOOL=OFF + -DENABLE_PDF:BOOL=OFF + -DENABLE_POCODOC:BOOL=OFF + -DENABLE_PROMETHEUS:BOOL=OFF + -DENABLE_REDIS:BOOL=OFF + -DENABLE_SEVENZIP:BOOL=OFF + -DENABLE_TESTS:BOOL=OFF + -DENABLE_UTIL:BOOL=ON + -DENABLE_XML:BOOL=ON + -DENABLE_ZIP:BOOL=ON ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/Qwt.cmake b/CMakeExternals/Qwt.cmake index e14f51089a..319d941763 100644 --- a/CMakeExternals/Qwt.cmake +++ b/CMakeExternals/Qwt.cmake @@ -1,61 +1,57 @@ #----------------------------------------------------------------------------- # Qwt #----------------------------------------------------------------------------- if(MITK_USE_Qwt) # Sanity checks if(DEFINED Qwt_DIR AND NOT EXISTS ${Qwt_DIR}) message(FATAL_ERROR "Qwt_DIR variable is defined but corresponds to non-existing directory") endif() set(proj Qwt) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED ${proj}_DIR) - set(patch_cmd ${CMAKE_COMMAND} -Dproj:STRING=${proj} -Dproj_target:STRING=qwt -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake) - set(qt54patch_cmd ${CMAKE_COMMAND} -DTEMPLATE_FILE:FILEPATH=${MITK_SOURCE_DIR}/CMakeExternals/EmptyFileForPatching.dummy -P ${MITK_SOURCE_DIR}/CMakeExternals/PatchQwt-6.1.0.cmake) - set(additional_cmake_args "-DQt5Svg_DIR:PATH=${Qt5Svg_DIR}" "-DQt5OpenGL_DIR:PATH=${Qt5OpenGL_DIR}" "-DQt5PrintSupport_DIR:PATH=${Qt5PrintSupport_DIR}" "-DQt5Concurrent_DIR:PATH=${Qt5Concurrent_DIR}" "-DQt5Designer_DIR:PATH=${Qt5_DIR}Designer" ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/qwt-6.1.5.tar.bz2 - URL_MD5 d65582f99312796ed42c3be3208ed3db - PATCH_COMMAND ${CMAKE_COMMAND} -Dproj=${proj} -Dproj_target:STRING=qwt -P ${CMAKE_CURRENT_LIST_DIR}/GenerateDefaultCMakeBuildSystem.cmake + GIT_REPOSITORY https://github.com/MITK/Qwt.git + GIT_TAG v6.2.0-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} - ${qt_project_args} CMAKE_CACHE_ARGS + -DQWT_BUILD_DESIGNER_PLUGIN:BOOL=OFF ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/QwtCMakeLists.txt b/CMakeExternals/QwtCMakeLists.txt deleted file mode 100644 index 5c91a4acac..0000000000 --- a/CMakeExternals/QwtCMakeLists.txt +++ /dev/null @@ -1,264 +0,0 @@ -cmake_minimum_required(VERSION 3.18) - -project(Qwt) - -set(${PROJECT_NAME}_MAJOR_VERSION 6) -set(${PROJECT_NAME}_MINOR_VERSION 1) -set(${PROJECT_NAME}_PATCH_VERSION 0) -set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) - -set(QWT_MOC_HEADERS - - # General - qwt_dyngrid_layout.h - qwt_magnifier.h - qwt_panner.h - qwt_picker.h - qwt_text_label.h - - # QwtPlot - qwt_abstract_legend.h - qwt_legend.h - qwt_legend_label.h - qwt_plot.h - qwt_plot_renderer.h - qwt_plot_canvas.h - qwt_plot_panner.h - qwt_plot_picker.h - qwt_plot_zoomer.h - qwt_plot_magnifier.h - qwt_sampling_thread.h - qwt_scale_widget.h - - # QwtOpenGL - qwt_plot_glcanvas.h - - # QwtWidgets - qwt_abstract_slider.h - qwt_abstract_scale.h - qwt_analog_clock.h - qwt_compass.h - qwt_counter.h - qwt_dial.h - qwt_knob.h - qwt_slider.h - qwt_thermo.h - qwt_wheel.h -) - -set(QWT_SOURCES - - # General - qwt_abstract_scale_draw.cpp - qwt_clipper.cpp - qwt_color_map.cpp - qwt_column_symbol.cpp - qwt_date.cpp - qwt_date_scale_draw.cpp - qwt_date_scale_engine.cpp - qwt_dyngrid_layout.cpp - qwt_event_pattern.cpp - qwt_graphic.cpp - qwt_interval.cpp - qwt_interval_symbol.cpp - qwt_math.cpp - qwt_magnifier.cpp - qwt_null_paintdevice.cpp - qwt_painter.cpp - qwt_painter_command.cpp - qwt_panner.cpp - qwt_picker.cpp - qwt_picker_machine.cpp - qwt_pixel_matrix.cpp - qwt_point_3d.cpp - qwt_point_polar.cpp - qwt_round_scale_draw.cpp - qwt_scale_div.cpp - qwt_scale_draw.cpp - qwt_scale_map.cpp - qwt_spline.cpp - qwt_scale_engine.cpp - qwt_symbol.cpp - qwt_system_clock.cpp - qwt_text_engine.cpp - qwt_text_label.cpp - qwt_text.cpp - qwt_transform.cpp - qwt_widget_overlay.cpp - - # QwtPlot - qwt_curve_fitter.cpp - qwt_abstract_legend.cpp - qwt_legend.cpp - qwt_legend_data.cpp - qwt_legend_label.cpp - qwt_plot.cpp - qwt_plot_renderer.cpp - qwt_plot_xml.cpp - qwt_plot_axis.cpp - qwt_plot_curve.cpp - qwt_plot_dict.cpp - qwt_plot_directpainter.cpp - qwt_plot_grid.cpp - qwt_plot_histogram.cpp - qwt_plot_item.cpp - qwt_plot_abstract_barchart.cpp - qwt_plot_barchart.cpp - qwt_plot_multi_barchart.cpp - qwt_plot_intervalcurve.cpp - qwt_plot_zoneitem.cpp - qwt_plot_tradingcurve.cpp - qwt_plot_spectrogram.cpp - qwt_plot_spectrocurve.cpp - qwt_plot_scaleitem.cpp - qwt_plot_legenditem.cpp - qwt_plot_seriesitem.cpp - qwt_plot_shapeitem.cpp - qwt_plot_marker.cpp - qwt_plot_textlabel.cpp - qwt_plot_layout.cpp - qwt_plot_canvas.cpp - qwt_plot_panner.cpp - qwt_plot_rasteritem.cpp - qwt_plot_picker.cpp - qwt_plot_zoomer.cpp - qwt_plot_magnifier.cpp - qwt_plot_rescaler.cpp - qwt_point_mapper.cpp - qwt_raster_data.cpp - qwt_matrix_raster_data.cpp - qwt_sampling_thread.cpp - qwt_series_data.cpp - qwt_point_data.cpp - qwt_scale_widget.cpp - - # QwtSvg - qwt_plot_svgitem.cpp - - # QwtOpenGL - qwt_plot_glcanvas.cpp - - # QwtWidgets - qwt_abstract_slider.cpp - qwt_abstract_scale.cpp - qwt_arrow_button.cpp - qwt_analog_clock.cpp - qwt_compass.cpp - qwt_compass_rose.cpp - qwt_counter.cpp - qwt_dial.cpp - qwt_dial_needle.cpp - qwt_knob.cpp - qwt_slider.cpp - qwt_thermo.cpp - qwt_wheel.cpp - -) - -set(_qwt_moc_headers ) -foreach(_header ${QWT_MOC_HEADERS}) - list(APPEND _qwt_moc_headers src/${_header}) -endforeach() - -set(_qwt_sources ) -foreach(_source ${QWT_SOURCES}) - list(APPEND _qwt_sources src/${_source}) -endforeach() - -find_package(Qt5Svg REQUIRED) -find_package(Qt5OpenGL REQUIRED) -find_package(Qt5PrintSupport REQUIRED) -find_package(Qt5Concurrent REQUIRED) - -qt5_wrap_cpp(_qwt_sources ${_qwt_moc_headers}) - -add_library(qwt SHARED ${_qwt_sources}) -target_link_libraries(qwt PUBLIC Qt5::Svg Qt5::OpenGL Qt5::PrintSupport Qt5::Concurrent) - -target_compile_definitions(qwt PUBLIC QWT_DLL PRIVATE QWT_MAKEDLL) -set_target_properties(qwt PROPERTIES - SOVERSION ${${PROJECT_NAME}_VERSION} -) - - -# Build the designer plug-in - -option(QWT_BUILD_DESIGNER_PLUGIN "Build the Qt Designer plugin" ON) - if (QWT_BUILD_DESIGNER_PLUGIN) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) - - set(_qwt_designer_sources - designer/qwt_designer_plotdialog.cpp - designer/qwt_designer_plugin.cpp - ) - - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) - set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) - set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/plugins/designer) - - find_package(Qt5Designer REQUIRED) - include_directories(${Qt5Designer_INCLUDE_DIRS}) - qt5_wrap_cpp(_qwt_designer_sources - designer/qwt_designer_plugin.h - designer/qwt_designer_plotdialog.h - ) - qt5_add_resources(_qwt_designer_sources designer/qwt_designer_plugin.qrc) - - add_library(qwt_designer_plugin SHARED ${_qwt_designer_sources}) - target_link_libraries(qwt_designer_plugin qwt Qt5::Designer) - - set_target_properties(qwt_designer_plugin PROPERTIES - SOVERSION ${${PROJECT_NAME}_VERSION} - COMPILE_DEFINITIONS QWT_DLL) -endif() - -set(${PROJECT_NAME}_LIBRARIES qwt) - -# Install support - -if (QWT_BUILD_DESIGNER_PLUGIN) - install(TARGETS qwt_designer_plugin - RUNTIME DESTINATION plugins/designer - LIBRARY DESTINATION plugins/designer - ) -endif() - -install(TARGETS ${${PROJECT_NAME}_LIBRARIES} EXPORT ${PROJECT_NAME}_TARGETS - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include/${PROJECT_NAME} -) -install(DIRECTORY src/ - DESTINATION include/${PROJECT_NAME} - FILES_MATCHING PATTERN "*.h" -) - -# Config files - -configure_file( - ${PROJECT_NAME}Config.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake - @ONLY -) -configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake - @ONLY -) - -export(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake -) - -set(config_package_location lib/cmake/${PROJECT_NAME}) -install(EXPORT ${PROJECT_NAME}_TARGETS - FILE ${PROJECT_NAME}Targets.cmake - DESTINATION ${config_package_location} -) -install(FILES - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" - DESTINATION ${config_package_location} -) diff --git a/CMakeExternals/SWIG.cmake b/CMakeExternals/SWIG.cmake index eccbfd6aae..62a99606fe 100644 --- a/CMakeExternals/SWIG.cmake +++ b/CMakeExternals/SWIG.cmake @@ -1,72 +1,76 @@ #------------------------------------------------------------ # SWIG (Simple Wrapper Interface Generator) #----------------------------------------------------------- if(MITK_USE_SWIG) if(DEFINED SWIG_DIR AND NOT EXISTS ${SWIG_DIR}) message(FATAL_ERROR "SWIG_DIR variable is defined but corresponds to non-existing directory") endif() - set(SWIG_TARGET_VERSION 3.0.2) + set(SWIG_TARGET_VERSION 4.0.2) set(proj SWIG) if(WIN32) set(proj_DEPENDENCIES) else() set(proj_DEPENDENCIES PCRE) endif() set(SWIG_DEPENDS ${proj}) if(NOT SWIG_DIR) # We don't "install" SWIG in the common install prefix, # since it is only used as a tool during the MITK super-build # to generate the Python wrappings for some projects. # binary SWIG for windows if(WIN32) set(swig_source_dir ${CMAKE_CURRENT_BINARY_DIR}/swigwin-${SWIG_TARGET_VERSION}) # swig.exe available as pre-built binary on Windows: ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/swigwin-${SWIG_TARGET_VERSION}.zip - URL_MD5 "3f18de4fc09ab9abb0d3be37c11fbc8f" + URL_MD5 "009926b512aee9318546bdd4c7eab6f9" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" ) ExternalProject_Get_Property(${proj} source_dir) set(SWIG_DIR ${source_dir}) set(SWIG_EXECUTABLE ${source_dir}/swig.exe) else() # swig uses bison find it by cmake and pass it down find_package(BISON) set(BISON_FLAGS "" CACHE STRING "Flags used by bison") mark_as_advanced( BISON_FLAGS) ExternalProject_add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/swig-${SWIG_TARGET_VERSION}.tar.gz - # Custom install dir for SWIG + URL_MD5 7c3e46cb5af2b469722cafa0d91e127b + # Switching to Git would require additional prerequisites: + # - autotools-dev + # - automake + # GIT_REPOSITORY https://github.com/swig/swig.git + # GIT_TAG v${SWIG_TARGET_VERSION} INSTALL_DIR ${ep_prefix}/src/${proj}-install - URL_MD5 "62f9b0d010cef36a13a010dc530d0d41" CONFIGURE_COMMAND /./configure CC=${CMAKE_C_COMPILER}${CMAKE_C_COMPILER_ARG1} LDFLAGS=${CMAKE_LINKER_FLAGS} ${CMAKE_LINKER_FLAGS_RELEASE} CXX=${CMAKE_CXX_COMPILER}${CMAKE_CXX_COMPILER_ARG1} "--prefix=" "--with-pcre-prefix=${PCRE_DIR}" --without-octave "--with-python=${Python3_EXECUTABLE}" DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} install_dir) set(SWIG_DIR ${install_dir}/share/swig/${SWIG_TARGET_VERSION}) set(SWIG_EXECUTABLE ${install_dir}/bin/swig) endif() else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/VTK.cmake b/CMakeExternals/VTK.cmake index f0c58f66d5..69fa6d4da1 100644 --- a/CMakeExternals/VTK.cmake +++ b/CMakeExternals/VTK.cmake @@ -1,88 +1,85 @@ #----------------------------------------------------------------------------- # VTK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED VTK_DIR AND NOT EXISTS ${VTK_DIR}) message(FATAL_ERROR "VTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj VTK) set(proj_DEPENDENCIES ) set(VTK_DEPENDS ${proj}) -if(MITK_USE_HDF5) - list(APPEND proj_DEPENDENCIES HDF5) -endif() - if(NOT DEFINED VTK_DIR) set(additional_cmake_args ) if(WIN32) list(APPEND additional_cmake_args -DCMAKE_CXX_MP_FLAG:BOOL=ON ) else() list(APPEND additional_cmake_args -DVTK_MODULE_USE_EXTERNAL_VTK_freetype:BOOL=ON ) endif() # Optionally enable memory leak checks for any objects derived from vtkObject. This # will force unit tests to fail if they have any of these memory leaks. option(MITK_VTK_DEBUG_LEAKS OFF) mark_as_advanced(MITK_VTK_DEBUG_LEAKS) list(APPEND additional_cmake_args -DVTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} ) if(MITK_USE_Qt5) list(APPEND additional_cmake_args -DVTK_GROUP_ENABLE_Qt:STRING=YES -DQt5_DIR:PATH=${Qt5_DIR} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/VTK-9.1.0.tar.gz - URL_MD5 96508e51d7c3764cd5aba06fffd9864e + GIT_REPOSITORY https://github.com/Kitware/VTK.git + GIT_TAG v9.1.0 + GIT_SUBMODULES "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} -DOpenGL_GL_PREFERENCE:STRING=LEGACY -DVTK_ENABLE_WRAPPING:BOOL=OFF -DVTK_LEGACY_REMOVE:BOOL=ON -DVTK_MODULE_ENABLE_VTK_TestingRendering:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingContextOpenGL2:STRING=YES -DVTK_MODULE_ENABLE_VTK_RenderingVolumeOpenGL2:STRING=YES -DVTK_MODULE_ENABLE_VTK_GUISupportQtQuick:STRING=NO ${additional_cmake_args} ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) set(VTK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/Vigra.cmake b/CMakeExternals/Vigra.cmake index f79b5ff82c..5b2c4ddd22 100644 --- a/CMakeExternals/Vigra.cmake +++ b/CMakeExternals/Vigra.cmake @@ -1,72 +1,71 @@ #----------------------------------------------------------------------------- # VIGRA #----------------------------------------------------------------------------- if(MITK_USE_Vigra) # Sanity checks if(DEFINED Vigra_DIR AND NOT EXISTS ${Vigra_DIR}) message(FATAL_ERROR "Vigra_DIR variable is defined but corresponds to non-existing directory") endif() if(NOT ${MITK_USE_HDF5}) message(FATAL_ERROR "HDF5 is required for Vigra. Please enable it.") endif() set(proj Vigra) set(proj_DEPENDENCIES HDF5) set(Vigra_DEPENDS ${proj}) # If a mac ports installation is present some imaging-io-libraries may interfere with the vigra build. # Hence, we exclude them here. set(mac_additional_cmake_args) if(APPLE) set(mac_additional_cmake_args -DJPEG_INCLUDE_DIR= -DJPEG_LIBRARY= -DTIFF_INCLUDE_DIR= -DTIFF_LIBRARY= -DPNG_LIBRARY_RELEASE= -DPNG_PNG_INCLUDE_DIR= ) endif() if(NOT DEFINED Vigra_DIR) set(additional_cmake_args ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/vigra-1.10.0-src.tar.gz - URL_MD5 4f963f0be4fcb8b06271c2aa40baa9be - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/Vigra.patch + GIT_REPOSITORY https://github.com/MITK/vigra.git + GIT_TAG Version-1-10-0-patched CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} ${mac_additional_cmake_args} -DAUTOEXEC_TESTS:BOOL=OFF -DWITH_VIGRANUMPY:BOOL=OFF -DHDF5_DIR:PATH=${HDF5_DIR} -DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=TRUE -DCMAKE_INSTALL_PREFIX:PATH= CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(Vigra_DIR ${ep_prefix}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif(MITK_USE_Vigra) diff --git a/CMakeExternals/cpprestsdk.cmake b/CMakeExternals/cpprestsdk.cmake index 93644937b8..ea888903a9 100644 --- a/CMakeExternals/cpprestsdk.cmake +++ b/CMakeExternals/cpprestsdk.cmake @@ -1,39 +1,41 @@ set(proj cpprestsdk) set(proj_DEPENDENCIES Boost ZLIB) if(MITK_USE_${proj}) set(${proj}_DEPENDS ${proj}) if(DEFINED ${proj}_DIR AND NOT EXISTS ${${proj}_DIR}) message(FATAL_ERROR "${proj}_DIR variable is defined but corresponds to non-existing directory!") endif() if(NOT DEFINED ${proj}_DIR) set(cmake_cache_args ${ep_common_cache_args} -DBUILD_SAMPLES:BOOL=OFF -DBUILD_TESTS:BOOL=OFF -DWERROR:BOOL=OFF ) if(OPENSSL_ROOT_DIR) list(APPEND cmake_cache_args -DOPENSSL_ROOT_DIR:PATH=${OPENSSL_ROOT_DIR} ) endif() ExternalProject_Add(${proj} GIT_REPOSITORY https://github.com/microsoft/cpprestsdk.git - GIT_TAG v2.10.16 + GIT_TAG v2.10.18 SOURCE_SUBDIR Release - CMAKE_ARGS ${ep_common_args} + CMAKE_ARGS + "-DBoost_DIR:PATH=${Boost_DIR}" + ${ep_common_args} CMAKE_CACHE_ARGS ${cmake_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/tinyxml2.cmake b/CMakeExternals/tinyxml2.cmake index 8b24f8c184..900956a1b2 100644 --- a/CMakeExternals/tinyxml2.cmake +++ b/CMakeExternals/tinyxml2.cmake @@ -1,52 +1,52 @@ #----------------------------------------------------------------------------- # tinyxml2 #----------------------------------------------------------------------------- # Sanity checks if(DEFINED tinyxml2_DIR AND NOT EXISTS ${tinyxml2_DIR}) message(FATAL_ERROR "tinyxml2_DIR variable is defined but corresponds to non-existing directory") endif() set(proj tinyxml2) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED tinyxml2_DIR) set(additional_cmake_args ) if(WIN32) set(additional_cmake_args -DBUILD_SHARED_LIBS:BOOL=OFF) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/tinyxml2-8.0.0.tar.gz - URL_MD5 5dc535c8b34ee621fe2128f072d275b5 + GIT_REPOSITORY https://github.com/leethomason/tinyxml2.git + GIT_TAG 8.0.0 CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} -DBUILD_TESTING:BOOL=OFF -DBUILD_TESTS:BOOL=OFF CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(${proj}_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 9abcfe07f0..4db599bd2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1436 +1,1436 @@ #[[ 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.04.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") unset(MITK_ABSOLUTE_EXTENSION_DIRS) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_ABSOLUTE_EXTENSION_DIR "${MITK_EXTENSION_DIR}" ABSOLUTE) list(APPEND MITK_ABSOLUTE_EXTENSION_DIRS "${MITK_ABSOLUTE_EXTENSION_DIR}") endforeach() set(MITK_DIR_PLUS_EXTENSION_DIRS "${MITK_SOURCE_DIR}" ${MITK_ABSOLUTE_EXTENSION_DIRS}) #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_ABSOLUTE_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR "${MITK_EXTENSION_DIR}/CMake") if(EXISTS "${MITK_CMAKE_EXTENSION_DIR}") list(APPEND CMAKE_MODULE_PATH "${MITK_CMAKE_EXTENSION_DIR}") endif() endforeach() #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTest) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) include(mitkFunctionAddLibrarySearchPaths) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Check miminum macOS version #----------------------------------------------------------------------------- # The minimum supported macOS version is 10.14. If you use a version less than # 10.14, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE macos_version) if (macos_version VERSION_LESS "10.14") message(WARNING "Detected macOS version \"${macos_version}\" is not supported anymore. Minimum required macOS version is at least 10.14.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.14) message(WARNING "Detected macOS deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required macOS version is at least 10.14.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2017 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.10) message(FATAL_ERROR "Microsoft Visual Studio 2017 or newer required") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 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() 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} -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN -DNOMINMAX") + 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) 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/Modules/CameraCalibration/CMakeLists.txt b/Modules/CameraCalibration/CMakeLists.txt index 361c50a164..bf8e292636 100644 --- a/Modules/CameraCalibration/CMakeLists.txt +++ b/Modules/CameraCalibration/CMakeLists.txt @@ -1,7 +1,7 @@ MITK_CREATE_MODULE( DEPENDS MitkIGT - PACKAGE_DEPENDS PUBLIC OpenCV + PACKAGE_DEPENDS PUBLIC OpenCV|calib3d ) # add testing dir add_subdirectory(Testing) diff --git a/Modules/Core/include/mitkIOUtil.h b/Modules/Core/include/mitkIOUtil.h index 036258e4f6..c774f9b929 100644 --- a/Modules/Core/include/mitkIOUtil.h +++ b/Modules/Core/include/mitkIOUtil.h @@ -1,440 +1,444 @@ /*============================================================================ 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 MITKIOUTIL_H #define MITKIOUTIL_H #include #include #include #include #include #include #include #include #include #include +#if !defined(MITK_WINDOWS_NO_UNDEF) && defined(GetTempPath) + #undef GetTempPath +#endif + namespace us { class ModuleResource; } namespace mitk { class PropertyList; /** * \ingroup IO * * \brief A utility class to load and save data from/to the local file system. * * \see QmitkIOUtil */ class MITKCORE_EXPORT IOUtil { public: /**Struct that containes information regarding the current loading process. (e.g. Path that should be loaded, all found readers for the load path,...). It is set be IOUtil and used to pass information via the option callback in load operations. */ struct MITKCORE_EXPORT LoadInfo { LoadInfo(const std::string &path); std::string m_Path; std::vector m_Output; FileReaderSelector m_ReaderSelector; bool m_Cancel; const PropertyList* m_Properties; }; /**Struct that is the base class for option callbacks used in load operations. The callback is used by IOUtil, if more than one suitable reader was found or the a reader containes options that can be set. The callback allows to change option settings and select the reader that should be used (via loadInfo). */ struct MITKCORE_EXPORT ReaderOptionsFunctorBase { virtual bool operator()(LoadInfo &loadInfo) const = 0; }; struct MITKCORE_EXPORT SaveInfo { SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path); bool operator<(const SaveInfo &other) const; /// The BaseData object to save. const BaseData *m_BaseData; /// Contains a set of IFileWriter objects. FileWriterSelector m_WriterSelector; /// The selected mime-type, used to restrict results from FileWriterSelector. MimeType m_MimeType; /// The path to write the BaseData object to. std::string m_Path; /// Flag indicating if sub-sequent save operations are to be canceled. bool m_Cancel; }; /**Struct that is the base class for option callbacks used in save operations. The callback is used by IOUtil, if more than one suitable writer was found or the a writer containes options that can be set. The callback allows to change option settings and select the writer that should be used (via saveInfo). */ struct MITKCORE_EXPORT WriterOptionsFunctorBase { virtual bool operator()(SaveInfo &saveInfo) const = 0; }; /** * Get the file system path where the running executable is located. * * @return The location of the currently running executable, without the filename. */ static std::string GetProgramPath(); /** * Get the default temporary path. * * @return The default path for temporary data. */ static std::string GetTempPath(); /** * Returns the Directory Seperator for the current OS. * * @return the Directory Seperator for the current OS, i.e. "\\" for Windows and "/" otherwise. */ static char GetDirectorySeparator(); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and returns the name of * the newly create file. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream &tmpStream, const std::string &templateName = "XXXXXX", std::string path = std::string()); /** * Create and open a temporary file. * * This method generates a unique temporary filename from \c templateName, creates * and opens the file using the output stream \c tmpStream and the specified open * mode \c mode and returns the name of the newly create file. The open mode is always * OR'd with std::ios_base::out | std::ios_base::trunc. * * The \c templateName argument must contain six consective 'X' characters ("XXXXXX") * and these are replaced with a string that makes the filename unique. * * The file is created with read and write permissions for owner only. * * @param tmpStream The output stream for writing to the temporary file. * @param mode The open mode for the temporary file stream. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(std::ofstream &tmpStream, std::ios_base::openmode mode, const std::string &templateName = "XXXXXX", std::string path = std::string()); /** * Creates an empty temporary file. * * This method generates a unique temporary filename from \c templateName and creates * this file. * * The file is created with read and write permissions for owner only. * * --- * This version is potentially unsafe because the created temporary file is not kept open * and could be used by another process between calling this method and opening the returned * file path for reading or writing. * --- * * @return The filename of the created temporary file. * @param templateName An optional template for the filename. * @param path An optional path where the temporary file should be created. Defaults * to the default temp path as returned by GetTempPath(). * @throw mitk::Exception if the temporary file could not be created. */ static std::string CreateTemporaryFile(const std::string &templateName = "XXXXXX", std::string path = std::string()); /** * Create a temporary directory. * * This method generates a uniquely named temporary directory from \c templateName. * The last set of six consecutive 'X' characters in \c templateName is replaced * with a string that makes the directory name unique. * * The directory is created with read, write and executable permissions for owner only. * * @param templateName An optional template for the directory name. * @param path An optional path where the temporary directory should be created. Defaults * to the default temp path as returned by GetTempPath(). * @return The filename of the created temporary file. * * @throw mitk::Exception if the temporary directory could not be created. */ static std::string CreateTemporaryDirectory(const std::string &templateName = "XXXXXX", std::string path = std::string()); /** * @brief Load a file into the given DataStorage. * * This method calls Load(const std::vector&, DataStorage&) with a * one-element vector. * * @param path The absolute file name including the file extension. * @param storage A DataStorage object to which the loaded data will be added. * @param optionsCallback Pointer to a callback instance. The callback is used by * the load operation if more the suitable reader was found or the reader has options * that can be set. * @return The set of added DataNode objects. * @throws mitk::Exception if \c path could not be loaded. * * @sa Load(const std::vector&, DataStorage&) */ static DataStorage::SetOfObjects::Pointer Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * @brief Load a file into the given DataStorage given user defined IFileReader::Options. * * This method calls Load(const std::vector&, DataStorage&) with a * one-element vector. * * @param path The absolute file name including the file extension. * @param options IFileReader option instance that should be used if selected reader * has options. * @param storage A DataStorage object to which the loaded data will be added. * @return The set of added DataNode objects. * @throws mitk::Exception if \c path could not be loaded. * * @sa Load(const std::vector&, DataStorage&) */ static DataStorage::SetOfObjects::Pointer Load(const std::string &path, const IFileReader::Options &options, DataStorage &storage); /** * @brief Load a file and return the loaded data. * * This method calls Load(const std::vector&) with a * one-element vector. * * @param path The absolute file name including the file extension. * @param optionsCallback Pointer to a callback instance. The callback is used by * the load operation if more the suitable reader was found or the reader has options * that can be set. * @return The set of added DataNode objects. * @throws mitk::Exception if \c path could not be loaded. * * @sa Load(const std::vector&, DataStorage&) */ static std::vector Load(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback = nullptr); template static typename T::Pointer Load(const std::string& path, const ReaderOptionsFunctorBase *optionsCallback = nullptr) { return dynamic_cast(Load(path, optionsCallback).at(0).GetPointer()); } /** * @brief Load a file and return the loaded data. * * This method calls Load(const std::vector&) with a * one-element vector. * * @param path The absolute file name including the file extension. * @param options IFileReader option instance that should be used if selected reader * has options. * @return The set of added DataNode objects. * @throws mitk::Exception if \c path could not be loaded. * * @sa Load(const std::vector&, DataStorage&) */ static std::vector Load(const std::string &path, const IFileReader::Options &options); template static typename T::Pointer Load(const std::string& path, const IFileReader::Options &options) { return dynamic_cast(Load(path, options).at(0).GetPointer()); } /** * @brief Loads a list of file paths into the given DataStorage. * * If an entry in \c paths cannot be loaded, this method will continue to load * the remaining entries into \c storage and throw an exception afterwards. * * @param paths A list of absolute file names including the file extension. * @param storage A DataStorage object to which the loaded data will be added. * @param optionsCallback Pointer to a callback instance. The callback is used by * the load operation if more the suitable reader was found or the reader has options * that can be set. * @return The set of added DataNode objects. * @throws mitk::Exception if an entry in \c paths could not be loaded. */ static DataStorage::SetOfObjects::Pointer Load(const std::vector &paths, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback = nullptr); static std::vector Load(const std::vector &paths, const ReaderOptionsFunctorBase *optionsCallback = nullptr); /** * @brief Loads the contents of a us::ModuleResource and returns the corresponding mitk::BaseData * @param usResource a ModuleResource, representing a BaseData object * @param mode Optional parameter to set the openmode of the stream * @return The set of loaded BaseData objects. \c Should contain either one or zero elements, since a resource * stream * respresents one object. * @throws mitk::Exception if no reader was found for the stream. */ static std::vector Load(const us::ModuleResource &usResource, std::ios_base::openmode mode = std::ios_base::in); template static typename T::Pointer Load(const us::ModuleResource &usResource, std::ios_base::openmode mode = std::ios_base::in) { return dynamic_cast(Load(usResource, mode).at(0).GetPointer()); } static BaseData::Pointer Load(const std::string& path, const PropertyList* properties); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param path The path to the image including file name and and optional file extension. * If no extension is set, the default extension and mime-type for the * BaseData type of \c data is used. * @param setPathProperty * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &path, bool setPathProperty = false); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param path The path to the image including file name and an optional file extension. * If no extension is set, the default extension and mime-type for the * BaseData type of \c data is used. * @param options The IFileWriter options to use for the selected writer. * @param setPathProperty * @throws mitk::Exception if no writer for \c data is available or the writer * is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &path, const IFileWriter::Options &options, bool setPathProperty = false); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param mimeType The mime-type to use for writing \c data. * @param path The path to the image including file name and an optional file extension. * @param addExtension If \c true, an extension according to the given \c mimeType * is added to \c path if it does not contain one. If \c path already contains * a file name extension, it is not checked for compatibility with \c mimeType. * @param setPathProperty * * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is * available or the writer is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension = true, bool setPathProperty = false); /** * @brief Save a mitk::BaseData instance. * @param data The data to save. * @param mimeType The mime-type to use for writing \c data. * @param path The path to the image including file name and an optional file extension. * @param options Configuration data for the used IFileWriter instance. * @param addExtension If \c true, an extension according to the given \c mimeType * is added to \c path if it does not contain one. If \c path already contains * a file name extension, it is not checked for compatibility with \c mimeType. * @param setPathProperty * * @throws mitk::Exception if no writer for the combination of \c data and \c mimeType is * available or the writer is not able to write the image. */ static void Save(const mitk::BaseData *data, const std::string &mimeType, const std::string &path, const mitk::IFileWriter::Options &options, bool addExtension = true, bool setPathProperty = false); /** * @brief Use SaveInfo objects to save BaseData instances. * * This is a low-level method for directly working with SaveInfo objects. Usually, * the Save() methods taking a BaseData object as an argument are more appropriate. * * @param saveInfos A list of SaveInfo objects for saving contained BaseData objects. * @param setPathProperty * * @see Save(const mitk::BaseData*, const std::string&) */ static void Save(std::vector &saveInfos, bool setPathProperty = false); protected: static std::string Load(std::vector &loadInfos, DataStorage::SetOfObjects *nodeResult, DataStorage *ds, const ReaderOptionsFunctorBase *optionsCallback); static std::string Save(const BaseData *data, const std::string &mimeType, const std::string &path, WriterOptionsFunctorBase *optionsCallback, bool addExtension, bool setPathProperty); static std::string Save(std::vector &saveInfos, WriterOptionsFunctorBase *optionsCallback, bool setPathProperty); private: struct Impl; }; } #endif // MITKIOUTIL_H diff --git a/Modules/Core/src/IO/mitkIOUtil.cpp b/Modules/Core/src/IO/mitkIOUtil.cpp index edef3c2d4a..98a473e9a6 100644 --- a/Modules/Core/src/IO/mitkIOUtil.cpp +++ b/Modules/Core/src/IO/mitkIOUtil.cpp @@ -1,1015 +1,1015 @@ /*============================================================================ 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 "mitkIOUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // ITK #include // VTK #include #include #include #include #include static std::string GetLastErrorStr() { #ifdef US_PLATFORM_POSIX return std::string(strerror(errno)); #else // Retrieve the system error message for the last-error code LPVOID lpMsgBuf; DWORD dw = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, nullptr); std::string errMsg((LPCTSTR)lpMsgBuf); LocalFree(lpMsgBuf); return errMsg; #endif } #ifdef US_PLATFORM_WINDOWS #include #include // make the posix flags point to the obsolte bsd types on windows #define S_IRUSR S_IREAD #define S_IWUSR S_IWRITE #else #include #include #include #endif #include #include static const char validLetters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; // A cross-platform version of the mkstemps function static int mkstemps_compat(char *tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary files to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary file. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return -1; } /* This is where the Xs start. */ char *XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return -1; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, nullptr); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif for (unsigned int count = 0; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; int fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = savedErrno; return fd; } else if (errno != EEXIST) { return -1; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1; } // A cross-platform version of the POSIX mkdtemp function static char *mkdtemps_compat(char *tmpl, int suffixlen) { static unsigned long long value = 0; int savedErrno = errno; // Lower bound on the number of temporary dirs to attempt to generate. #define ATTEMPTS_MIN (62 * 62 * 62) /* The number of times to attempt to generate a temporary dir. To conform to POSIX, this must be no smaller than TMP_MAX. */ #if ATTEMPTS_MIN < TMP_MAX const unsigned int attempts = TMP_MAX; #else const unsigned int attempts = ATTEMPTS_MIN; #endif const int len = strlen(tmpl); if ((len - suffixlen) < 6 || strncmp(&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) { errno = EINVAL; return nullptr; } /* This is where the Xs start. */ char *XXXXXX = &tmpl[len - 6 - suffixlen]; /* Get some more or less random data. */ #ifdef US_PLATFORM_WINDOWS { SYSTEMTIME stNow; FILETIME ftNow; // get system time GetSystemTime(&stNow); stNow.wMilliseconds = 500; if (!SystemTimeToFileTime(&stNow, &ftNow)) { errno = -1; return nullptr; } unsigned long long randomTimeBits = ((static_cast(ftNow.dwHighDateTime) << 32) | static_cast(ftNow.dwLowDateTime)); value = randomTimeBits ^ static_cast(GetCurrentThreadId()); } #else { struct timeval tv; gettimeofday(&tv, nullptr); unsigned long long randomTimeBits = ((static_cast(tv.tv_usec) << 32) | static_cast(tv.tv_sec)); value = randomTimeBits ^ static_cast(getpid()); } #endif unsigned int count = 0; for (; count < attempts; value += 7777, ++count) { unsigned long long v = value; /* Fill in the random bits. */ XXXXXX[0] = validLetters[v % 62]; v /= 62; XXXXXX[1] = validLetters[v % 62]; v /= 62; XXXXXX[2] = validLetters[v % 62]; v /= 62; XXXXXX[3] = validLetters[v % 62]; v /= 62; XXXXXX[4] = validLetters[v % 62]; v /= 62; XXXXXX[5] = validLetters[v % 62]; #ifdef US_PLATFORM_WINDOWS int fd = _mkdir(tmpl); //, _S_IREAD | _S_IWRITE | _S_IEXEC); #else int fd = mkdir(tmpl, S_IRUSR | S_IWUSR | S_IXUSR); #endif if (fd >= 0) { errno = savedErrno; return tmpl; } else if (errno != EEXIST) { return nullptr; } } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return nullptr; } //#endif //************************************************************** // mitk::IOUtil method definitions namespace mitk { struct IOUtil::Impl { struct FixedReaderOptionsFunctor : public ReaderOptionsFunctorBase { FixedReaderOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} bool operator()(LoadInfo &loadInfo) const override { IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader) { reader->SetOptions(m_Options); } return false; } private: const IFileReader::Options &m_Options; }; struct FixedWriterOptionsFunctor : public WriterOptionsFunctorBase { FixedWriterOptionsFunctor(const IFileReader::Options &options) : m_Options(options) {} bool operator()(SaveInfo &saveInfo) const override { IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer) { writer->SetOptions(m_Options); } return false; } private: const IFileWriter::Options &m_Options; }; static BaseData::Pointer LoadBaseDataFromFile(const std::string &path, const ReaderOptionsFunctorBase* optionsCallback = nullptr); }; BaseData::Pointer IOUtil::Impl::LoadBaseDataFromFile(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback) { std::vector baseDataList = Load(path, optionsCallback); // The Load(path) call above should throw an exception if nothing could be loaded assert(!baseDataList.empty()); return baseDataList.front(); } #ifdef US_PLATFORM_WINDOWS std::string IOUtil::GetProgramPath() { char path[512]; std::size_t index = std::string(path, GetModuleFileName(nullptr, path, 512)).find_last_of('\\'); return std::string(path, index); } #elif defined(US_PLATFORM_APPLE) #include std::string IOUtil::GetProgramPath() { char path[512]; uint32_t size = sizeof(path); if (_NSGetExecutablePath(path, &size) == 0) { std::size_t index = std::string(path).find_last_of('/'); std::string strPath = std::string(path, index); // const char* execPath = strPath.c_str(); // mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(execPath,false); return strPath; } return std::string(); } #else #include #include #include std::string IOUtil::GetProgramPath() { std::stringstream ss; ss << "/proc/" << getpid() << "/exe"; char proc[512] = {0}; ssize_t ch = readlink(ss.str().c_str(), proc, 512); if (ch == -1) return std::string(); std::size_t index = std::string(proc).find_last_of('/'); return std::string(proc, index); } #endif char IOUtil::GetDirectorySeparator() { #ifdef US_PLATFORM_WINDOWS return '\\'; #else return '/'; #endif } std::string IOUtil::GetTempPath() { static std::string result; if (result.empty()) { #ifdef US_PLATFORM_WINDOWS char tempPathTestBuffer[1]; - DWORD bufferLength = ::GetTempPath(1, tempPathTestBuffer); + DWORD bufferLength = GetTempPathA(1, tempPathTestBuffer); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } std::vector tempPath(bufferLength); - bufferLength = ::GetTempPath(bufferLength, &tempPath[0]); + bufferLength = GetTempPathA(bufferLength, &tempPath[0]); if (bufferLength == 0) { mitkThrow() << GetLastErrorStr(); } result.assign(tempPath.begin(), tempPath.begin() + static_cast(bufferLength)); #else result = "/tmp/"; #endif } return result; } std::string IOUtil::CreateTemporaryFile(const std::string &templateName, std::string path) { std::ofstream tmpOutputStream; std::string returnValue = CreateTemporaryFile(tmpOutputStream, templateName, path); tmpOutputStream.close(); return returnValue; } std::string IOUtil::CreateTemporaryFile(std::ofstream &f, const std::string &templateName, std::string path) { return CreateTemporaryFile(f, std::ios_base::out | std::ios_base::trunc, templateName, path); } std::string IOUtil::CreateTemporaryFile(std::ofstream &f, std::ios_base::openmode mode, const std::string &templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? -1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? -1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; int fd = mkstemps_compat(&dst_path[0], suffixlen); if (fd != -1) { path.assign(dst_path.begin(), dst_path.end() - 1); f.open(path.c_str(), mode | std::ios_base::out | std::ios_base::trunc); close(fd); } else { mitkThrow() << "Creating temporary file " << &dst_path[0] << " failed: " << GetLastErrorStr(); } return path; } std::string IOUtil::CreateTemporaryDirectory(const std::string &templateName, std::string path) { if (path.empty()) { path = GetTempPath(); } path += GetDirectorySeparator() + templateName; std::vector dst_path(path.begin(), path.end()); dst_path.push_back('\0'); std::size_t lastX = path.find_last_of('X'); std::size_t firstX = path.find_last_not_of('X', lastX); int firstNonX = firstX == std::string::npos ? -1 : firstX - 1; while (lastX != std::string::npos && (lastX - firstNonX) < 6) { lastX = path.find_last_of('X', firstX); firstX = path.find_last_not_of('X', lastX); firstNonX = firstX == std::string::npos ? -1 : firstX - 1; } std::size_t suffixlen = lastX == std::string::npos ? path.size() : path.size() - lastX - 1; if (mkdtemps_compat(&dst_path[0], suffixlen) == nullptr) { mitkThrow() << "Creating temporary directory " << &dst_path[0] << " failed: " << GetLastErrorStr(); } path.assign(dst_path.begin(), dst_path.end() - 1); return path; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); return Load(paths, storage, optionsCallback); } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::string &path, const IFileReader::Options &options, DataStorage &storage) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::string &path, const ReaderOptionsFunctorBase *optionsCallback) { std::vector paths; paths.push_back(path); return Load(paths, optionsCallback); } std::vector IOUtil::Load(const std::string &path, const IFileReader::Options &options) { std::vector loadInfos; loadInfos.push_back(LoadInfo(path)); Impl::FixedReaderOptionsFunctor optionsCallback(options); std::string errMsg = Load(loadInfos, nullptr, nullptr, &optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return loadInfos.front().m_Output; } DataStorage::SetOfObjects::Pointer IOUtil::Load(const std::vector &paths, DataStorage &storage, const ReaderOptionsFunctorBase *optionsCallback) { DataStorage::SetOfObjects::Pointer nodeResult = DataStorage::SetOfObjects::New(); std::vector loadInfos; for (const auto &loadInfo : paths) { loadInfos.emplace_back(loadInfo); } std::string errMsg = Load(loadInfos, nodeResult, &storage, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } return nodeResult; } std::vector IOUtil::Load(const std::vector &paths, const ReaderOptionsFunctorBase *optionsCallback) { std::vector result; std::vector loadInfos; for (const auto &loadInfo : paths) { loadInfos.emplace_back(loadInfo); } std::string errMsg = Load(loadInfos, nullptr, nullptr, optionsCallback); if (!errMsg.empty()) { mitkThrow() << errMsg; } for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd; ++iter) { result.insert(result.end(), iter->m_Output.begin(), iter->m_Output.end()); } return result; } std::string IOUtil::Load(std::vector &loadInfos, DataStorage::SetOfObjects *nodeResult, DataStorage *ds, const ReaderOptionsFunctorBase *optionsCallback) { if (loadInfos.empty()) { return "No input files given"; } int filesToRead = loadInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToRead); std::string errMsg; std::map usedReaderItems; std::vector< std::string > read_files; for (auto &loadInfo : loadInfos) { if(std::find(read_files.begin(), read_files.end(), loadInfo.m_Path) != read_files.end()) continue; std::vector readers = loadInfo.m_ReaderSelector.Get(); if (readers.empty()) { if (!itksys::SystemTools::FileExists(Utf8Util::Local8BitToUtf8(loadInfo.m_Path).c_str())) { errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; } else { errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; } continue; } bool callOptionsCallback = readers.size() > 1 || !readers.front().GetReader()->GetOptions().empty(); // check if we already used a reader which should be re-used std::vector currMimeTypes = loadInfo.m_ReaderSelector.GetMimeTypes(); std::string selectedMimeType; for (std::vector::const_iterator mimeTypeIter = currMimeTypes.begin(), mimeTypeIterEnd = currMimeTypes.end(); mimeTypeIter != mimeTypeIterEnd; ++mimeTypeIter) { std::map::const_iterator oldSelectedItemIter = usedReaderItems.find(mimeTypeIter->GetName()); if (oldSelectedItemIter != usedReaderItems.end()) { // we found an already used item for a mime-type which is contained // in the current reader set, check all current readers if there service // id equals the old reader for (std::vector::const_iterator currReaderItem = readers.begin(), currReaderItemEnd = readers.end(); currReaderItem != currReaderItemEnd; ++currReaderItem) { if (currReaderItem->GetMimeType().GetName() == mimeTypeIter->GetName() && currReaderItem->GetServiceId() == oldSelectedItemIter->second.GetServiceId() && currReaderItem->GetConfidenceLevel() >= oldSelectedItemIter->second.GetConfidenceLevel()) { // okay, we used the same reader already, re-use its options selectedMimeType = mimeTypeIter->GetName(); callOptionsCallback = false; loadInfo.m_ReaderSelector.Select(oldSelectedItemIter->second.GetServiceId()); loadInfo.m_ReaderSelector.GetSelected().GetReader()->SetOptions( oldSelectedItemIter->second.GetReader()->GetOptions()); break; } } if (!selectedMimeType.empty()) break; } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(loadInfo); if (!callOptionsCallback && !loadInfo.m_Cancel) { usedReaderItems.erase(selectedMimeType); FileReaderSelector::Item selectedItem = loadInfo.m_ReaderSelector.GetSelected(); usedReaderItems.insert(std::make_pair(selectedItem.GetMimeType().GetName(), selectedItem)); } } if (loadInfo.m_Cancel) { errMsg += "Reading operation(s) cancelled."; break; } IFileReader *reader = loadInfo.m_ReaderSelector.GetSelected().GetReader(); if (reader == nullptr) { errMsg += "Unexpected nullptr reader."; break; } reader->SetProperties(loadInfo.m_Properties); // Do the actual reading try { DataStorage::SetOfObjects::Pointer nodes; if (ds != nullptr) { nodes = reader->Read(*ds); std::vector< std::string > new_files = reader->GetReadFiles(); read_files.insert( read_files.end(), new_files.begin(), new_files.end() ); } else { nodes = DataStorage::SetOfObjects::New(); std::vector baseData = reader->Read(); for (auto iter = baseData.begin(); iter != baseData.end(); ++iter) { if (iter->IsNotNull()) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); nodes->InsertElement(nodes->Size(), node); } } std::vector< std::string > new_files = reader->GetReadFiles(); read_files.insert( read_files.end(), new_files.begin(), new_files.end() ); } for (DataStorage::SetOfObjects::ConstIterator nodeIter = nodes->Begin(), nodeIterEnd = nodes->End(); nodeIter != nodeIterEnd; ++nodeIter) { const mitk::DataNode::Pointer &node = nodeIter->Value(); mitk::BaseData::Pointer data = node->GetData(); if (data.IsNull()) { continue; } data->SetProperty("path", mitk::StringProperty::New(Utf8Util::Local8BitToUtf8(loadInfo.m_Path))); loadInfo.m_Output.push_back(data); if (nodeResult) { nodeResult->push_back(nodeIter->Value()); } } if (loadInfo.m_Output.empty() || (nodeResult && nodeResult->Size() == 0)) { errMsg += "Unknown read error occurred reading " + loadInfo.m_Path; } } catch (const std::exception &e) { errMsg += "Exception occured when reading file " + loadInfo.m_Path + ":\n" + e.what() + "\n\n"; } mitk::ProgressBar::GetInstance()->Progress(2); --filesToRead; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToRead); return errMsg; } std::vector IOUtil::Load(const us::ModuleResource &usResource, std::ios_base::openmode mode) { us::ModuleResourceStream resStream(usResource, mode); mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); std::vector mimetypes = mimeTypeProvider->GetMimeTypesForFile(usResource.GetResourcePath()); std::vector data; if (mimetypes.empty()) { mitkThrow() << "No mimetype for resource stream: " << usResource.GetResourcePath(); return data; } mitk::FileReaderRegistry fileReaderRegistry; std::vector> refs = fileReaderRegistry.GetReferences(mimetypes[0]); if (refs.empty()) { mitkThrow() << "No reader available for resource stream: " << usResource.GetResourcePath(); return data; } mitk::IFileReader *reader = fileReaderRegistry.GetReader(refs[0]); reader->SetInput(usResource.GetResourcePath(), &resStream); data = reader->Read(); return data; } BaseData::Pointer IOUtil::Load(const std::string& path, const PropertyList* properties) { LoadInfo loadInfo(path); loadInfo.m_Properties = properties; std::vector loadInfos; loadInfos.push_back(loadInfo); auto errMsg = Load(loadInfos, nullptr, nullptr, nullptr); if (!errMsg.empty()) mitkThrow() << errMsg; return loadInfos.front().m_Output.front(); } void IOUtil::Save(const BaseData *data, const std::string &path, bool setPathProperty) { Save(data, path, IFileWriter::Options(), setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &path, const IFileWriter::Options &options, bool setPathProperty) { Save(data, std::string(), path, options, setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, bool addExtension, bool setPathProperty) { Save(data, mimeType, path, IFileWriter::Options(), addExtension, setPathProperty); } void IOUtil::Save(const BaseData *data, const std::string &mimeType, const std::string &path, const IFileWriter::Options &options, bool addExtension, bool setPathProperty) { if ((data == nullptr) || (data->IsEmpty())) mitkThrow() << "BaseData cannotbe null or empty for save methods in IOUtil.h."; std::string errMsg; if (options.empty()) { errMsg = Save(data, mimeType, path, nullptr, addExtension, setPathProperty); } else { Impl::FixedWriterOptionsFunctor optionsCallback(options); errMsg = Save(data, mimeType, path, &optionsCallback, addExtension, setPathProperty); } if (!errMsg.empty()) { mitkThrow() << errMsg; } } void IOUtil::Save(std::vector &saveInfos, bool setPathProperty) { std::string errMsg = Save(saveInfos, nullptr, setPathProperty); if (!errMsg.empty()) { mitkThrow() << errMsg; } } std::string IOUtil::Save(const BaseData *data, const std::string &mimeTypeName, const std::string &path, WriterOptionsFunctorBase *optionsCallback, bool addExtension, bool setPathProperty) { if (path.empty()) { return "No output filename given"; } mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider()); MimeType mimeType = mimeTypeProvider->GetMimeTypeForName(mimeTypeName); SaveInfo saveInfo(data, mimeType, path); std::string ext = Utf8Util::Utf8ToLocal8Bit(itksys::SystemTools::GetFilenameExtension(Utf8Util::Local8BitToUtf8(path))); if (saveInfo.m_WriterSelector.IsEmpty()) { return std::string("No suitable writer found for the current data of type ") + data->GetNameOfClass() + (mimeType.IsValid() ? (std::string(" and mime-type ") + mimeType.GetName()) : std::string()) + (ext.empty() ? std::string() : (std::string(" with extension ") + ext)); } // Add an extension if not already specified if (ext.empty() && addExtension) { ext = saveInfo.m_MimeType.GetExtensions().empty() ? std::string() : "." + saveInfo.m_MimeType.GetExtensions().front(); saveInfo.m_Path += ext; } std::vector infos; infos.push_back(saveInfo); return Save(infos, optionsCallback, setPathProperty); } std::string IOUtil::Save(std::vector &saveInfos, WriterOptionsFunctorBase *optionsCallback, bool setPathProperty) { if (saveInfos.empty()) { return "No data for saving available"; } int filesToWrite = saveInfos.size(); mitk::ProgressBar::GetInstance()->AddStepsToDo(2 * filesToWrite); std::string errMsg; std::set usedSaveInfos; for (auto &saveInfo : saveInfos) { const std::string baseDataType = saveInfo.m_BaseData->GetNameOfClass(); std::vector writers = saveInfo.m_WriterSelector.Get(); // Error out if no compatible Writer was found if (writers.empty()) { errMsg += std::string("No writer available for ") + baseDataType + " data.\n"; continue; } bool callOptionsCallback = writers.size() > 1 || !writers[0].GetWriter()->GetOptions().empty(); // check if we already used a writer for this base data type // which should be re-used auto oldSaveInfoIter = usedSaveInfos.find(saveInfo); if (oldSaveInfoIter != usedSaveInfos.end()) { // we previously saved a base data object of the same data with the same mime-type, // check if the same writer is contained in the current writer set and if the // confidence level matches FileWriterSelector::Item oldSelectedItem = oldSaveInfoIter->m_WriterSelector.Get(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); for (std::vector::const_iterator currWriterItem = writers.begin(), currWriterItemEnd = writers.end(); currWriterItem != currWriterItemEnd; ++currWriterItem) { if (currWriterItem->GetServiceId() == oldSelectedItem.GetServiceId() && currWriterItem->GetConfidenceLevel() >= oldSelectedItem.GetConfidenceLevel()) { // okay, we used the same writer already, re-use its options callOptionsCallback = false; saveInfo.m_WriterSelector.Select(oldSaveInfoIter->m_WriterSelector.GetSelectedId()); saveInfo.m_WriterSelector.GetSelected().GetWriter()->SetOptions(oldSelectedItem.GetWriter()->GetOptions()); break; } } } if (callOptionsCallback && optionsCallback) { callOptionsCallback = (*optionsCallback)(saveInfo); if (!callOptionsCallback && !saveInfo.m_Cancel) { usedSaveInfos.erase(saveInfo); usedSaveInfos.insert(saveInfo); } } if (saveInfo.m_Cancel) { errMsg += "Writing operation(s) cancelled."; break; } IFileWriter *writer = saveInfo.m_WriterSelector.GetSelected().GetWriter(); if (writer == nullptr) { errMsg += "Unexpected nullptr writer."; break; } // Do the actual writing try { writer->SetOutputLocation(saveInfo.m_Path); writer->Write(); } catch (const std::exception &e) { errMsg += std::string("Exception occurred when writing to ") + saveInfo.m_Path + ":\n" + e.what() + "\n"; } if (setPathProperty) saveInfo.m_BaseData->GetPropertyList()->SetStringProperty("path", Utf8Util::Local8BitToUtf8(saveInfo.m_Path).c_str()); mitk::ProgressBar::GetInstance()->Progress(2); --filesToWrite; } if (!errMsg.empty()) { MITK_ERROR << errMsg; } mitk::ProgressBar::GetInstance()->Progress(2 * filesToWrite); return errMsg; } IOUtil::SaveInfo::SaveInfo(const BaseData *baseData, const MimeType &mimeType, const std::string &path) : m_BaseData(baseData), m_WriterSelector(baseData, mimeType.GetName(), path), m_MimeType(mimeType.IsValid() ? mimeType // use the original mime-type : (m_WriterSelector.IsEmpty() ? mimeType // no writer found, use the original invalid mime-type : m_WriterSelector.GetDefault().GetMimeType() // use the found default mime-type )), m_Path(path), m_Cancel(false) { } bool IOUtil::SaveInfo::operator<(const IOUtil::SaveInfo &other) const { int r = strcmp(m_BaseData->GetNameOfClass(), other.m_BaseData->GetNameOfClass()); if (r == 0) { return m_WriterSelector.GetSelected().GetMimeType() < other.m_WriterSelector.GetSelected().GetMimeType(); } return r < 0; } IOUtil::LoadInfo::LoadInfo(const std::string &path) : m_Path(path), m_ReaderSelector(path), m_Cancel(false), m_Properties(nullptr) { } } diff --git a/Modules/DICOM/CMakeLists.txt b/Modules/DICOM/CMakeLists.txt index 36966c5338..7a333dad07 100644 --- a/Modules/DICOM/CMakeLists.txt +++ b/Modules/DICOM/CMakeLists.txt @@ -1,9 +1,11 @@ MITK_CREATE_MODULE( DEPENDS MitkCore PACKAGE_DEPENDS - PUBLIC GDCM|MSFF tinyxml2 - PRIVATE DCMTK ITK|IOGDCM + PUBLIC tinyxml2 + PRIVATE DCMTK|dcmdata+ofstd ITK|IOGDCM + TARGET_DEPENDS + PUBLIC gdcmMSFF ) add_subdirectory(test) add_subdirectory(autoload/DICOMImageIO) diff --git a/Modules/DICOMPM/CMakeLists.txt b/Modules/DICOMPM/CMakeLists.txt index aa17f28473..42f6d9fda7 100644 --- a/Modules/DICOMPM/CMakeLists.txt +++ b/Modules/DICOMPM/CMakeLists.txt @@ -1,6 +1,4 @@ MITK_CREATE_MODULE(DICOMPM DEPENDS MitkCore MitkDICOM MitkModelFit MitkDICOMQI - PACKAGE_DEPENDS - PRIVATE DCMTK ) add_subdirectory(autoload/DICOMPMIO) diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/CMakeLists.txt b/Modules/DICOMPM/autoload/DICOMPMIO/CMakeLists.txt index 3dd397dbaf..361ba5ce5f 100644 --- a/Modules/DICOMPM/autoload/DICOMPMIO/CMakeLists.txt +++ b/Modules/DICOMPM/autoload/DICOMPMIO/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE(DICOMPMIO DEPENDS MitkModelFit MitkDICOMQI MitkDICOMPM PACKAGE_DEPENDS - PRIVATE DCMQI DCMTK + PRIVATE DCMQI DCMTK|dcmpmap+dcmsr AUTOLOAD_WITH MitkCore ) diff --git a/Modules/DICOMQI/CMakeLists.txt b/Modules/DICOMQI/CMakeLists.txt index eee1639517..d0e9e8421c 100644 --- a/Modules/DICOMQI/CMakeLists.txt +++ b/Modules/DICOMQI/CMakeLists.txt @@ -1,5 +1,3 @@ MITK_CREATE_MODULE( DEPENDS MitkCore MitkDICOM - PACKAGE_DEPENDS - PRIVATE DCMTK ) diff --git a/Modules/DICOMTesting/CMakeLists.txt b/Modules/DICOMTesting/CMakeLists.txt index 857f5a39a1..8bc304edae 100644 --- a/Modules/DICOMTesting/CMakeLists.txt +++ b/Modules/DICOMTesting/CMakeLists.txt @@ -1,43 +1,41 @@ if(BUILD_TESTING) -if(GDCM_DIR) # clear variables from prior files.cmake # Else CMake would use the content of these variables and would try to create tests (which are not present in DICOMTesting). set(MODULE_TESTS) set(MODULE_IMAGE_TESTS) set(MODULE_SURFACE_TESTS) set(MODULE_TESTIMAGE) set(MODULE_TESTSURFACE) set(MODULE_CUSTOM_TESTS) set(H_FILES) set(CPP_FILES) # now create a new module only for testing purposes MITK_CREATE_MODULE( DEPENDS MitkDICOM PACKAGE_DEPENDS - PRIVATE GDCM DCMTK ITK|IOGDCM + PRIVATE DCMTK|config ITK|IOGDCM ) mitk_check_module_dependencies(MODULES MitkDICOMTesting MISSING_DEPENDENCIES_VAR _missing_deps) if(_missing_deps) message(STATUS "mitkDICOMTesting module helper applications won't be built. Missing: ${_missing_deps}") else(_missing_deps) # dumps out image information add_executable(DumpDICOMMitkImage src/DumpDICOMMitkImage.cpp) mitk_use_modules(TARGET DumpDICOMMitkImage MODULES MitkDICOMTesting) # compares dumped out image information against reference dump add_executable(VerifyDICOMMitkImageDump src/VerifyDICOMMitkImageDump.cpp) mitk_use_modules(TARGET VerifyDICOMMitkImageDump MODULES MitkDICOMTesting) set_property(TARGET DumpDICOMMitkImage VerifyDICOMMitkImageDump PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Tests") add_subdirectory(test) endif() endif() -endif() diff --git a/Modules/DICOMUI/CMakeLists.txt b/Modules/DICOMUI/CMakeLists.txt index 50dfc8a723..ad06378441 100644 --- a/Modules/DICOMUI/CMakeLists.txt +++ b/Modules/DICOMUI/CMakeLists.txt @@ -1,8 +1,7 @@ include_directories(${CTK_INCLUDE_DIRS}) MITK_CREATE_MODULE( DEPENDS MitkCore PACKAGE_DEPENDS - PUBLIC CTK|CTKDICOMWidgets Qt5|Sql - PRIVATE Qt5|OpenGL+Widgets+Xml + PUBLIC CTK|CTKDICOMWidgets ) diff --git a/Modules/DICOMUI/include/QmitkDicomExternalDataWidget.h b/Modules/DICOMUI/include/QmitkDicomExternalDataWidget.h index afc501c30c..8c80a4b33f 100644 --- a/Modules/DICOMUI/include/QmitkDicomExternalDataWidget.h +++ b/Modules/DICOMUI/include/QmitkDicomExternalDataWidget.h @@ -1,119 +1,117 @@ /*============================================================================ 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 QmitkDicomExternalDataWidget_h #define QmitkDicomExternalDataWidget_h #include "ui_QmitkDicomExternalDataWidgetControls.h" #include -// include ctk -#include -#include - // include QT #include #include #include #include #include #include #include class ctkFileDialog; +class ctkDICOMDatabase; +class ctkDICOMIndexer; /** * \brief QmitkDicomExternalDataWidget is a QWidget providing functionality for dicom import. * * \ingroup Functionalities */ class MITKDICOMUI_EXPORT QmitkDicomExternalDataWidget : public QWidget { // 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 Widget_ID; /** * \brief QmitkDicomExternalDataWidget(QWidget *parent) constructor. * * \param parent is a pointer to the parent widget */ QmitkDicomExternalDataWidget(QWidget *parent); /** * \brief QmitkDicomExternalDataWidget destructor. */ ~QmitkDicomExternalDataWidget() override; /** * \brief CreateQtPartControl(QWidget *parent) sets the view objects from ui_QmitkDicomExternalDataWidgetControls.h. * * \param parent is a pointer to the parent widget */ virtual void CreateQtPartControl(QWidget *parent); /** * \brief Initializes the widget. This method has to be called before widget can start. */ void Initialize(); signals: /// @brief emitted when import into database is finished. void SignalStartDicomImport(const QStringList &); /// @brief emitted when view button is clicked. void SignalDicomToDataManager(QHash); public slots: /// @brief Called when download button was clicked. void OnDownloadButtonClicked(); /// @brief Called when view button was clicked. void OnViewButtonClicked(); /// @brief Called when adding a dicom directory. Starts a thread adding the directory. void OnStartDicomImport(const QString &); void OnSeriesSelectionChanged(const QStringList &s); protected slots: void OnProgressStep(const QString&); void OnProgressDetail(const QString&); protected: /// \brief Get the list of filepath from current selected index in TreeView. All file paths referring to the index /// will be returned. QStringList GetFileNamesFromIndex(); /// \brief SetupImportDialog Sets up import dialog. void SetupImportDialog(); void SetupProgressDialog(); ctkDICOMDatabase *m_ExternalDatabase; ctkDICOMIndexer *m_ExternalIndexer; ctkFileDialog *m_ImportDialog; QProgressDialog *m_ProgressDialog; QString m_LastImportDirectory; QString m_ProgressStep; Ui::QmitkDicomExternalDataWidgetControls *m_Controls; }; #endif // _QmitkDicomExternalDataWidget_H_INCLUDED diff --git a/Modules/DICOMUI/include/QmitkDicomLocalStorageWidget.h b/Modules/DICOMUI/include/QmitkDicomLocalStorageWidget.h index b5da4acd91..20c5157ba6 100644 --- a/Modules/DICOMUI/include/QmitkDicomLocalStorageWidget.h +++ b/Modules/DICOMUI/include/QmitkDicomLocalStorageWidget.h @@ -1,115 +1,113 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkDicomLocalStorageWidget_h #define QmitkDicomLocalStorageWidget_h #include "ui_QmitkDicomLocalStorageWidgetControls.h" #include -// include ctk -#include -#include -#include - // include QT #include #include #include #include #include class QProgressDialog; class QLabel; +class ctkDICOMDatabase; +class ctkDICOMIndexer; + /** * \brief QmitkDicomLocalStorageWidget is a QWidget providing functionality for dicom storage and import. * * \ingroup Functionalities */ class MITKDICOMUI_EXPORT QmitkDicomLocalStorageWidget : public QWidget { // 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 Widget_ID; /** * \brief QmitkDicomLocalStorageWidget(QWidget *parent) constructor. * * \param parent is a pointer to the parent widget */ QmitkDicomLocalStorageWidget(QWidget *parent); /** * \brief QmitkDicomExternalDataWidget destructor. */ ~QmitkDicomLocalStorageWidget() override; /** * \brief CreateQtPartControl(QWidget *parent) sets the view objects from ui_QmitkDicomExternalDataWidgetControls.h. * * \param parent is a pointer to the parent widget */ virtual void CreateQtPartControl(QWidget *parent); /** * \brief SetDatabaseDirectory sets database directory. * * \param newDatabaseDirectory contains path to new database directoy. */ void SetDatabaseDirectory(QString newDatabaseDirectory); signals: /// @brief emitted when import into database is finished. void SignalFinishedImport(); /** * @brief emitted when view button is clicked. * @param _t1 containing dicom UIDs properties. */ void SignalDicomToDataManager(QHash _t1); /// \brief emitted if cancel button is pressed. void SignalCancelImport(); public slots: /// @brief Called when view button was clicked. void OnViewButtonClicked(); /// @brief Called delete button was clicked. void OnDeleteButtonClicked(); /// @brief Called when adding a dicom directory. Starts a thread adding the directory. void OnStartDicomImport(const QString &dicomData); /// @brief Called when adding a list of dicom files. Starts a thread adding the dicom files. void OnStartDicomImport(const QStringList &dicomData); /// @brief Called when the selection in the series table has changed void OnSeriesSelectionChanged(const QStringList &); protected: void SetDatabase(QString databaseFile); bool DeletePatients(); bool DeleteStudies(); bool DeleteSeries(); ctkDICOMDatabase *m_LocalDatabase; ctkDICOMIndexer *m_LocalIndexer; Ui::QmitkDicomLocalStorageWidgetControls *m_Controls; }; #endif // _QmitkDicomLocalStorageWidget_H_INCLUDED diff --git a/Modules/DICOMUI/src/QmitkDicomExternalDataWidget.cpp b/Modules/DICOMUI/src/QmitkDicomExternalDataWidget.cpp index 783ecb4f4e..414ecfb82b 100644 --- a/Modules/DICOMUI/src/QmitkDicomExternalDataWidget.cpp +++ b/Modules/DICOMUI/src/QmitkDicomExternalDataWidget.cpp @@ -1,229 +1,230 @@ /*============================================================================ 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. ============================================================================*/ // Qmitk #include "QmitkDicomExternalDataWidget.h" #include // CTK +#include #include // Qt #include #include #include const std::string QmitkDicomExternalDataWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomExternalDataWidget"; QmitkDicomExternalDataWidget::QmitkDicomExternalDataWidget(QWidget *parent) : QWidget(parent), m_ProgressDialog(nullptr), m_Controls(nullptr) { Initialize(); CreateQtPartControl(this); } QmitkDicomExternalDataWidget::~QmitkDicomExternalDataWidget() { } void QmitkDicomExternalDataWidget::CreateQtPartControl(QWidget *parent) { // build up qt Widget, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkDicomExternalDataWidgetControls; m_Controls->setupUi(parent); m_Controls->viewExternalDataButton->setVisible(true); m_Controls->ctkDICOMBrowser->setTableOrientation(Qt::Vertical); m_Controls->ctkDICOMBrowser->setDICOMDatabase(m_ExternalDatabase); SetupImportDialog(); SetupProgressDialog(); // connect buttons connect(m_Controls->downloadButton, SIGNAL(clicked()), this, SLOT(OnDownloadButtonClicked())); connect(m_Controls->viewExternalDataButton, SIGNAL(clicked()), this, SLOT(OnViewButtonClicked())); connect(m_Controls->directoryButton, SIGNAL(clicked()), m_ImportDialog, SLOT(show())); connect(m_Controls->ctkDICOMBrowser, SIGNAL(seriesSelectionChanged(const QStringList &)), this, SLOT(OnSeriesSelectionChanged(const QStringList &))); connect( m_Controls->ctkDICOMBrowser, SIGNAL(seriesDoubleClicked(const QModelIndex &)), this, SLOT(OnViewButtonClicked())); connect(m_ImportDialog, SIGNAL(fileSelected(QString)), this, SLOT(OnStartDicomImport(QString))); connect(m_ExternalIndexer, SIGNAL(progressStep(QString)), this, SLOT(OnProgressStep(const QString&))); connect(m_ExternalIndexer, SIGNAL(progressDetail(QString)), this, SLOT(OnProgressDetail(const QString &))); connect(m_ExternalIndexer, SIGNAL(progress(int)), m_ProgressDialog, SLOT(setValue(int))); // actually the progress dialog closes if the maximum value is reached, BUT // the following line is needed since the external indexer wont reach maximum value (100 % progress) connect(m_ExternalIndexer, SIGNAL(indexingComplete(int, int, int, int)), m_ProgressDialog, SLOT(close())); connect(m_ProgressDialog, SIGNAL(canceled()), m_ExternalIndexer, SLOT(cancel())); } } void QmitkDicomExternalDataWidget::Initialize() { m_ExternalDatabase = new ctkDICOMDatabase(this); try { // this used to be an in-memory database, but latest CTK enhancements made it difficult // to maintain this mechanism QTemporaryFile tmpDatabaseFile; tmpDatabaseFile.open(); tmpDatabaseFile.setAutoRemove(false); m_ExternalDatabase->openDatabase(tmpDatabaseFile.fileName(), QString("EXTERNAL-DB")); } catch (const std::exception&) { MITK_ERROR << "Database error: " << m_ExternalDatabase->lastError().toStdString(); m_ExternalDatabase->closeDatabase(); return; } m_ExternalIndexer = new ctkDICOMIndexer(this); } void QmitkDicomExternalDataWidget::OnDownloadButtonClicked() { QStringList filesToDownload = GetFileNamesFromIndex(); if (filesToDownload.size() == 0) { QMessageBox info; info.setText("You have to select an entry in the DICOM browser for import."); info.exec(); return; } emit SignalStartDicomImport(GetFileNamesFromIndex()); } void QmitkDicomExternalDataWidget::OnViewButtonClicked() { QStringList uids = m_Controls->ctkDICOMBrowser->currentSeriesSelection(); QString uid; foreach (uid, uids) { QStringList filesForSeries = m_ExternalDatabase->filesForSeries(uid); QHash eventProperty; eventProperty.insert("FilesForSeries", filesForSeries); if (!filesForSeries.isEmpty()) { QString modality = m_ExternalDatabase->fileValue(filesForSeries.at(0), "0008,0060"); eventProperty.insert("Modality", modality); } emit SignalDicomToDataManager(eventProperty); } } void QmitkDicomExternalDataWidget::OnProgressStep(const QString& step) { m_ProgressStep = step; m_ProgressDialog->setLabelText(step); } void QmitkDicomExternalDataWidget::OnProgressDetail(const QString& detail) { m_ProgressDialog->setLabelText(m_ProgressStep+"\n"+detail); } QStringList QmitkDicomExternalDataWidget::GetFileNamesFromIndex() { QStringList filePaths; QString uid; QStringList seriesUIDs = m_Controls->ctkDICOMBrowser->currentSeriesSelection(); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } if (!filePaths.empty()) return filePaths; QStringList studyUIDs = m_Controls->ctkDICOMBrowser->currentStudiesSelection(); foreach (uid, studyUIDs) { seriesUIDs = m_ExternalDatabase->seriesForStudy(uid); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } } if (!filePaths.empty()) return filePaths; QStringList patientsUIDs = m_Controls->ctkDICOMBrowser->currentPatientsSelection(); foreach (uid, patientsUIDs) { studyUIDs = m_ExternalDatabase->studiesForPatient(uid); foreach (uid, studyUIDs) { seriesUIDs = m_ExternalDatabase->seriesForStudy(uid); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } } } return filePaths; } void QmitkDicomExternalDataWidget::OnStartDicomImport(const QString &directory) { m_ImportDialog->close(); // no need to show / start the progress dialog, as the dialog // appears by receiving the progress signal from the external indexer m_LastImportDirectory = directory; m_ExternalIndexer->addDirectory(m_ExternalDatabase, m_LastImportDirectory); } void QmitkDicomExternalDataWidget::OnSeriesSelectionChanged(const QStringList &s) { m_Controls->viewExternalDataButton->setEnabled((s.size() != 0)); } void QmitkDicomExternalDataWidget::SetupImportDialog() { // Initialize import widget m_ImportDialog = new ctkFileDialog(this); // Since copy on import is not working at the moment // this feature is disabled // QCheckBox* importCheckbox = new QCheckBox("Copy on import", m_ImportDialog); // m_ImportDialog->setBottomWidget(importCheckbox); m_ImportDialog->setFileMode(QFileDialog::Directory); m_ImportDialog->setLabelText(QFileDialog::Accept, "Import"); m_ImportDialog->setWindowTitle("Import DICOM files from directory"); m_ImportDialog->setWindowModality(Qt::ApplicationModal); } void QmitkDicomExternalDataWidget::SetupProgressDialog() { m_ProgressDialog = new QProgressDialog("Initialization ...", "Cancel", 0, 100, this); m_ProgressDialog->setWindowTitle("DICOM Import"); m_ProgressDialog->setWindowModality(Qt::ApplicationModal); m_ProgressDialog->setMinimumDuration(0); // FIX T20008: immediately set the progress dialog value to maximum --> will close the dialog m_ProgressDialog->setValue(100); } diff --git a/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp b/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp index 975912427f..460b412664 100644 --- a/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp +++ b/Modules/DICOMUI/src/QmitkDicomLocalStorageWidget.cpp @@ -1,228 +1,230 @@ /*============================================================================ 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. ============================================================================*/ // Qmitk #include "QmitkDicomLocalStorageWidget.h" //#include // Qt #include #include #include #include +#include + const std::string QmitkDicomLocalStorageWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomLocalStorageWidget"; QmitkDicomLocalStorageWidget::QmitkDicomLocalStorageWidget(QWidget *parent) : QWidget(parent), m_LocalIndexer(new ctkDICOMIndexer(parent)), m_Controls(nullptr) { CreateQtPartControl(this); } QmitkDicomLocalStorageWidget::~QmitkDicomLocalStorageWidget() { m_LocalDatabase->closeDatabase(); } void QmitkDicomLocalStorageWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Controls = new Ui::QmitkDicomLocalStorageWidgetControls; m_Controls->setupUi(parent); connect(m_Controls->deleteButton, SIGNAL(clicked()), this, SLOT(OnDeleteButtonClicked())); connect(m_Controls->viewInternalDataButton, SIGNAL(clicked()), this, SLOT(OnViewButtonClicked())); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList &)), this, SLOT(OnSeriesSelectionChanged(const QStringList &))); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList &)), this, SLOT(OnSeriesSelectionChanged(const QStringList &))); connect( m_Controls->ctkDicomBrowser, SIGNAL(seriesDoubleClicked(const QModelIndex &)), this, SLOT(OnViewButtonClicked())); connect(m_LocalIndexer, SIGNAL(indexingComplete(int, int, int, int)), this, SIGNAL(SignalFinishedImport())); m_Controls->ctkDicomBrowser->setTableOrientation(Qt::Vertical); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QString &dicomData) { if (m_LocalDatabase->isOpen()) { m_LocalIndexer->addDirectory(dicomData); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QStringList &dicomData) { if (m_LocalDatabase->isOpen()) { m_LocalIndexer->addListOfFiles( dicomData); } } void QmitkDicomLocalStorageWidget::OnDeleteButtonClicked() { if (!this->DeletePatients()) { if (!this->DeleteStudies()) { this->DeleteSeries(); } } m_Controls->ctkDicomBrowser->updateTableViews(); } bool QmitkDicomLocalStorageWidget::DeletePatients() { auto selectedPatientUIDs = m_Controls->ctkDicomBrowser->currentPatientsSelection(); if (!selectedPatientUIDs.empty()) { QStringList studyUIDs; for (const auto &patientUID : qAsConst(selectedPatientUIDs)) studyUIDs.append(m_LocalDatabase->studiesForPatient(patientUID)); QStringList seriesUIDs; for (const auto &studyUID : studyUIDs) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question(nullptr, "Delete Patients", QString("Do you really want to delete %1 %2, containing %3 series in %4 %5?") .arg(selectedPatientUIDs.count()) .arg(selectedPatientUIDs.count() != 1 ? "patients" : "patient") .arg(seriesUIDs.count()) .arg(studyUIDs.count()) .arg(studyUIDs.count() != 1 ? "studies" : "study"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto &patientUID : qAsConst(selectedPatientUIDs)) m_LocalDatabase->removePatient(patientUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteStudies() { auto selectedStudyUIDs = m_Controls->ctkDicomBrowser->currentStudiesSelection(); if (!selectedStudyUIDs.empty()) { QStringList seriesUIDs; for (const auto &studyUID : qAsConst(selectedStudyUIDs)) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question(nullptr, "Delete Studies", QString("Do you really want to delete %1 %2, containing %3 series?") .arg(selectedStudyUIDs.count()) .arg(selectedStudyUIDs.count() != 1 ? "studies" : "study") .arg(seriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto &studyUID : qAsConst(selectedStudyUIDs)) m_LocalDatabase->removeStudy(studyUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteSeries() { auto selectedSeriesUIDs = m_Controls->ctkDicomBrowser->currentSeriesSelection(); if (!selectedSeriesUIDs.empty()) { auto answer = QMessageBox::question(nullptr, "Delete Series", QString("Do you really want to delete %1 series?").arg(selectedSeriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto &seriesUID : qAsConst(selectedSeriesUIDs)) m_LocalDatabase->removeSeries(seriesUID); } return true; } return false; } void QmitkDicomLocalStorageWidget::OnViewButtonClicked() { QStringList uids = m_Controls->ctkDicomBrowser->currentSeriesSelection(); QString uid; foreach (uid, uids) { QStringList filesForSeries = m_LocalDatabase->filesForSeries(uid); QHash eventProperty; eventProperty.insert("FilesForSeries", filesForSeries); if (!filesForSeries.isEmpty()) { QString modality = m_LocalDatabase->fileValue(filesForSeries.at(0), "0008,0060"); eventProperty.insert("Modality", modality); } emit SignalDicomToDataManager(eventProperty); } } void QmitkDicomLocalStorageWidget::SetDatabaseDirectory(QString newDatatbaseDirectory) { QDir databaseDirecory = QDir(newDatatbaseDirectory); if (!databaseDirecory.exists()) { databaseDirecory.mkpath(databaseDirecory.absolutePath()); } QString newDatatbaseFile = databaseDirecory.absolutePath() + QString("/ctkDICOM.sql"); this->SetDatabase(newDatatbaseFile); } void QmitkDicomLocalStorageWidget::SetDatabase(QString databaseFile) { m_LocalDatabase = new ctkDICOMDatabase(databaseFile); m_LocalDatabase->setParent(this); m_Controls->ctkDicomBrowser->setDICOMDatabase(m_LocalDatabase); m_LocalIndexer->setDatabase(m_LocalDatabase); } void QmitkDicomLocalStorageWidget::OnSeriesSelectionChanged(const QStringList &s) { m_Controls->viewInternalDataButton->setEnabled((s.size() != 0)); } diff --git a/Modules/IGT/Common/mitkSerialCommunication.cpp b/Modules/IGT/Common/mitkSerialCommunication.cpp index 3d6104df87..00f9f75a78 100644 --- a/Modules/IGT/Common/mitkSerialCommunication.cpp +++ b/Modules/IGT/Common/mitkSerialCommunication.cpp @@ -1,510 +1,510 @@ /*============================================================================ 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 "mitkSerialCommunication.h" #ifdef WIN32 //#include #include #else // Posix #include #include #include #include #include #include #include #include #define INVALID_HANDLE_VALUE -1 #endif #define OK 1 #define ERROR_VALUE 0 mitk::SerialCommunication::SerialCommunication() : itk::Object(), m_DeviceName(""), m_PortNumber(COM1), m_BaudRate(BaudRate9600), m_DataBits(DataBits8), m_Parity(None), m_StopBits(StopBits1), m_HardwareHandshake(HardwareHandshakeOff), m_ReceiveTimeout(500), m_SendTimeout(500), m_Connected(false) { #ifdef WIN32 // Windows m_ComPortHandle = INVALID_HANDLE_VALUE; #else // Posix m_FileDescriptor = INVALID_HANDLE_VALUE; #endif } mitk::SerialCommunication::~SerialCommunication() { CloseConnection(); } bool mitk::SerialCommunication::IsConnected() { return m_Connected; } int mitk::SerialCommunication::OpenConnection() { if (m_Connected) return ERROR_VALUE; #ifdef WIN32 std::stringstream ss; if (m_DeviceName.empty()) ss << "\\\\.\\COM" << static_cast(m_PortNumber); // use m_PortNumber else ss << "\\\\.\\" << m_DeviceName; // use m_DeviceName - m_ComPortHandle = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, + m_ComPortHandle = CreateFileA(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE, 0, // no sharing 0, // no security flags OPEN_EXISTING, // open com port, don't create it 0, // no flags 0); // no template if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; GetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); GetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); GetCommMask(m_ComPortHandle, &m_PreviousMask); if (this->ApplyConfiguration() != OK) // set interface parameters { CloseHandle(m_ComPortHandle); m_ComPortHandle = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #else // Posix std::stringstream ss; if (m_DeviceName.empty()) ss << "/dev/ttyS" << static_cast(m_PortNumber) - 1; // use m_PortNumber, COM1 = ttyS0 else ss << m_DeviceName; // use m_DeviceName //m_FileDescriptor = open(ss.str().c_str(), O_RDWR | O_NONBLOCK | O_NDELAY | O_NOCTTY | O_EXCL); // open device file m_FileDescriptor = open(ss.str().c_str(), O_RDWR|O_NONBLOCK|O_EXCL); // open device file if (m_FileDescriptor < 0) return ERROR_VALUE; fcntl(m_FileDescriptor, F_SETFL, 0); // change to blocking mode tcflush(m_FileDescriptor, TCIOFLUSH); // flush buffers if (this->ApplyConfiguration() != OK) // set interface parameters { close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; return ERROR_VALUE; } m_Connected = true; return OK; #endif } void mitk::SerialCommunication::CloseConnection() { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); SetCommState(m_ComPortHandle, &m_PreviousDeviceControlBlock); // restore previous settings SetCommTimeouts(m_ComPortHandle, &m_PreviousTimeout); // restore previous timeout values SetCommMask(m_ComPortHandle, m_PreviousMask); // restore previous mask value PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // empty buffers CloseHandle(m_ComPortHandle); // close handle m_ComPortHandle = INVALID_HANDLE_VALUE; m_Connected = false; return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; ClearReceiveBuffer(); ClearSendBuffer(); close(m_FileDescriptor); m_FileDescriptor = INVALID_HANDLE_VALUE; m_Connected = false; return; #endif } int mitk::SerialCommunication::Receive(std::string& answer, unsigned int numberOfBytes, const char *eol) { if (numberOfBytes == 0) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD numberOfBytesRead = 0; char* buffer = new char[numberOfBytes]; if (ReadFile(m_ComPortHandle, buffer, numberOfBytes, &numberOfBytesRead, nullptr) != 0) { if (numberOfBytesRead > 0) // data read { answer.assign(buffer, numberOfBytesRead); // copy buffer to answer delete buffer; if (numberOfBytesRead == numberOfBytes) { return OK; // everything was received } else { return ERROR_VALUE; // some data was received, but not as much as expected } } else // error { answer = ""; delete buffer; return ERROR_VALUE; } } delete buffer; return OK; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; unsigned long bytesRead = 0; unsigned long bytesLeft = numberOfBytes; auto buffer = new char[numberOfBytes]; while ((bytesLeft > 0) && (bytesRead < numberOfBytes)) { int num = read(m_FileDescriptor, &buffer[bytesRead], 1); // read one byte if (num == -1) // ERROR_VALUE { if (errno == EAGAIN) // nonblocking, no byte there right now, but maybe next time continue; else break; // ERROR_VALUE, stop trying to read } if (num == 0) // timeout or eof(?) break; bytesLeft -= num; // n is number of chars left to read bytesRead += num; // i is the number of chars read if (eol && *eol == buffer[bytesRead-1]) // end of line char reached break; } if (bytesRead > 0) answer.assign(buffer, bytesRead); // copy buffer to answer delete[] buffer; if ( bytesRead == numberOfBytes || // everything was received (eol && answer.size() > 0 && *eol == answer.at(answer.size()-1)) ) // end of line char reached return OK; else return ERROR_VALUE; // some data was received, but not as much as expected #endif } int mitk::SerialCommunication::Send(const std::string& input, bool block) { //long retval = E2ERR_OPENFAILED; if (input.empty()) return OK; if (m_Connected == false) return ERROR_VALUE; #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DWORD bytesWritten = 0; if (WriteFile(m_ComPortHandle, input.data(), static_cast(input.size()), &bytesWritten, nullptr) == TRUE) return OK; else return ERROR_VALUE; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return ERROR_VALUE; long bytesWritten = 0; long bytesLeft = input.size(); while (bytesLeft > 0) { bytesWritten = write(m_FileDescriptor, input.data() + bytesWritten, bytesLeft); if (bytesWritten <= 0) return ERROR_VALUE; //return ERROR_VALUE bytesLeft -= bytesWritten; } if (block) { // wait for output to be physically sent if (tcdrain(m_FileDescriptor) == -1) return ERROR_VALUE; } return OK; #endif } int mitk::SerialCommunication::ApplyConfiguration() { #ifdef WIN32 // Windows implementation return ApplyConfigurationWin(); #else // Posix return ApplyConfigurationUnix(); #endif } /** * The Code for Baud rates is highly platform specific and divided into separate subroutines for readability. */ #ifdef WIN32 int mitk::SerialCommunication::ApplyConfigurationWin() { if (m_ComPortHandle == INVALID_HANDLE_VALUE) return ERROR_VALUE; DCB controlSettings; if (GetCommState(m_ComPortHandle, &controlSettings) == 0) { return ERROR_VALUE; } std::ostringstream o; o << "baud=" << m_BaudRate << " parity=" << static_cast(m_Parity) << " data=" << m_DataBits << " stop=" << m_StopBits; if (BuildCommDCBA(o.str().c_str(), &controlSettings) == 0) // Build device-control block return ERROR_VALUE; if (m_HardwareHandshake == HardwareHandshakeOn) // Modify hardware handshake values { controlSettings.fDtrControl = DTR_CONTROL_ENABLE; controlSettings.fRtsControl = RTS_CONTROL_ENABLE; controlSettings.fOutxCtsFlow = TRUE; controlSettings.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { controlSettings.fDtrControl = DTR_CONTROL_DISABLE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; controlSettings.fOutxCtsFlow = FALSE; controlSettings.fRtsControl = RTS_CONTROL_DISABLE; } if (SetCommState(m_ComPortHandle, &controlSettings) == FALSE) // Configure com port return ERROR_VALUE; COMMTIMEOUTS timeouts; timeouts.ReadIntervalTimeout = m_ReceiveTimeout; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = m_ReceiveTimeout; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = m_SendTimeout; if (SetCommTimeouts(m_ComPortHandle, &timeouts) == FALSE) // set timeout values return ERROR_VALUE; PurgeComm(m_ComPortHandle, PURGE_TXCLEAR | PURGE_RXCLEAR); // clear read and write buffers return OK; } #else /** * \brief Applies the configuration for Linux */ int mitk::SerialCommunication::ApplyConfigurationUnix() { if ( m_FileDescriptor == INVALID_HANDLE_VALUE ) return ERROR_VALUE; struct termios termIOStructure; if ( tcgetattr(m_FileDescriptor, &termIOStructure) != 0 ) // retrieve parameters from com port return ERROR_VALUE; cfmakeraw(&termIOStructure); // set flags to raw mode termIOStructure.c_cflag |= CLOCAL; if (m_HardwareHandshake == HardwareHandshakeOn) { // enable termIOStructure.c_cflag |= CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } else { // disable termIOStructure.c_cflag &= ~CRTSCTS; termIOStructure.c_iflag &= ~(IXON|IXOFF); } termIOStructure.c_cflag &= ~CSIZE; // set number of data bits switch (m_DataBits) { case DataBits7: termIOStructure.c_cflag |= CS7; break; case DataBits8: default: termIOStructure.c_cflag |= CS8; } switch (m_StopBits) // set number of stop bits { case StopBits2: termIOStructure.c_cflag |= CSTOPB; break; case StopBits1: default: termIOStructure.c_cflag &= ~CSTOPB; } switch (m_Parity) // set parity { case Odd: termIOStructure.c_cflag |= (PARENB|PARODD); break; case Even: termIOStructure.c_cflag |= PARENB; termIOStructure.c_cflag &= ~PARODD; // TODO: check if this is intended // FALLTHRU case None: // FALLTHRU default: termIOStructure.c_cflag &= ~PARENB; break; } speed_t baudrate; // set baudrate switch (m_BaudRate) { case BaudRate9600: baudrate = B9600; break; case BaudRate14400: baudrate = B9600; //14400 is not defined for posix, use 9600 instead break; case BaudRate19200: baudrate = B19200; break; case BaudRate38400: baudrate = B38400; break; case BaudRate57600: baudrate = B57600; break; case BaudRate115200: baudrate = B115200; break; case BaudRate230400: baudrate = B230400; break; // the following baud rates do not work for apple #ifndef __APPLE__ case BaudRate460800: baudrate = B460800; break; case BaudRate500000: baudrate = B500000; break; case BaudRate576000: baudrate = B576000; break; case BaudRate921600: baudrate = B921600; break; case BaudRate1000000: baudrate = B1000000; break; case BaudRate1152000: baudrate = B1152000; break; //case BaudRate1228739: //baudrate = B1228739; //break; case BaudRate1500000: baudrate = B1500000; break; case BaudRate2000000: baudrate = B2000000; break; case BaudRate2500000: baudrate = B2500000; break; case BaudRate3000000: baudrate = B3000000; break; case BaudRate3500000: baudrate = B3500000; break; case BaudRate4000000: baudrate = B4000000; break; #endif default: MITK_WARN("mitk::SerialCommunication") << "Baud rate not recognized, using default of 9600 Baud."; baudrate = B9600; break; } cfsetispeed(&termIOStructure, baudrate); cfsetospeed(&termIOStructure, baudrate); termIOStructure.c_cc[VMIN] = 0; termIOStructure.c_cc[VTIME] = m_ReceiveTimeout / 100; // timeout in 1/10 sec, not in ms. Rounded down. if (tcsetattr(m_FileDescriptor, TCSANOW, &termIOStructure) == 0) return OK; else return ERROR_VALUE; } #endif void mitk::SerialCommunication::SendBreak(unsigned int ms) { #ifdef WIN32 if (m_ComPortHandle == INVALID_HANDLE_VALUE) return; SetCommBreak(m_ComPortHandle); itksys::SystemTools::Delay(ms); ClearCommBreak(m_ComPortHandle); return; #else // Posix if (m_FileDescriptor == INVALID_HANDLE_VALUE) return; tcsendbreak(m_FileDescriptor, ms); return; #endif } void mitk::SerialCommunication::ClearReceiveBuffer() { #ifdef WIN32 if (m_ComPortHandle != INVALID_HANDLE_VALUE) PurgeComm(m_ComPortHandle, PURGE_RXCLEAR); #else // Posix if (m_FileDescriptor != INVALID_HANDLE_VALUE) tcflush(m_FileDescriptor, TCIFLUSH); #endif } void mitk::SerialCommunication::ClearSendBuffer() { #ifdef WIN32 if ( m_ComPortHandle != INVALID_HANDLE_VALUE ) PurgeComm(m_ComPortHandle, PURGE_TXCLEAR); #else // Posix if ( m_FileDescriptor != INVALID_HANDLE_VALUE ) tcflush(m_FileDescriptor, TCOFLUSH); #endif } diff --git a/Modules/Multilabel/autoload/DICOMSegIO/CMakeLists.txt b/Modules/Multilabel/autoload/DICOMSegIO/CMakeLists.txt index de9ed9e7cc..899a24f3d3 100644 --- a/Modules/Multilabel/autoload/DICOMSegIO/CMakeLists.txt +++ b/Modules/Multilabel/autoload/DICOMSegIO/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( DICOMSegIO DEPENDS MitkMultilabel MitkDICOMQI PACKAGE_DEPENDS - PRIVATE DCMQI DCMTK + PRIVATE DCMQI DCMTK|dcmseg+dcmsr AUTOLOAD_WITH MitkCore ) diff --git a/Modules/OpenCVVideoSupport/CMakeLists.txt b/Modules/OpenCVVideoSupport/CMakeLists.txt index 2040203b4a..10db853b78 100644 --- a/Modules/OpenCVVideoSupport/CMakeLists.txt +++ b/Modules/OpenCVVideoSupport/CMakeLists.txt @@ -1,19 +1,24 @@ -set(dependencies OpenCV) +set(dependencies OpenCV|videoio+calib3d) + +# adding option for videoinput library on windows (for directshow based frame grabbing) +if(WIN32 AND MITK_USE_OpenCV) + option(MITK_USE_videoInput "Use videoInput (DirectShow wrapper) library" OFF) +endif() + if(MITK_USE_videoInput) - set(dependencies ${dependencies} videoInput) -endif(MITK_USE_videoInput) + list(APPEND dependencies videoInput) +endif() mitk_create_module( INCLUDE_DIRS Commands DEPENDS MitkAlgorithmsExt PACKAGE_DEPENDS PUBLIC ${dependencies} - ADDITIONAL_LIBS ${OPENCVVIDEOSUPPORT_ADDITIONAL_LIBS} ) if(MODULE_IS_ENABLED) if(MITK_USE_Qt5) add_subdirectory(UI) endif() endif() add_subdirectory(Testing) diff --git a/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp index 56a6241f47..91385c18c3 100644 --- a/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp +++ b/Modules/OpenCVVideoSupport/Commands/mitkConvertGrayscaleOpenCVImageFilter.cpp @@ -1,33 +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. ============================================================================*/ #include "mitkConvertGrayscaleOpenCVImageFilter.h" #include +#include namespace mitk { bool ConvertGrayscaleOpenCVImageFilter::OnFilterImage( cv::Mat& image ) { // there is nothing to do if the image is grayscale already if (image.channels() == 1) { return true; } cv::Mat buffer; cv::cvtColor(image, buffer, CV_RGB2GRAY, 1); // content of buffer should now be the content of image buffer.copyTo(image); return true; } } // namespace mitk diff --git a/Modules/OpenCVVideoSupport/Commands/mitkGrabCutOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkGrabCutOpenCVImageFilter.cpp index 294c802013..dd911780a9 100644 --- a/Modules/OpenCVVideoSupport/Commands/mitkGrabCutOpenCVImageFilter.cpp +++ b/Modules/OpenCVVideoSupport/Commands/mitkGrabCutOpenCVImageFilter.cpp @@ -1,391 +1,392 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // mitk headers #include "mitkGrabCutOpenCVImageFilter.h" #include "mitkPointSet.h" #include +#include // This is a magic number defined in "grabcut.cpp" of OpenCV. // GrabCut function crashes if less than this number of model // points are given. There must be at least as much model points // as components of the Gaussian Mixture Model. #define GMM_COMPONENTS_COUNT 5 mitk::GrabCutOpenCVImageFilter::GrabCutOpenCVImageFilter() : m_ModelPointsDilationSize(0), m_UseOnlyRegionAroundModelPoints(false), m_CurrentProcessImageNum(0), m_InputImageId(AbstractOpenCVImageFilter::INVALID_IMAGE_ID), m_ResultImageId(AbstractOpenCVImageFilter::INVALID_IMAGE_ID), m_StopThread(false) { m_Thread = std::thread(&GrabCutOpenCVImageFilter::SegmentationWorker, this); } mitk::GrabCutOpenCVImageFilter::~GrabCutOpenCVImageFilter() { // terminate worker thread on destruction m_StopThread = true; m_WorkerBarrier.notify_all(); if (m_Thread.joinable()) m_Thread.detach(); } bool mitk::GrabCutOpenCVImageFilter::OnFilterImage( cv::Mat& image ) { if ( image.empty() ) { MITK_WARN << "Filtering empty image?"; return false; } // make sure that the image is an rgb image as needed // by the GrabCut algorithm if (image.type() != CV_8UC3) { cv::Mat tmp = image.clone(); cv::cvtColor(tmp, image, CV_GRAY2RGB); } // set image as the current input image, guarded by // a mutex as the worker thread reads this imagr m_ImageMutex.lock(); m_InputImage = image.clone(); m_InputImageId = this->GetCurrentImageId(); m_ImageMutex.unlock(); // wake up the worker thread if there was an image set // and foreground model points are available if ( ! m_ForegroundPoints.empty()) { m_WorkerBarrier.notify_all(); } return true; } void mitk::GrabCutOpenCVImageFilter::SetModelPoints(ModelPointsList foregroundPoints) { m_PointSetsMutex.lock(); m_ForegroundPoints = foregroundPoints; m_PointSetsMutex.unlock(); } void mitk::GrabCutOpenCVImageFilter::SetModelPoints(ModelPointsList foregroundPoints, ModelPointsList backgroundPoints) { m_PointSetsMutex.lock(); m_BackgroundPoints = backgroundPoints; m_ForegroundPoints = foregroundPoints; m_PointSetsMutex.unlock(); } void mitk::GrabCutOpenCVImageFilter::SetModelPoints(cv::Mat foregroundMask) { m_PointSetsMutex.lock(); m_ForegroundPoints = this->ConvertMaskToModelPointsList(foregroundMask); m_PointSetsMutex.unlock(); } void mitk::GrabCutOpenCVImageFilter::SetModelPoints(cv::Mat foregroundMask, cv::Mat backgroundMask) { m_PointSetsMutex.lock(); m_ForegroundPoints = this->ConvertMaskToModelPointsList(foregroundMask); m_BackgroundPoints = this->ConvertMaskToModelPointsList(backgroundMask); m_PointSetsMutex.unlock(); } void mitk::GrabCutOpenCVImageFilter::SetModelPointsDilationSize(int modelPointsDilationSize) { if ( modelPointsDilationSize < 0 ) { MITK_ERROR("AbstractOpenCVImageFilter")("GrabCutOpenCVImageFilter") << "Model points dilation size must not be smaller then zero."; mitkThrow() << "Model points dilation size must not be smaller then zero."; } m_ModelPointsDilationSize = modelPointsDilationSize; } void mitk::GrabCutOpenCVImageFilter::SetUseOnlyRegionAroundModelPoints(unsigned int additionalWidth) { m_UseOnlyRegionAroundModelPoints = true; m_AdditionalWidth = additionalWidth; } void mitk::GrabCutOpenCVImageFilter::SetUseFullImage() { m_UseOnlyRegionAroundModelPoints = false; } cv::Rect mitk::GrabCutOpenCVImageFilter::GetRegionAroundModelPoints() { return m_BoundingBox; } int mitk::GrabCutOpenCVImageFilter::GetResultImageId() { return m_ResultImageId; } cv::Mat mitk::GrabCutOpenCVImageFilter::GetResultMask() { cv::Mat result; m_ResultMutex.lock(); result = m_ResultMask.clone(); m_ResultMutex.unlock(); return result; } std::vector mitk::GrabCutOpenCVImageFilter::GetResultContours() { std::vector > cvContours; std::vector hierarchy; std::vector contourPoints; cv::Mat resultMask = this->GetResultMask(); if (resultMask.empty()) { return contourPoints; } cv::findContours(resultMask, cvContours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE); // convert cvContours to vector of ModelPointsLists for ( unsigned int i = 0; i < cvContours.size(); ++i ) { mitk::GrabCutOpenCVImageFilter::ModelPointsList curContourPoints; for ( auto it = cvContours[i].begin(); it != cvContours[i].end(); ++it) { itk::Index<2> index; index.SetElement(0, it->x); index.SetElement(1, it->y); curContourPoints.push_back(index); } contourPoints.push_back(curContourPoints); } return contourPoints; } mitk::GrabCutOpenCVImageFilter::ModelPointsList mitk::GrabCutOpenCVImageFilter::GetResultContourWithPixel(itk::Index<2> pixelIndex) { cv::Mat mask = this->GetResultMask(); if (mask.empty()) { return mitk::GrabCutOpenCVImageFilter::ModelPointsList(); } // return empty model point list if given pixel is outside the image borders if (pixelIndex.GetElement(0) < 0 || pixelIndex.GetElement(0) >= mask.size().height || pixelIndex.GetElement(1) < 0 || pixelIndex.GetElement(1) >= mask.size().width) { MITK_WARN("AbstractOpenCVImageFilter")("GrabCutOpenCVImageFilter") << "Given pixel index ("<< pixelIndex.GetElement(0) << ", " << pixelIndex.GetElement(1) << ") is outside the image (" << mask.size().height << ", " << mask.size().width << ")."; return mitk::GrabCutOpenCVImageFilter::ModelPointsList(); } // create a mask where the segmentation around the given pixel index is // set (done by flood filling the result mask using the pixel as seed) cv::floodFill(mask, cv::Point(pixelIndex.GetElement(0), pixelIndex.GetElement(1)), 5); cv::Mat foregroundMask; cv::compare(mask, 5, foregroundMask, cv::CMP_EQ); // find the contour on the flood filled image (there can be only one now) std::vector > cvContours; std::vector hierarchy; cv::findContours(foregroundMask, cvContours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_NONE); ModelPointsList contourPoints; // convert cvContours to ModelPointsList for ( auto it = cvContours[0].begin(); it != cvContours[0].end(); ++it) { itk::Index<2> index; index.SetElement(0, it->x); index.SetElement(1, it->y); contourPoints.push_back(index); } return contourPoints; } cv::Mat mitk::GrabCutOpenCVImageFilter::GetMaskFromPointSets() { // initialize mask with values of propably background cv::Mat mask(m_InputImage.size().height, m_InputImage.size().width, CV_8UC1, cv::GC_PR_BGD); // get foreground and background points (guarded by mutex) m_PointSetsMutex.lock(); ModelPointsList pointsLists[2] = {ModelPointsList(m_ForegroundPoints), ModelPointsList(m_BackgroundPoints)}; m_PointSetsMutex.unlock(); // define values for foreground and background pixels unsigned int pixelValues[2] = {cv::GC_FGD, cv::GC_BGD}; for (unsigned int n = 0; n < 2; ++n) { for (auto it = pointsLists[n].begin(); it != pointsLists[n].end(); ++it) { // set pixels around current pixel to the same value (size of this // area is specified by ModelPointsDilationSize) for ( int i = -m_ModelPointsDilationSize; i <= m_ModelPointsDilationSize; ++i ) { for ( int j = -m_ModelPointsDilationSize; j <= m_ModelPointsDilationSize; ++j) { int x = it->GetElement(1) + i; int y = it->GetElement(0) + j; if ( x >= 0 && y >= 0 && x < mask.cols && y < mask.rows) { mask.at(x, y) = pixelValues[n]; } } } } } return mask; } cv::Rect mitk::GrabCutOpenCVImageFilter::GetBoundingRectFromMask(cv::Mat mask) { cv::Mat nonPropablyBackgroundMask, modelPoints; cv::compare(mask, cv::GC_PR_BGD, nonPropablyBackgroundMask, cv::CMP_NE); cv::findNonZero(nonPropablyBackgroundMask, modelPoints); if (modelPoints.empty()) { MITK_WARN("AbstractOpenCVImageFilter")("GrabCutOpenCVImageFilter") << "Cannot find any foreground points. Returning full image size as bounding rectangle."; return cv::Rect(0, 0, mask.rows, mask.cols); } // calculate bounding rect around the model points cv::Rect boundingRect = cv::boundingRect(modelPoints); // substract additional width to x and y value (and make sure that they aren't outside the image then) boundingRect.x = static_cast(boundingRect.x) > m_AdditionalWidth ? boundingRect.x - m_AdditionalWidth : 0; boundingRect.y = static_cast(boundingRect.y) > m_AdditionalWidth ? boundingRect.y - m_AdditionalWidth : 0; // add additional width to width of bounding rect (twice as x value was moved before) // and make sure that the bounding rect will stay inside the image borders) if ( static_cast(boundingRect.x + boundingRect.width) + 2 * m_AdditionalWidth < static_cast(mask.size().width) ) { boundingRect.width += 2 * m_AdditionalWidth; } else { boundingRect.width = mask.size().width - boundingRect.x - 1; } // add additional width to height of bounding rect (twice as y value was moved before) // and make sure that the bounding rect will stay inside the image borders) if ( static_cast(boundingRect.y + boundingRect.height) + 2 * m_AdditionalWidth < static_cast(mask.size().height) ) { boundingRect.height += 2 * m_AdditionalWidth; } else { boundingRect.height = mask.size().height - boundingRect.y - 1; } assert(boundingRect.x + boundingRect.width < mask.size().width); assert(boundingRect.y + boundingRect.height < mask.size().height); return boundingRect; } cv::Mat mitk::GrabCutOpenCVImageFilter::RunSegmentation(cv::Mat input, cv::Mat mask) { // test if foreground and background models are large enough for GrabCut cv::Mat compareFgResult, compareBgResult; cv::compare(mask, cv::GC_FGD, compareFgResult, cv::CMP_EQ); cv::compare(mask, cv::GC_PR_BGD, compareBgResult, cv::CMP_EQ); if ( cv::countNonZero(compareFgResult) < GMM_COMPONENTS_COUNT || cv::countNonZero(compareBgResult) < GMM_COMPONENTS_COUNT) { // return result mask with no pixels set to foreground return cv::Mat::zeros(mask.size(), mask.type()); } // do the actual grab cut segmentation (initialized with the mask) cv::Mat bgdModel, fgdModel; cv::grabCut(input, mask, cv::Rect(), bgdModel, fgdModel, 1, cv::GC_INIT_WITH_MASK); // set propably foreground pixels to white on result mask cv::Mat result; cv::compare(mask, cv::GC_PR_FGD, result, cv::CMP_EQ); // set foreground pixels to white on result mask cv::Mat foregroundMat; cv::compare(mask, cv::GC_FGD, foregroundMat, cv::CMP_EQ); foregroundMat.copyTo(result, foregroundMat); return result; // now the result mask can be returned } mitk::GrabCutOpenCVImageFilter::ModelPointsList mitk::GrabCutOpenCVImageFilter::ConvertMaskToModelPointsList(cv::Mat mask) { cv::Mat points; cv::findNonZero(mask, points); // push extracted points into a vector of itk indices ModelPointsList pointsVector; for ( size_t n = 0; n < points.total(); ++n) { itk::Index<2> index; index.SetElement(0, points.at(n).x); index.SetElement(1, points.at(n).y); pointsVector.push_back(index); } return pointsVector; } void mitk::GrabCutOpenCVImageFilter::SegmentationWorker() { std::mutex mutex; std::unique_lock lock(mutex); while (true) { m_WorkerBarrier.wait(lock, [this] { return !m_StopThread; }); m_ImageMutex.lock(); cv::Mat image = m_InputImage.clone(); int inputImageId = m_InputImageId; m_ImageMutex.unlock(); cv::Mat mask = this->GetMaskFromPointSets(); cv::Mat result; if (m_UseOnlyRegionAroundModelPoints) { result = cv::Mat(mask.rows, mask.cols, mask.type(), 0.0); m_BoundingBox = this->GetBoundingRectFromMask(mask); RunSegmentation(image(m_BoundingBox), mask(m_BoundingBox)).copyTo(result(m_BoundingBox)); } else { result = this->RunSegmentation(image, mask); } // save result to member attribute m_ResultMutex.lock(); m_ResultMask = result; m_ResultImageId = inputImageId; m_ResultMutex.unlock(); } } diff --git a/Modules/OpenCVVideoSupport/Testing/mitkBasicCombinationOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkBasicCombinationOpenCVImageFilterTest.cpp index 215ea78ac6..bd2ab53c9f 100644 --- a/Modules/OpenCVVideoSupport/Testing/mitkBasicCombinationOpenCVImageFilterTest.cpp +++ b/Modules/OpenCVVideoSupport/Testing/mitkBasicCombinationOpenCVImageFilterTest.cpp @@ -1,88 +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 "mitkBasicCombinationOpenCVImageFilter.h" #include "mitkConvertGrayscaleOpenCVImageFilter.h" #include "mitkCropOpenCVImageFilter.h" #include -#include +#include +#include #include static bool ImagesAreEqualInGray(const cv::Mat& img1, const cv::Mat& img2) { cv::Mat grayImg1; cv::Mat grayImg2; cv::cvtColor(img1, grayImg1, CV_RGB2GRAY, 1); cv::cvtColor(img2, grayImg2, CV_RGB2GRAY, 1); return cv::countNonZero(grayImg1 != grayImg2) == 0; } static void ConvertTestLoadedImage(std::string mitkImagePath) { cv::Mat image = cv::imread(mitkImagePath.c_str()); cv::Mat compareImg = image.clone(); mitk::BasicCombinationOpenCVImageFilter::Pointer combinationFilter = mitk::BasicCombinationOpenCVImageFilter::New(); MITK_TEST_CONDITION(combinationFilter->FilterImage(image), "Filtering with empty filter list is ok."); MITK_TEST_CONDITION(ImagesAreEqualInGray(image, compareImg), "Image must not be changed after filtering with empty filter list."); mitk::ConvertGrayscaleOpenCVImageFilter::Pointer grayscaleFilter = mitk::ConvertGrayscaleOpenCVImageFilter::New(); combinationFilter->PushFilter(grayscaleFilter.GetPointer()); MITK_TEST_CONDITION(combinationFilter->FilterImage(image), "Filtering with grayscale filter should be ok."); MITK_TEST_CONDITION(image.channels() == 1, "Image must not have more than one channel after grayscale conversion."); image.release(); image = compareImg.clone(); mitk::CropOpenCVImageFilter::Pointer cropFilter = mitk::CropOpenCVImageFilter::New(); combinationFilter->PushFilter(cropFilter.GetPointer()); MITK_TEST_CONDITION( ! combinationFilter->FilterImage(image), "Filter function must return false if an filter returns false."); MITK_TEST_CONDITION(combinationFilter->PopFilter() == cropFilter, "Last added filter is equal to returned filter."); image.release(); image = compareImg.clone(); MITK_TEST_CONDITION(combinationFilter->FilterImage(image), "Filter function should return true again after removing incorrect filter."); MITK_TEST_CONDITION(combinationFilter->RemoveFilter(grayscaleFilter.GetPointer()), "Filter must be found."); image.release(); image = compareImg.clone(); MITK_TEST_CONDITION(combinationFilter->FilterImage(image), "Filter function should still return true."); MITK_TEST_CONDITION(ImagesAreEqualInGray(image, compareImg), "Image must not be changed after all filters were removed."); } /**Documentation * test for the class "ConvertGrayscaleOpenCVImageFilter". */ int mitkBasicCombinationOpenCVImageFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("BasicCombinationOpenCVImageFilter") MITK_TEST_CONDITION_REQUIRED(argc == 2, "Two parameters are needed for this test.") ConvertTestLoadedImage(argv[1]); MITK_TEST_END(); // always end with this! } diff --git a/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp index 734589e1d4..cb063aa307 100644 --- a/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp +++ b/Modules/OpenCVVideoSupport/Testing/mitkConvertGrayscaleOpenCVImageFilterTest.cpp @@ -1,53 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkConvertGrayscaleOpenCVImageFilter.h" #include #include +#include #include static void ConvertTestLoadedImage(std::string mitkImagePath, std::string mitkGrayscaleImagePath) { cv::Mat image = cv::imread(mitkImagePath.c_str()); cv::Mat compareImg = cv::imread(mitkGrayscaleImagePath.c_str()); // directly convert the image for comparison cv::Mat comparisonImg; cv::cvtColor(compareImg, comparisonImg, CV_RGB2GRAY, 1); mitk::ConvertGrayscaleOpenCVImageFilter::Pointer grayscaleFilter = mitk::ConvertGrayscaleOpenCVImageFilter::New(); MITK_TEST_CONDITION(grayscaleFilter->FilterImage(image), "Filtering should return true for success."); MITK_TEST_CONDITION(image.channels() == 1, "Image must not have more than one channel after grayscale conversion."); MITK_TEST_CONDITION(cv::countNonZero(image != comparisonImg) == 0, "All pixel values must be the same between the two converted images."); MITK_TEST_CONDITION_REQUIRED(grayscaleFilter->FilterImage(image), "Image conversion should be no problem if image is a grayscale image already.") } /**Documentation * test for the class "ConvertGrayscaleOpenCVImageFilter". */ int mitkConvertGrayscaleOpenCVImageFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("ConvertGrayscaleOpenCVImageFilter") MITK_TEST_CONDITION_REQUIRED(argc > 2, "At least three parameters needed for this test.") ConvertTestLoadedImage(argv[1], argv[2]); MITK_TEST_END(); // always end with this! } diff --git a/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp index 954b9c2791..d9f59c6bbd 100644 --- a/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp +++ b/Modules/OpenCVVideoSupport/Testing/mitkCropOpenCVImageFilterTest.cpp @@ -1,97 +1,98 @@ /*============================================================================ 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 "mitkCropOpenCVImageFilter.h" #include #include +#include #include static bool ImagesAreEqualInGray(const cv::Mat& img1, const cv::Mat& img2) { cv::Mat grayImg1; cv::Mat grayImg2; cv::cvtColor(img1, grayImg1, CV_RGB2GRAY, 1); cv::cvtColor(img2, grayImg2, CV_RGB2GRAY, 1); return cv::countNonZero(grayImg1 != grayImg2) == 0; } static void CropTestLoadedImage(std::string mitkImagePath, std::string mitkCroppedImagePath) { cv::Mat image = cv::imread(mitkImagePath.c_str()); cv::Mat croppedImage = cv::imread(mitkCroppedImagePath.c_str()); MITK_INFO << mitkImagePath.c_str(); MITK_INFO << mitkCroppedImagePath.c_str(); mitk::CropOpenCVImageFilter::Pointer cropFilter = mitk::CropOpenCVImageFilter::New(); // try to crop without setting a region of interest cv::Mat testImage = image.clone(); MITK_TEST_CONDITION( ! cropFilter->FilterImage(testImage), "Filter function must return false if no region of interest is set."); MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image), "Image should not be changed yet."); // set region of interst now and then try to crop again cv::Rect roi = cv::Rect(0,0, testImage.cols, testImage.rows); cropFilter->SetCropRegion(roi); MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image), "Image should not be changed if cropping with a roi of the whole image."); // test if filter corrects negative roi position cv::Rect roiWrong = cv::Rect(-1,-1, 2, 2); roi = cv::Rect(0,0,2,2); cropFilter->SetCropRegion(roiWrong); MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, image(roi)), "Image should be equal to directly cropped image whith correct roi."); // test whith "normal" roi testImage = image.clone(); roi = cv::Rect( 150,100,100,100 ); cropFilter->SetCropRegion(roi); MITK_TEST_CONDITION(cropFilter->FilterImage(testImage), "Filter function should return successfully."); MITK_TEST_CONDITION(ImagesAreEqualInGray(testImage, croppedImage), "Image should be equal to cropped image (loaded from data directory)."); // test with not correctable roi roiWrong = cv::Rect( 5,5,-1,-1 ); MITK_TEST_FOR_EXCEPTION(mitk::Exception, cropFilter->SetCropRegion(roiWrong)); // test with rois where the top left corner is outside the image boundaries roiWrong = cv::Rect( testImage.cols,0,1,1 ); cropFilter->SetCropRegion(roiWrong); MITK_TEST_CONDITION(!cropFilter->FilterImage(testImage), "Filter function should return unsuccessfully if top left corner is outside image boundary (cols)."); roiWrong = cv::Rect( 0,testImage.rows,1,1 ); cropFilter->SetCropRegion(roiWrong); MITK_TEST_CONDITION(!cropFilter->FilterImage(testImage), "Filter function should return unsuccessfully if top left corner is outside image boundary (rows)."); roiWrong = cv::Rect( testImage.cols,testImage.rows,1,1 ); cropFilter->SetCropRegion(roiWrong); MITK_TEST_CONDITION(!cropFilter->FilterImage(testImage), "Filter function should return unsuccessfully if top left corner is outside image boundary (cols+rows)."); } /**Documentation * test for the class "CropOpenCVImageFilter". */ int mitkCropOpenCVImageFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("CropOpenCVImageFilter") MITK_TEST_CONDITION_REQUIRED(argc > 2, "At least three parameters needed for this test."); CropTestLoadedImage(argv[1], argv[2]); MITK_TEST_END(); // always end with this! } diff --git a/Modules/OpenCVVideoSupport/Testing/mitkGrabCutOpenCVImageFilterTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkGrabCutOpenCVImageFilterTest.cpp index be50a4358c..4d9288e879 100644 --- a/Modules/OpenCVVideoSupport/Testing/mitkGrabCutOpenCVImageFilterTest.cpp +++ b/Modules/OpenCVVideoSupport/Testing/mitkGrabCutOpenCVImageFilterTest.cpp @@ -1,177 +1,178 @@ /*============================================================================ 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 "mitkGrabCutOpenCVImageFilter.h" #include #include "itkIndex.h" #include #include +#include #include #include "mitkOpenCVToMitkImageFilter.h" static void GrabCutTestLoadedImage(std::string imagePath, std::string maskPath, std::string resultMaskPath) { // load test images cv::Mat image = cv::imread(imagePath.c_str()); cv::Mat maskImage = cv::imread(maskPath.c_str()); cv::Mat resultMaskImage = cv::imread(resultMaskPath.c_str()); // make sure that the loaded mask is a gray scale image cv::Mat maskImageGray; cv::cvtColor(maskImage, maskImageGray, CV_RGB2GRAY, 1); // make sure that the loaded reference image is a gray scale image cv::Mat resultMaskImageGray; cv::cvtColor(resultMaskImage, resultMaskImageGray, CV_RGB2GRAY, 1); // extract foreground points from loaded mask image cv::Mat foregroundMask, foregroundPoints; cv::compare(maskImageGray, 250, foregroundMask, cv::CMP_GE); cv::findNonZero(foregroundMask, foregroundPoints); // push extracted forground points into a vector of itk indices std::vector > foregroundPointsVector; for ( size_t n = 0; n < foregroundPoints.total(); ++n) { itk::Index<2> index; index.SetElement(0, foregroundPoints.at(n).x); index.SetElement(1, foregroundPoints.at(n).y); foregroundPointsVector.push_back(index); } mitk::GrabCutOpenCVImageFilter::Pointer grabCutFilter = mitk::GrabCutOpenCVImageFilter::New(); int currentImageId = 0; // test filtering with image set but no model points set { MITK_TEST_CONDITION(grabCutFilter->FilterImage(image), "Filtering should return true for sucess.") cv::Mat resultMask = grabCutFilter->GetResultMask(); MITK_TEST_CONDITION(resultMask.empty(), "Result mask must be empty when no foreground points are set.") } // test filtering with very little model points set { std::vector > littleForegroundPointsSet(foregroundPointsVector.begin(), foregroundPointsVector.begin()+3); grabCutFilter->SetModelPoints(littleForegroundPointsSet); grabCutFilter->FilterImage(image, ++currentImageId); cv::Mat resultMask; // wait up to ten seconds for the segmentation to finish for (unsigned int n = 0; n < 100; ++n) { if ( grabCutFilter->GetResultImageId() == currentImageId ) { resultMask = grabCutFilter->GetResultMask(); break; } itksys::SystemTools::Delay(100); } MITK_TEST_CONDITION(!resultMask.empty(), "Result mask must not be empty when little (" << littleForegroundPointsSet.size() <<") foreground points are set."); } // test filtering with image and model points set { grabCutFilter->SetModelPoints(foregroundPointsVector); MITK_TEST_CONDITION(grabCutFilter->FilterImage(image, ++currentImageId), "Filtering should return true for sucess.") cv::Mat resultMask; // wait up to ten seconds for the segmentation to finish for (unsigned int n = 0; n < 100; ++n) { if ( grabCutFilter->GetResultImageId() == currentImageId ) { resultMask = grabCutFilter->GetResultMask(); break; } itksys::SystemTools::Delay(100); } MITK_TEST_CONDITION( ! resultMask.empty() && cv::countNonZero(resultMask != resultMaskImageGray) == 0, "Filtered image should match reference image.") // adding new image should still work MITK_TEST_CONDITION(grabCutFilter->FilterImage(image), "Adding new image should still work.") } // test filtering with using only region around model points // (but with really big additional width so that whole image should be used again) { grabCutFilter->SetUseOnlyRegionAroundModelPoints(image.cols); grabCutFilter->FilterImage(image, ++currentImageId); cv::Mat resultMask; // wait up to ten seconds for the segmentation to finish for (unsigned int n = 0; n < 100; ++n) { if (grabCutFilter->GetResultImageId() == currentImageId) { resultMask = grabCutFilter->GetResultMask(); break; } itksys::SystemTools::Delay(100); } MITK_TEST_CONDITION( ! resultMask.empty() && cv::countNonZero(resultMask != resultMaskImageGray) == 0, "Filtered image with really big region used should match reference image again.") } // test filtering with using only region around model points { grabCutFilter->SetUseOnlyRegionAroundModelPoints(0); grabCutFilter->FilterImage(image, ++currentImageId); cv::Mat resultMask; // wait up to ten seconds for the segmentation to finish for (unsigned int n = 0; n < 100; ++n) { if (grabCutFilter->GetResultImageId() == currentImageId) { resultMask = grabCutFilter->GetResultMask(); break; } itksys::SystemTools::Delay(100); } cv::Mat nonPropablyBackgroundMask, modelPoints; cv::compare(maskImageGray, 250, nonPropablyBackgroundMask, cv::CMP_GE); cv::findNonZero(nonPropablyBackgroundMask, modelPoints); cv::Rect boundingRect = cv::boundingRect(modelPoints); cv::Mat compareMask(resultMask.rows, resultMask.cols, resultMask.type(), 0.0); resultMaskImageGray(boundingRect).copyTo(compareMask(boundingRect)); MITK_TEST_CONDITION( ! resultMask.empty() && cv::countNonZero(resultMask != compareMask) == 0, "Filtered image with region just around the model points used should match reference image again.") } } int mitkGrabCutOpenCVImageFilterTest(int argc, char* argv[]) { MITK_TEST_BEGIN("GrabCutOpenCVImageFilter") MITK_TEST_CONDITION_REQUIRED(argc == 4, "Test needs four command line parameters.") GrabCutTestLoadedImage(argv[1], argv[2], argv[3]); MITK_TEST_END() // always end with this! } diff --git a/Modules/OpenCVVideoSupport/Testing/mitkOpenCVMitkConversionTest.cpp b/Modules/OpenCVVideoSupport/Testing/mitkOpenCVMitkConversionTest.cpp index a5c5b0a068..0ed282d3a3 100644 --- a/Modules/OpenCVVideoSupport/Testing/mitkOpenCVMitkConversionTest.cpp +++ b/Modules/OpenCVVideoSupport/Testing/mitkOpenCVMitkConversionTest.cpp @@ -1,247 +1,246 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // mitk includes #include "mitkImageToOpenCVImageFilter.h" #include "mitkOpenCVToMitkImageFilter.h" #include #include #include #include #include "mitkImageReadAccessor.h" #include "mitkImageSliceSelector.h" // itk includes #include #include -#include // define test pixel indexes and intensities and other values typedef itk::RGBPixel< unsigned char > TestUCRGBPixelType; cv::Size testImageSize; cv::Point pos1; cv::Point pos2; cv::Point pos3; cv::Vec3b color1; cv::Vec3b color2; cv::Vec3b color3; uchar greyValue1; uchar greyValue2; uchar greyValue3; /*! Documentation * Test for image conversion of OpenCV images and mitk::Images. It tests the classes * OpenCVToMitkImageFilter and ImageToOpenCVImageFilter */ // Some declarations template void ComparePixels( itk::Image,VImageDimension>* image ); void ReadImageDataAndConvertForthAndBack(std::string imageFileName); void ConvertCVMatForthAndBack(mitk::Image::Pointer inputForCVMat, std::string imageFileName); // Begin the test for mitkImage to OpenCV image conversion and back. int mitkOpenCVMitkConversionTest(int argc, char* argv[]) { MITK_TEST_BEGIN("ImageToOpenCVImageFilter") // the first part of this test checks the conversion of a cv::Mat style OpenCV image. // we build an cv::Mat image MITK_INFO << "setting test values"; testImageSize = cv::Size(11,11); pos1 = cv::Point(0,0); pos2 = cv::Point(5,5); pos3 = cv::Point(10,10); color1 = cv::Vec3b(50,0,0); color2 = cv::Vec3b(0,128,0); color3 = cv::Vec3b(0,0,255); greyValue1 = 0; greyValue2 = 128; greyValue3 = 255; MITK_INFO << "generating test OpenCV image (RGB)"; cv::Mat testRGBImage = cv::Mat::zeros( testImageSize, CV_8UC3 ); // generate some test intensity values testRGBImage.at(pos1)= color1; testRGBImage.at(pos2)= color2; testRGBImage.at(pos3)= color3; // convert it to a mitk::Image MITK_INFO << "converting OpenCV test image to mitk image and comparing scalar rgb values"; mitk::OpenCVToMitkImageFilter::Pointer openCvToMitkFilter = mitk::OpenCVToMitkImageFilter::New(); openCvToMitkFilter->SetOpenCVMat( testRGBImage ); openCvToMitkFilter->Update(); mitk::Image::Pointer mitkImage = openCvToMitkFilter->GetOutput(); AccessFixedTypeByItk(mitkImage.GetPointer(), ComparePixels, (itk::RGBPixel), // rgb image (2) ); // convert it back to OpenCV image MITK_INFO << "converting mitk image to OpenCV image and comparing scalar rgb values"; mitk::ImageToOpenCVImageFilter::Pointer mitkToOpenCv = mitk::ImageToOpenCVImageFilter::New(); mitkToOpenCv->SetImage( mitkImage ); cv::Mat openCvImage = mitkToOpenCv->GetOpenCVMat(); // and test equality of the sentinel pixel cv::Vec3b convertedColor1 = openCvImage.at(pos1); cv::Vec3b convertedColor2 = openCvImage.at(pos2); cv::Vec3b convertedColor3 = openCvImage.at(pos3); MITK_TEST_CONDITION( color1 == convertedColor1, "Testing if initially created color values " << static_cast( color1[0] ) << ", " << static_cast( color1[1] ) << ", " << static_cast( color1[2] ) << " matches the color values " << static_cast( convertedColor1[0] ) << ", " << static_cast( convertedColor1[1] ) << ", " << static_cast( convertedColor1[2] ) << " at the same position " << pos1.x << ", " << pos1.y << " in the back converted OpenCV image" ) MITK_TEST_CONDITION( color2 == convertedColor2, "Testing if initially created color values " << static_cast( color2[0] ) << ", " << static_cast( color2[1] ) << ", " << static_cast( color2[2] ) << " matches the color values " << static_cast( convertedColor2[0] ) << ", " << static_cast( convertedColor2[1] ) << ", " << static_cast( convertedColor2[2] ) << " at the same position " << pos2.x << ", " << pos2.y << " in the back converted OpenCV image" ) MITK_TEST_CONDITION( color3 == convertedColor3, "Testing if initially created color values " << static_cast( color3[0] ) << ", " << static_cast( color3[1] ) << ", " << static_cast( color3[2] ) << " matches the color values " << static_cast( convertedColor3[0] ) << ", " << static_cast( convertedColor3[1] ) << ", " << static_cast( convertedColor3[2] ) << " at the same position " << pos3.x << ", " << pos3.y << " in the back converted OpenCV image" ) // the second part of this test checks the conversion of mitk::Image to cv::Mat and back. for (int i = 1; i < argc; ++i) { ReadImageDataAndConvertForthAndBack(argv[i]); } MITK_TEST_END(); } template void ComparePixels( itk::Image,VImageDimension>* image ) { typedef itk::RGBPixel PixelType; typedef itk::Image ImageType; typename ImageType::IndexType pixelIndex; pixelIndex[0] = pos1.x; pixelIndex[1] = pos1.y; PixelType onePixel = image->GetPixel( pixelIndex ); MITK_TEST_CONDITION( color1[0] == onePixel.GetBlue(), "Testing if blue value (= " << static_cast(color1[0]) << ") at postion " << pos1.x << ", " << pos1.y << " in OpenCV image is " << "equals the blue value (= " << static_cast(onePixel.GetBlue()) << ")" << " in the generated mitk image"); pixelIndex[0] = pos2.x; pixelIndex[1] = pos2.y; onePixel = image->GetPixel( pixelIndex ); MITK_TEST_CONDITION( color2[1] == onePixel.GetGreen(), "Testing if green value (= " << static_cast(color2[1]) << ") at postion " << pos2.x << ", " << pos2.y << " in OpenCV image is " << "equals the green value (= " << static_cast(onePixel.GetGreen()) << ")" << " in the generated mitk image"); pixelIndex[0] = pos3.x; pixelIndex[1] = pos3.y; onePixel = image->GetPixel( pixelIndex ); MITK_TEST_CONDITION( color3[2] == onePixel.GetRed(), "Testing if red value (= " << static_cast(color3[2]) << ") at postion " << pos3.x << ", " << pos3.y << " in OpenCV image is " << "equals the red value (= " << static_cast(onePixel.GetRed()) << ")" << " in the generated mitk image"); } void ReadImageDataAndConvertForthAndBack(std::string imageFileName) { // first we load an mitk::Image from the data repository mitk::Image::Pointer mitkTestImage = mitk::IOUtil::Load(imageFileName); // some format checking mitk::Image::Pointer resultImg = nullptr; if( mitkTestImage->GetDimension() <= 3 ) { if( mitkTestImage->GetDimension() > 2 && mitkTestImage->GetDimension(2) == 1 ) { mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); sliceSelector->SetInput(mitkTestImage); sliceSelector->SetSliceNr(0); sliceSelector->Update(); resultImg = sliceSelector->GetOutput()->Clone(); } else if(mitkTestImage->GetDimension() < 3) { resultImg = mitkTestImage; } else { return; // 3D images are not supported, except with just one slice. } } else { return; // 4D images are not supported! } ConvertCVMatForthAndBack(resultImg, imageFileName); } void ConvertCVMatForthAndBack(mitk::Image::Pointer inputForCVMat, std::string) { // now we convert it to OpenCV Mat mitk::ImageToOpenCVImageFilter::Pointer toOCvConverter = mitk::ImageToOpenCVImageFilter::New(); toOCvConverter->SetImage(inputForCVMat); cv::Mat cvmatTestImage = toOCvConverter->GetOpenCVMat(); MITK_TEST_CONDITION_REQUIRED( !cvmatTestImage.empty(), "Conversion to cv::Mat successful!"); mitk::OpenCVToMitkImageFilter::Pointer toMitkConverter = mitk::OpenCVToMitkImageFilter::New(); toMitkConverter->SetOpenCVMat(cvmatTestImage); toMitkConverter->Update(); // initialize the image with the input image, since we want to test equality and OpenCV does not feature geometries and spacing mitk::Image::Pointer result = inputForCVMat->Clone(); mitk::ImageReadAccessor resultAcc(toMitkConverter->GetOutput(), toMitkConverter->GetOutput()->GetSliceData()); result->SetImportSlice(const_cast(resultAcc.GetData())); if( result->GetPixelType().GetNumberOfComponents() == 1 ) { MITK_ASSERT_EQUAL( result, inputForCVMat, "Testing equality of input and output image of cv::Mat conversion" ); } else if( result->GetPixelType().GetNumberOfComponents() == 3 ) { MITK_ASSERT_EQUAL( result, inputForCVMat, "Testing equality of input and output image of cv::Mat conversion" ); } else { MITK_WARN << "Unhandled number of components used to test equality, please enhance test!"; } // change OpenCV image to test if the filter gets updated cv::Mat changedcvmatTestImage = cvmatTestImage.clone(); if (result->GetPixelType().GetBitsPerComponent() == sizeof(char)*8) { changedcvmatTestImage.at(0,0) = cvmatTestImage.at(0,0) != 0 ? 0 : 1; } else if (result->GetPixelType().GetBitsPerComponent() == sizeof(float)*8) { changedcvmatTestImage.at(0,0) = cvmatTestImage.at(0,0) != 0 ? 0 : 1; } toMitkConverter->SetOpenCVMat(changedcvmatTestImage); toMitkConverter->Update(); MITK_TEST_NOT_EQUAL(toMitkConverter->GetOutput(), inputForCVMat, "Converted image must not be the same as before."); } diff --git a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.cpp b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.cpp index 41dc3fef68..7127bd0068 100644 --- a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.cpp +++ b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.cpp @@ -1,444 +1,446 @@ /*============================================================================ 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 "QmitkOpenCVVideoControls.h" #include #include #include #include +#include + class QmitkOpenCVVideoControlsPrivate { public: QmitkOpenCVVideoControlsPrivate(QmitkOpenCVVideoControls* q, const std::string& id) : q(q) , m_Id(id) {} /// /// muellerm: persitence service implementation /// PERSISTENCE_GET_SERVICE_METHOD_MACRO QmitkOpenCVVideoControls* q; /// /// muellerm: a unique id for the prop list /// std::string m_Id; void ToPropertyList(); void FromPropertyList(); }; QmitkOpenCVVideoControls::QmitkOpenCVVideoControls(QmitkVideoBackground* _VideoBackground , QmitkRenderWindow* _RenderWindow , QWidget * parent, Qt::WindowFlags f) : QWidget(parent, f) , m_VideoBackground(nullptr) , m_RenderWindow(nullptr) , m_VideoSource(nullptr) , m_Controls(new Ui::QmitkOpenCVVideoControls) , m_SliderCurrentlyMoved(false) , d(new QmitkOpenCVVideoControlsPrivate(this, "QmitkOpenCVVideoControls")) { m_Controls->setupUi(this); m_Controls->FileChooser->SetFileMustExist(true); m_Controls->FileChooser->SetSelectDir(false); this->SetRenderWindow(_RenderWindow); this->SetVideoBackground(_VideoBackground); d->FromPropertyList(); mitk::IPersistenceService* persistenceService = d->GetPersistenceService(); if (persistenceService != nullptr) { persistenceService->AddPropertyListReplacedObserver(this); } else { MITK_WARN << "No Persistence Service available in constructor"; } } QmitkOpenCVVideoControls::~QmitkOpenCVVideoControls() { if (m_VideoSource != nullptr && m_VideoSource->IsCapturingEnabled()) { this->Stop(); // emulate stop } mitk::IPersistenceService* persistenceService = d->GetPersistenceService(); if (persistenceService != nullptr) { persistenceService->RemovePropertyListReplacedObserver(this); } else { MITK_WARN << "No Persistence Service available in destructor"; } d->ToPropertyList(); } void QmitkOpenCVVideoControls::on_VideoProgressSlider_valueChanged(int /*value*/) { //Fixes T23169 on_VideoProgressSlider_sliderReleased(); } void QmitkOpenCVVideoControls::on_UseGrabbingDeviceButton_clicked(bool /*checked=false*/) { m_Controls->GrabbingDevicePanel->setEnabled(true); m_Controls->VideoFilePanel->setEnabled(false); } void QmitkOpenCVVideoControls::on_UseVideoFileButton_clicked(bool /*checked=false*/) { m_Controls->GrabbingDevicePanel->setEnabled(false); m_Controls->VideoFilePanel->setEnabled(true); m_Controls->FileChooser->setEnabled(true); } void QmitkOpenCVVideoControls::on_VideoProgressSlider_sliderPressed() { m_SliderCurrentlyMoved = true; // temporary pause the video while sliding if (!m_VideoSource->GetCapturePaused()) m_VideoSource->PauseCapturing(); } void QmitkOpenCVVideoControls::on_VideoProgressSlider_sliderReleased() { double progressRatio = static_cast(m_Controls->VideoProgressSlider->value()) / static_cast(m_Controls->VideoProgressSlider->maximum()); m_VideoSource->SetVideoCaptureProperty(CV_CAP_PROP_POS_FRAMES, progressRatio*m_VideoSource->GetVideoCaptureProperty(CV_CAP_PROP_FRAME_COUNT)); // resume the video ( if it was not paused by the user) if (m_VideoSource->GetCapturePaused() && m_Controls->PlayButton->isChecked()) m_VideoSource->PauseCapturing(); m_SliderCurrentlyMoved = false; } void QmitkOpenCVVideoControls::on_RepeatVideoButton_clicked(bool checked) { MITK_INFO << "repeat video clicked"; m_VideoSource->SetRepeatVideo(checked); } void QmitkOpenCVVideoControls::on_PlayButton_clicked(bool checked) { MITK_INFO << "play button clicked"; if (checked) { this->Play(); } else { // show pause button this->IsPlaying(true); m_VideoSource->PauseCapturing(); } } void QmitkOpenCVVideoControls::on_StopButton_clicked(bool /*checked=false*/) { this->Stop(); } void QmitkOpenCVVideoControls::Play() { if (m_VideoSource->GetCapturePaused()) { this->IsPlaying(false); m_VideoSource->PauseCapturing(); } else { if (m_Controls->UseGrabbingDeviceButton->isChecked()) { m_VideoSource->SetVideoCameraInput(m_Controls->GrabbingDeviceNumber->text().toInt(), false); m_Controls->VideoFileControls->setEnabled(false); } else { m_VideoSource->SetVideoFileInput(m_Controls->FileChooser->GetFile().c_str(), m_Controls->RepeatVideoButton->isChecked(), false); m_VideoSource->SetRepeatVideo(m_Controls->RepeatVideoButton->isChecked()); m_Controls->VideoProgressSlider->setValue(0); } m_VideoSource->StartCapturing(); if (!m_VideoSource->IsCapturingEnabled()) { MITK_ERROR << "Video could not be initialized!"; m_Controls->PlayButton->setChecked(false); } else { int hertz = m_Controls->UpdateRate->text().toInt(); int updateTime = itk::Math::Round(1000.0 / hertz); // resets the whole background m_VideoBackground->SetTimerDelay(updateTime); m_VideoBackground->AddRenderWindow(m_RenderWindow->GetVtkRenderWindow()); this->connect(m_VideoBackground, SIGNAL(NewFrameAvailable(mitk::VideoSource*)) , this, SLOT(NewFrameAvailable(mitk::VideoSource*))); this->connect(m_VideoBackground, SIGNAL(EndOfVideoSourceReached(mitk::VideoSource*)) , this, SLOT(EndOfVideoSourceReached(mitk::VideoSource*))); m_VideoBackground->Enable(); this->m_Controls->StopButton->setEnabled(true); // show video file controls if (m_Controls->UseVideoFileButton->isChecked()) { m_Controls->VideoFileControls->setEnabled(true); m_Controls->RepeatVideoButton->setEnabled(true); m_Controls->VideoProgressSlider->setEnabled(true); } // show pause button this->IsPlaying(false); // disable other controls m_Controls->GrabbingDevicePanel->setEnabled(false); m_Controls->VideoFilePanel->setEnabled(false); m_Controls->UseGrabbingDeviceButton->setEnabled(false); m_Controls->UseVideoFileButton->setEnabled(false); m_Controls->UpdateRatePanel->setEnabled(false); } } } void QmitkOpenCVVideoControls::Stop() { // disable video file controls, stop button and show play button again m_Controls->UseGrabbingDeviceButton->setEnabled(true); m_Controls->UseVideoFileButton->setEnabled(true); if (m_Controls->UseGrabbingDeviceButton->isChecked()) on_UseGrabbingDeviceButton_clicked(true); else on_UseVideoFileButton_clicked(true); m_Controls->UpdateRatePanel->setEnabled(true); m_Controls->VideoProgressSlider->setValue(0); m_Controls->VideoFileControls->setEnabled(false); this->m_Controls->StopButton->setEnabled(false); this->IsPlaying(true); if (m_VideoBackground) { m_VideoBackground->Disable(); if (m_RenderWindow) m_VideoBackground->RemoveRenderWindow(m_RenderWindow->GetVtkRenderWindow()); this->disconnect(m_VideoBackground, SIGNAL(NewFrameAvailable(mitk::VideoSource*)) , this, SLOT(NewFrameAvailable(mitk::VideoSource*))); } if (m_VideoSource != nullptr) m_VideoSource->StopCapturing(); } void QmitkOpenCVVideoControls::Reset() { this->Stop(); } void QmitkOpenCVVideoControls::IsPlaying(bool paused) { if (paused) { m_Controls->PlayButton->setText("Play"); m_Controls->PlayButton->setIcon(QIcon(":/OpenCVVideoSupportUI/media-playback-start.png")); m_Controls->PlayButton->setChecked(false); } else { m_Controls->PlayButton->setText("Pause"); m_Controls->PlayButton->setIcon(QIcon(":/OpenCVVideoSupportUI/media-playback-pause.png")); m_Controls->PlayButton->setChecked(true); } } void QmitkOpenCVVideoControls::NewFrameAvailable(mitk::VideoSource* /*videoSource*/) { emit NewOpenCVFrameAvailable(m_VideoSource->GetCurrentFrame()); if (!m_SliderCurrentlyMoved) { m_Controls->VideoProgressSlider->setValue(itk::Math::Round(m_VideoSource->GetVideoCaptureProperty(CV_CAP_PROP_POS_FRAMES) *(1 / m_VideoSource->GetVideoCaptureProperty(CV_CAP_PROP_FRAME_COUNT) *m_Controls->VideoProgressSlider->maximum()))); } } void QmitkOpenCVVideoControls::EndOfVideoSourceReached(mitk::VideoSource* /*videoSource*/) { if (m_Controls->RepeatVideoButton->isChecked()) { this->Reset(); this->Play(); } else { this->Stop(); } } void QmitkOpenCVVideoControls::SetRenderWindow(QmitkRenderWindow* _RenderWindow) { if (m_RenderWindow == _RenderWindow) return; // In Reset() m_MultiWidget is used, set it to 0 now for avoiding errors if (_RenderWindow == nullptr) m_RenderWindow = nullptr; this->Reset(); m_RenderWindow = _RenderWindow; if (m_RenderWindow == nullptr) { this->setEnabled(false); } else { this->setEnabled(true); } } QmitkRenderWindow* QmitkOpenCVVideoControls::GetRenderWindow() const { return m_RenderWindow; } void QmitkOpenCVVideoControls::SetVideoBackground(QmitkVideoBackground* _VideoBackground) { if (m_VideoBackground == _VideoBackground) return; if (m_VideoBackground != nullptr) this->disconnect(m_VideoBackground, SIGNAL(destroyed(QObject*)) , this, SLOT(QObjectDestroyed(QObject*))); this->Reset(); m_VideoBackground = _VideoBackground; if (m_VideoBackground == nullptr) { m_VideoSource = nullptr; MITK_WARN << "m_MultiWidget is 0"; this->setEnabled(false); } else { this->setEnabled(true); m_VideoSource = dynamic_cast(m_VideoBackground->GetVideoSource()); // preset form entries if (m_VideoSource != nullptr) { if (!m_VideoSource->GetVideoFileName().empty()) { m_Controls->FileChooser->SetFile(m_VideoSource->GetVideoFileName()); on_UseGrabbingDeviceButton_clicked(false); } else if (m_VideoSource->GetGrabbingDeviceNumber() >= 0) m_Controls->GrabbingDeviceNumber->setValue(m_VideoSource->GetGrabbingDeviceNumber()); m_Controls->UpdateRate->setValue(m_VideoBackground->GetTimerDelay()); this->connect(m_VideoBackground, SIGNAL(destroyed(QObject*)) , this, SLOT(QObjectDestroyed(QObject*))); } else { MITK_WARN << "m_VideoSource is 0"; this->setEnabled(false); } } } QmitkVideoBackground* QmitkOpenCVVideoControls::GetVideoBackground() const { return m_VideoBackground; } void QmitkOpenCVVideoControls::QObjectDestroyed(QObject * obj /*= 0 */) { if (m_VideoBackground == obj) { m_VideoSource = nullptr; this->SetVideoBackground(nullptr); } } void QmitkOpenCVVideoControlsPrivate::ToPropertyList() { mitk::IPersistenceService* persistenceService = this->GetPersistenceService(); if (persistenceService != nullptr) { mitk::PropertyList::Pointer propList = persistenceService->GetPropertyList(m_Id); propList->Set("deviceType", q->m_Controls->UseGrabbingDeviceButton->isChecked() ? 0 : 1); propList->Set("grabbingDeviceNumber", q->m_Controls->GrabbingDeviceNumber->value()); propList->Set("updateRate", q->m_Controls->UpdateRate->value()); propList->Set("repeatVideo", q->m_Controls->RepeatVideoButton->isChecked()); } else { MITK_WARN << "Persistence Service not available."; } } void QmitkOpenCVVideoControlsPrivate::FromPropertyList() { mitk::IPersistenceService* persistenceService = this->GetPersistenceService(); if (persistenceService != nullptr) { mitk::PropertyList::Pointer propList = persistenceService->GetPropertyList(m_Id); bool repeatVideo = false; propList->Get("repeatVideo", repeatVideo); q->m_Controls->RepeatVideoButton->setChecked(repeatVideo); int updateRate = 25; propList->Get("updateRate", updateRate); q->m_Controls->UpdateRate->setValue(updateRate); int grabbingDeviceNumber = 0; propList->Get("grabbingDeviceNumber", grabbingDeviceNumber); q->m_Controls->GrabbingDeviceNumber->setValue(grabbingDeviceNumber); int deviceType = 0; propList->Get("deviceType", deviceType); if (deviceType == 0) { q->m_Controls->UseGrabbingDeviceButton->setChecked(true); } else { q->m_Controls->UseVideoFileButton->setChecked(true); } } else { MITK_WARN << "Persistence Service not available."; } } void QmitkOpenCVVideoControls::AfterPropertyListReplaced(const std::string& id, mitk::PropertyList* /*propertyList*/) { if (id == d->m_Id) d->FromPropertyList(); } diff --git a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h index ed5ea696f2..d70660f536 100644 --- a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h +++ b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h @@ -1,116 +1,117 @@ /*============================================================================ 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 QmitkOpenCVVideoControls_h #define QmitkOpenCVVideoControls_h #include #include #include -#include "opencv2/core.hpp" +#include +#include class QmitkRenderWindow; class QmitkVideoBackground; namespace mitk { class VideoSource; class OpenCVVideoSource; } class QmitkOpenCVVideoControlsPrivate; /// /// \brief Offers widgets to play/pause/stop a video on a certain render window with /// the use of an !initialized! QmitkVideoBackground. The QmitkVideoBackground should /// contain an OpenCVVideoSource is then owned by this widget (and deleted) /// class MITKOPENCVVIDEOSUPPORTUI_EXPORT QmitkOpenCVVideoControls : public QWidget, public mitk::PropertyListReplacedObserver { Q_OBJECT public: /// /// Construct the widget with the given render window and the given preset values /// QmitkOpenCVVideoControls(QmitkVideoBackground* _VideoBackground, QmitkRenderWindow* _RenderWindow , QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); /// /// call reset if video playback is enabled here /// ~QmitkOpenCVVideoControls() override; /// /// sets the render window for this video player /// void SetRenderWindow(QmitkRenderWindow* _RenderWindow); /// /// returns the current render window /// QmitkRenderWindow* GetRenderWindow() const; /// /// sets the qmitkvideobackground for this /// void SetVideoBackground(QmitkVideoBackground* _VideoBackground); /// /// returns the current QmitkVideoBackground /// QmitkVideoBackground* GetVideoBackground() const; /// /// calls FromPropertyList /// void AfterPropertyListReplaced(const std::string& id, mitk::PropertyList* propertyList) override; signals: /// /// When playback is started this informs when a new frame was grabbed /// void NewOpenCVFrameAvailable(const IplImage*); protected slots: void on_UseGrabbingDeviceButton_clicked(bool checked = false); void on_UseVideoFileButton_clicked(bool checked = false); void on_VideoProgressSlider_sliderPressed(); void on_VideoProgressSlider_sliderReleased(); void on_VideoProgressSlider_valueChanged(int value); void on_RepeatVideoButton_clicked(bool checked = false); void on_PlayButton_clicked(bool checked = false); void on_StopButton_clicked(bool checked = false); void Play(); void Stop(); void Reset(); void IsPlaying(bool paused); void QObjectDestroyed(QObject * obj = nullptr); void NewFrameAvailable(mitk::VideoSource* videoSource); void EndOfVideoSourceReached(mitk::VideoSource* videoSource); protected: QmitkVideoBackground* m_VideoBackground; QmitkRenderWindow* m_RenderWindow; mitk::OpenCVVideoSource* m_VideoSource; Ui::QmitkOpenCVVideoControls* m_Controls; bool m_SliderCurrentlyMoved; private: friend class QmitkOpenCVVideoControlsPrivate; QScopedPointer d; }; #endif diff --git a/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.cpp b/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.cpp index 44a9a8dfa2..a150980125 100644 --- a/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.cpp +++ b/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.cpp @@ -1,129 +1,130 @@ /*============================================================================ 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 "mitkMovieGeneratorOpenCV.h" //#include #include "mitkGL.h" #include +#include mitk::MovieGeneratorOpenCV::MovieGeneratorOpenCV() { m_initialized = false; m_aviWriter = nullptr; m_dwRate = 20; m_FourCCCodec = nullptr; m_RemoveColouredFrame = true; } void mitk::MovieGeneratorOpenCV::SetFileName( const char *fileName ) { m_sFile = fileName; } void mitk::MovieGeneratorOpenCV::SetFrameRate(unsigned int rate) { m_dwRate = static_cast(rate); } void mitk::MovieGeneratorOpenCV::SetRemoveColouredFrame(bool RemoveColouredFrame) { m_RemoveColouredFrame = RemoveColouredFrame; } bool mitk::MovieGeneratorOpenCV::InitGenerator() { m_width = m_renderer->GetRenderWindow()->GetSize()[0]; // changed from glGetIntegerv( GL_VIEWPORT, viewport ); m_height = m_renderer->GetRenderWindow()->GetSize()[1]; // due to sometimes strange dimensions if(m_RemoveColouredFrame) { m_width -= 10; //remove colored boarders around renderwindows m_height -= 10; } m_width -= m_width % 4; // some video codecs have prerequisites to the image dimensions m_height -= m_height % 4; m_currentFrame = cvCreateImage(cvSize(m_width,m_height),8,3); // creating image with widget size, 8 bit per pixel and 3 channel r,g,b m_currentFrame->origin = 1; // avoid building a video with bottom up /* m_sFile = Name of the output video file. CV_FOURCC = 4-character code of codec used to compress the frames. For example, CV_FOURCC('P','I','M','1') is MPEG-1 codec, CV_FOURCC('M','J','P','G') is motion-jpeg codec etc. CV_FOURCC('P','I','M','1') = MPEG-1 codec CV_FOURCC('M','J','P','G') = motion-jpeg codec (does not work well) CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec CV_FOURCC('U', '2', '6', '3') = H263 codec CV_FOURCC('I', '2', '6', '3') = H263I codec CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec Under Win32 it is possible to pass -1 in order to choose compression method and additional compression parameters from dialog. m_dwRate = Framerate of the created video stream. frame_size Size of video frames. InitGenerator 1 = If it is not zero, the encoder will expect and encode color frames, otherwise it will work with grayscale frames (the flag is currently supported on Windows only).*/ if(m_FourCCCodec != nullptr) { #ifdef WIN32 m_aviWriter = cvCreateVideoWriter(m_sFile.c_str(),CV_FOURCC(m_FourCCCodec[0],m_FourCCCodec[1],m_FourCCCodec[2], m_FourCCCodec[3]),m_dwRate,cvSize(m_width,m_height),1); //initializing video writer #else m_aviWriter = cvCreateVideoWriter(m_sFile.c_str(),CV_FOURCC(m_FourCCCodec[0],m_FourCCCodec[1],m_FourCCCodec[2], m_FourCCCodec[3]),m_dwRate,cvSize(m_width,m_height)); //initializing video writer #endif } else { #ifdef WIN32 m_aviWriter = cvCreateVideoWriter(m_sFile.c_str(),-1,m_dwRate,cvSize(m_width,m_height),1); //initializing video writer #else m_aviWriter = cvCreateVideoWriter(m_sFile.c_str(),CV_FOURCC('X','V','I','D'),m_dwRate,cvSize(m_width,m_height)); //initializing video writer #endif } if(!m_aviWriter) { std::cout << "errors initializing video writer...correct video file path? on linux: ffmpeg must be included in OpenCV."; return false; } return true; } bool mitk::MovieGeneratorOpenCV::AddFrame( void *data ) { //cvSetImageData(m_currentFrame,data,m_width*3); memcpy(m_currentFrame->imageData,data,m_width*m_height*3); cvWriteFrame(m_aviWriter,m_currentFrame); return true; } bool mitk::MovieGeneratorOpenCV::TerminateGenerator() { if (m_aviWriter) { cvReleaseVideoWriter(&m_aviWriter); } return true; } diff --git a/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.h b/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.h index f677abe127..9ff24df620 100755 --- a/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.h +++ b/Modules/OpenCVVideoSupport/mitkMovieGeneratorOpenCV.h @@ -1,85 +1,85 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MovieGeneratorOpenCV_H_HEADER_INCLUDED #define MovieGeneratorOpenCV_H_HEADER_INCLUDED #include "mitkMovieGenerator.h" #include #include #include // OpenCV includes -#include "cv.h" -#include "highgui.h" +#include +#include namespace mitk { class MITKOPENCVVIDEOSUPPORT_EXPORT MovieGeneratorOpenCV : public MovieGenerator { public: mitkClassMacro(MovieGeneratorOpenCV, MovieGenerator); itkFactorylessNewMacro(Self); itkCloneMacro(Self); void SetFileName( const char *fileName ) override; void SetFourCCCodec(char* codec) { m_FourCCCodec = codec; } void SetFrameRate(unsigned int rate) override; /// /// if true the movie will be cutted by a 10 pixel margin /// in order to remove the standard mitk coloured borders /// default: true /// void SetRemoveColouredFrame(bool); protected: MovieGeneratorOpenCV(); //! called directly before the first frame is added bool InitGenerator() override; //! used to add a frame bool AddFrame( void *data ) override; //! called after the last frame is added bool TerminateGenerator() override; //! name of output file std::string m_sFile; //! frame rate int m_dwRate; private: CvVideoWriter* m_aviWriter; IplImage * m_currentFrame; char * m_FourCCCodec; bool m_RemoveColouredFrame; }; } // namespace mitk #endif /* MovieGeneratorOpenCV_H_HEADER_INCLUDED */ diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVToMitkImageFilter.h b/Modules/OpenCVVideoSupport/mitkOpenCVToMitkImageFilter.h index c92612cadd..e0ecd28678 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVToMitkImageFilter.h +++ b/Modules/OpenCVVideoSupport/mitkOpenCVToMitkImageFilter.h @@ -1,96 +1,97 @@ /*============================================================================ 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 mitkOpenCVToMitkImageFilter_h #define mitkOpenCVToMitkImageFilter_h // mitk includes #include #include #include // itk includes #include #include // OpenCV includes #include +#include #include namespace mitk { /// /// \brief Filter for creating MITK RGB Images from an OpenCV image /// class MITKOPENCVVIDEOSUPPORT_EXPORT OpenCVToMitkImageFilter : public ImageSource { public: typedef itk::RGBPixel< unsigned char > UCRGBPixelType; typedef itk::RGBPixel< unsigned short > USRGBPixelType; typedef itk::RGBPixel< float > FloatRGBPixelType; typedef itk::RGBPixel< double > DoubleRGBPixelType; /// /// the static function for the conversion /// template static Image::Pointer ConvertCVMatToMitkImage(const cv::Mat input); mitkClassMacro(OpenCVToMitkImageFilter, ImageSource); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /// /// sets an iplimage as input /// void SetOpenCVImage(const IplImage* image); //itkGetMacro(OpenCVImage, const IplImage*); /// /// sets an opencv mat as input (will be used if OpenCVImage Ipl image is 0) /// void SetOpenCVMat(const cv::Mat& image); itkGetMacro(OpenCVMat, cv::Mat); OutputImageType* GetOutput(void); //##Documentation //## @brief Convenient method to insert an openCV image as a slice at a //## certain time step into a 3D or 4D mitk::Image. //## //## @param openCVImage - the image that is inserted into the mitk Image //## @param mitkImage - pointer to the mitkImage, which is changed by this method! //## @param timeStep - the time step, at which the openCVImage is inserted //## //## @attention The parameter mitkImage will be changed! void InsertOpenCVImageAsMitkTimeSlice(const cv::Mat openCVImage, Image::Pointer mitkImage, int timeStep); protected: OpenCVToMitkImageFilter(); // purposely hidden ~OpenCVToMitkImageFilter() override; void GenerateData() override; protected: Image::Pointer m_Image; cv::Mat m_OpenCVMat; std::mutex m_ImageMutex; std::mutex m_OpenCVMatMutex; }; } // namespace mitk #endif // mitkOpenCVToMitkImageFilter_h diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp index 1fb0d2a342..b63d9da6cf 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp +++ b/Modules/OpenCVVideoSupport/mitkOpenCVVideoSource.cpp @@ -1,424 +1,426 @@ /*============================================================================ 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 "mitkOpenCVVideoSource.h" #include #include +#include + mitk::OpenCVVideoSource::OpenCVVideoSource() : m_VideoCapture(nullptr), m_CurrentImage(nullptr), m_CurrentVideoTexture(nullptr), m_PauseImage(nullptr), m_GrabbingDeviceNumber(-1), m_RepeatVideo(false), m_UseCVCAMLib(false), m_UndistortImage(false), m_FlipXAxisEnabled(false), m_FlipYAxisEnabled(false) { } mitk::OpenCVVideoSource::~OpenCVVideoSource() { this->Reset(); } void mitk::OpenCVVideoSource::SetVideoFileInput(const char * filename, bool repeatVideo, bool /*useCVCAMLib*/) { this->Reset(); m_VideoFileName = filename; m_VideoCapture = cvCaptureFromFile(filename); if(!m_VideoCapture) MITK_WARN << "Error in initializing video file input!"; m_RepeatVideo = repeatVideo; //m_CurrentImage = cvCreateImage(cvSize(m_CaptureWidth,m_CaptureHeight),8,3); this->Modified(); } void mitk::OpenCVVideoSource::SetVideoCameraInput(int cameraindex, bool /*useCVCAMLib*/) { this->Reset(); m_GrabbingDeviceNumber = cameraindex; m_VideoCapture = cvCaptureFromCAM(m_GrabbingDeviceNumber); if(!m_VideoCapture) MITK_ERROR << "Error in initializing CVHighGUI video camera!"<< std::endl; this->Modified(); } double mitk::OpenCVVideoSource::GetVideoCaptureProperty(int property_id) { return cvGetCaptureProperty(m_VideoCapture, property_id); } int mitk::OpenCVVideoSource::SetVideoCaptureProperty(int property_id, double value) { return cvSetCaptureProperty(m_VideoCapture, property_id, value); } //method extended for "static video feature" if enabled unsigned char* mitk::OpenCVVideoSource::GetVideoTexture() { // Fetch Frame and return pointer to opengl texture FetchFrame(); if (m_FlipXAxisEnabled || m_FlipYAxisEnabled) { //rotate the image to get a static video m_CurrentImage = this->FlipImage(m_CurrentImage); } //transfer the image to a texture this->UpdateVideoTexture(); return this->m_CurrentVideoTexture; this->Modified(); } cv::Mat mitk::OpenCVVideoSource::GetImage() { if(m_CurrentImage) { cv::Mat copy = cv::cvarrToMat( m_CurrentImage, false ); return copy.clone(); } return cv::Mat(); } const IplImage * mitk::OpenCVVideoSource::GetCurrentFrame() { return m_CurrentImage; } void mitk::OpenCVVideoSource::GetCurrentFrameAsOpenCVImage(IplImage * image) { // get last captured frame for processing the image data if(m_CurrentImage) { if(image) { image->origin = m_CurrentImage->origin; memcpy(image->imageData,m_CurrentImage->imageData,m_CurrentImage->width*m_CurrentImage->height*m_CurrentImage->nChannels); } } } void mitk::OpenCVVideoSource::FetchFrame() { // main procedure for updating video data if(m_CapturingInProcess) { if(m_VideoCapture) // we use highgui { if(!m_CapturePaused) { // release old image here m_CurrentImage = cvQueryFrame(m_VideoCapture); ++m_FrameCount; } if(m_CurrentImage == nullptr) // do we need to repeat the video if it is from video file? { double framePos = this->GetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO); MITK_DEBUG << "End of video file found. framePos: " << framePos; if(m_RepeatVideo && framePos >= 0.99) { MITK_DEBUG << "Restarting video file playback."; this->SetVideoCaptureProperty(CV_CAP_PROP_POS_AVI_RATIO, 0); m_FrameCount = 0; m_CurrentImage = cvQueryFrame(m_VideoCapture); } else { std::ostringstream s; s << "End of video file " << m_VideoFileName; std::logic_error err( s.str() ); throw err; } } else { // only undistort if not paused if(m_UndistortImage && m_UndistortCameraImage.IsNotNull()) m_UndistortCameraImage->UndistortImageFast(m_CurrentImage, nullptr); } if(m_CaptureWidth == 0 || m_CaptureHeight == 0) { MITK_DEBUG << "Trying to set m_CaptureWidth & m_CaptureHeight."; m_CaptureWidth = m_CurrentImage->width; m_CaptureHeight = m_CurrentImage->height; MITK_INFO << "frame width: " << m_CaptureWidth << ", height: " << m_CaptureHeight; m_CurrentImage->origin = 0; } } } } void mitk::OpenCVVideoSource::UpdateVideoTexture() { //write the grabbed frame into an opengl compatible array, that means flip it and swap channel order if(!m_CurrentImage) return; if(m_CurrentVideoTexture == nullptr) m_CurrentVideoTexture = new unsigned char[m_CaptureWidth*m_CaptureHeight*3]; int width = m_CurrentImage->width; int height = m_CurrentImage->height; int widthStep = m_CurrentImage->widthStep; int nChannels = m_CurrentImage->nChannels; unsigned char* tex = m_CurrentVideoTexture; char* data = m_CurrentImage->imageData; char* currentData = m_CurrentImage->imageData; int hIndex=0; int wIndex=0; int iout,jout; for(int i=0;i= width) { wIndex=0; hIndex++; } // vertically flip the image iout = -hIndex+height-1; jout = wIndex; currentData = data + iout*widthStep; tex[i+2] = currentData[jout*nChannels + 0]; // B tex[i+1] = currentData[jout*nChannels + 1]; // G tex[i] = currentData[jout*nChannels + 2]; // R } } void mitk::OpenCVVideoSource::StartCapturing() { if(m_VideoCapture != nullptr) m_CapturingInProcess = true; else m_CapturingInProcess = false; } void mitk::OpenCVVideoSource::StopCapturing() { m_CapturePaused = false; m_CapturingInProcess = false; } bool mitk::OpenCVVideoSource::OnlineImageUndistortionEnabled() const { return m_UndistortCameraImage; } void mitk::OpenCVVideoSource::PauseCapturing() { m_CapturePaused = !m_CapturePaused; if(m_CapturePaused) { m_PauseImage = cvCloneImage(m_CurrentImage); // undistort this pause image if necessary if(m_UndistortImage) m_UndistortCameraImage->UndistortImageFast(m_PauseImage, nullptr); m_CurrentImage = m_PauseImage; } else { cvReleaseImage( &m_PauseImage ); // release old pause image if necessary m_CurrentImage = nullptr; m_PauseImage = nullptr; } } void mitk::OpenCVVideoSource::EnableOnlineImageUndistortion(mitk::Point3D focal, mitk::Point3D principal, mitk::Point4D distortion) { // Initialize Undistortion m_UndistortImage = true; float kc[4]; kc[0] = distortion[0]; kc[1] = distortion[1]; kc[2] = distortion[2]; kc[3] = distortion[3]; if(m_CaptureWidth == 0 || m_CaptureHeight == 0) FetchFrame(); m_UndistortCameraImage = mitk::UndistortCameraImage::New(); m_UndistortCameraImage->SetUndistortImageFastInfo(focal[0], focal[1], principal[0], principal[1], kc, (float)m_CaptureWidth, (float)m_CaptureHeight); } void mitk::OpenCVVideoSource::DisableOnlineImageUndistortion() { m_UndistortImage = false; } // functions for compatibility with ITK segmentation only void mitk::OpenCVVideoSource::GetCurrentFrameAsItkHSVPixelImage(HSVPixelImageType::Pointer &Image) { FetchFrame(); // Prepare iteration HSVConstIteratorType itImage( Image, Image->GetLargestPossibleRegion()); itImage.GoToBegin(); HSVPixelType pixel; int rowsize = 3 * m_CaptureWidth; char* bufferend; char* picture; picture = this->m_CurrentImage->imageData; bufferend = this->m_CurrentImage->imageData + 3*(m_CaptureHeight*m_CaptureWidth); float r,g,b,h,s,v; try { // we have to flip the image for(char* datapointer = bufferend - rowsize;datapointer >= picture; datapointer -= rowsize) { for(char* current = datapointer; current < datapointer + rowsize; current++) { b = *current; current++; g = *current; current++; r = *current; RGBtoHSV(r,g,b,h,s,v); pixel[0] = h; pixel[1] = s; pixel[2] = v; itImage.Set(pixel); ++itImage; } } } catch( ... ) { std::cout << "Exception raised mitkOpenCVVideoSource: get hsv itk image conversion error." << std::endl; } } void mitk::OpenCVVideoSource::RGBtoHSV(float r, float g, float b, float &h, float &s, float &v) { if(r > 1.0) r = r/255; if(b > 1.0) b = b/255; if(g > 1.0) g = g/255; float mn=r,mx=r; int maxVal=0; if (g > mx){ mx=g;maxVal=1;} if (b > mx){ mx=b;maxVal=2;} if (g < mn) mn=g; if (b < mn) mn=b; float delta = mx - mn; v = mx; if( mx != 0 ) s = delta / mx; else { s = 0; h = 0; return; } if (s==0.0f) { h=-1; return; } else { switch (maxVal) { case 0:{h = ( g - b ) / delta;break;} // yel < h < mag case 1:{h = 2 + ( b - r ) / delta;break;} // cyan < h < yel case 2:{h = 4 + ( r - g ) / delta;break;} // mag < h < cyan } } h *= 60; if( h < 0 ) h += 360; } /* * Rotate input image according to rotation angle around the viewing direction. * Angle is supposed to be calculated in QmitkARRotationComponet in the update() method. */ IplImage* mitk::OpenCVVideoSource::FlipImage(IplImage* input) { if(input == nullptr) { //warn the user and quit std::cout<<"openCVVideoSource: Current video image is null! "<< std::endl; return input; } if(m_FlipXAxisEnabled && !m_FlipYAxisEnabled) { cvFlip(input,nullptr,0); } if(!m_FlipXAxisEnabled && m_FlipYAxisEnabled) { cvFlip(input,nullptr,1); } if(m_FlipXAxisEnabled && m_FlipYAxisEnabled) { cvFlip(input,nullptr,-1); } return input; } void mitk::OpenCVVideoSource::Reset() { // set capturing to false this->StopCapturing(); this->m_FrameCount = 0; if(m_VideoCapture) cvReleaseCapture(&m_VideoCapture); m_VideoCapture = nullptr; m_CurrentImage = nullptr; m_CaptureWidth = 0; m_CaptureHeight = 0; delete m_CurrentVideoTexture; m_CurrentVideoTexture = nullptr; if(m_PauseImage) cvReleaseImage(&m_PauseImage); m_PauseImage = nullptr; m_CapturePaused = false; m_VideoFileName.clear(); m_GrabbingDeviceNumber = -1; // do not touch repeat video //m_RepeatVideo = false; m_UseCVCAMLib = false; // do not touch undistort settings // bool m_UndistortImage; } void mitk::OpenCVVideoSource::SetEnableXAxisFlip(bool enable) { this->m_FlipXAxisEnabled = enable; this->Modified(); } void mitk::OpenCVVideoSource::SetEnableYAxisFlip(bool enable) { this->m_FlipXAxisEnabled = enable; this->Modified(); } diff --git a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.cpp b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.cpp index 1d78e43af2..40844de3fc 100644 --- a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.cpp +++ b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.cpp @@ -1,223 +1,231 @@ /*============================================================================ 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. ============================================================================*/ /// The list of internal camera parameters: /// * Focal length: The focal length in pixels is stored in m_fcX and m_fcY. /// * Principal point: The principal point coordinates are stored in the m_ccX and m_ccY. /// * Skew coefficient: The skew coefficient defining the angle between the x and y pixel axes is stored in the scalar alpha_c = 0. /// * Distortions: The image distortion coefficients (radial and tangential distortions) are stored in the 4x1 vector. #include "mitkUndistortCameraImage.h" - +#include +#include mitk::UndistortCameraImage::UndistortCameraImage() { m_tempImage = nullptr; } mitk::UndistortCameraImage::~UndistortCameraImage() { if(m_tempImage != nullptr) cvReleaseImage(&m_tempImage); } /// undistort one pixel coordinate using floating point accuracy... mitk::Point2D mitk::UndistortCameraImage::UndistortPixel(const mitk::Point2D& src) { float r_2 = 0; // radial distance squared const mitk::Point2D old_src = src; // copy of the original distorted point // distortion coefficients float k1 = m_distortionMatrixData[0]; float k2 = m_distortionMatrixData[1]; float p1 = m_distortionMatrixData[2]; float p2 = m_distortionMatrixData[3]; // Shift points to principal point and use focal length mitk::Point2D dstd; dstd[0] = (src[0] - m_ccX) / m_fcX; dstd[1] = (src[1] - m_ccY) / m_fcY; mitk::Point2D desPnt = dstd; // Compensate lens distortion float x = dstd[0]; float y = dstd[1]; for (int iter = 0; iter < 5; iter++) { r_2 = x*x + y*y; const float k_radial = 1 + k1 * r_2 + k2 * r_2 * r_2; const float delta_x = 2 * p1*x*y + p2 * (r_2 + 2*x*x); const float delta_y = 2 * p2*x*y + p1 * (r_2 + 2*y*y); x = (desPnt[0] - delta_x) / k_radial; y = (desPnt[1] - delta_y) / k_radial; } dstd[0] = x; dstd[1] = y; dstd[0] *= m_fcX; dstd[1] *= m_fcY; dstd[0] += m_ccX; dstd[1] += m_ccY; // ready // const mitk::Point2D dst = dstd; // do a sanity check to make sure this ideal point translates properly to the distorted point // this does the reverse of the above. It maps ideal undistorted to distorted image coordinates x = dstd[0] - m_ccX; y = dstd[1] - m_ccY; x /= m_fcX; y /= m_fcY; r_2 = x*x + y*y; float distx = x + x*(k1*r_2 + k2*r_2*r_2) + (2*p1*x*y + p2*(r_2 + 2*x*x)); float disty = y + y*(k1*r_2 + k2*r_2*r_2) + (2*p2*x*y + p1*(r_2 + 2*y*y)); distx *= m_fcX; disty *= m_fcY; distx += m_ccX; disty += m_ccY; // this should never be more than .2 pixels... const float diffx = old_src[0] - distx; const float diffy = old_src[1] - disty; if (fabs(diffx) > .1 || fabs(diffy) > .1) { std::cout << "undistort sanity check error: diffx =" << diffx << " , diffy = " << diffy; } return dstd; } void mitk::UndistortCameraImage::UndistortImage(IplImage *src, IplImage *dst) { // init intrinsic camera matrix [fx 0 cx; 0 fy cy; 0 0 1]. m_intrinsicMatrixData[0] = (double)m_fcX; m_intrinsicMatrixData[1] = 0.0; m_intrinsicMatrixData[2] = (double)m_ccX; m_intrinsicMatrixData[3] = 0.0; m_intrinsicMatrixData[4] = (double)m_fcY; m_intrinsicMatrixData[5] = (double)m_ccY; m_intrinsicMatrixData[6] = 0.0; m_intrinsicMatrixData[7] = 0.0; m_intrinsicMatrixData[8] = 1.0; m_intrinsicMatrix = cvMat(3, 3, CV_32FC1, m_intrinsicMatrixData); // init distortion matrix m_distortionMatrix = cvMat(1, 4, CV_32F, m_distortionMatrixData); // undistort - cvUndistort2(src,dst, &m_intrinsicMatrix, &m_distortionMatrix); + auto srcMat = cv::cvarrToMat(src); + auto dstMat = cv::cvarrToMat(dst); + auto intrinsicMat = cv::cvarrToMat(&m_intrinsicMatrix); + auto distortionMat = cv::cvarrToMat(&m_distortionMatrix); + cv::undistort(srcMat, dstMat, intrinsicMat, distortionMat); } // FAST METHODS FOR UNDISTORTION IN REALTIME // void mitk::UndistortCameraImage::UndistortImageFast(IplImage * src, IplImage* dst) { if(!src) return; /*if(dst == nullptr) dst = src; if(src->nChannels == 3) { IplImage *r = cvCreateImage(cvGetSize(src),src->depth,1);//subpixel IplImage *g = cvCreateImage(cvGetSize(src),src->depth,1);//subpixel IplImage *b = cvCreateImage(cvGetSize(src),src->depth,1);//subpixel cvSplit(src, r,g,b, nullptr); cvRemap( r, r, m_mapX, m_mapY ); // Undistort image cvRemap( g, g, m_mapX, m_mapY ); // Undistort image cvRemap( b, b, m_mapX, m_mapY ); // Undistort image cvMerge(r,g,b, nullptr, dst); } else { cvRemap(src, dst, m_mapX, m_mapY); }*/ /*if(m_tempImage == nullptr) m_tempImage = cvCreateImage(cvSize(src->width,src->height),src->depth,src->nChannels);*/ /*if(dst == nullptr) dst = cvCreateImage(cvSize(src->width,src->height),src->depth,src->nChannels);*/ if(!dst) { m_tempImage = cvCloneImage( src ); cvRemap(m_tempImage, src, m_mapX, m_mapY, CV_INTER_CUBIC); cvReleaseImage( &m_tempImage ); m_tempImage = nullptr; /*memcpy( src->imageData, m_tempImage->imageData, m_tempImage->imageSize ); cvReleaseImage( &m_tempImage );*/ } else { cvRemap(src, dst, m_mapX, m_mapY, CV_INTER_CUBIC); } /*m_tempImage->origin = src->origin; if(dst == nullptr) memcpy( src->imageData, m_tempImage->imageData, m_tempImage->imageSize ); else memcpy( dst->imageData, m_tempImage->imageData, m_tempImage->imageSize ); //cvUnDistort(m_srcImg, m_dstImg, m_undistMap,m_interpolationMode); //cvUndistort2(m_srcImg, m_dstImg, &m_intrinsicMatrix,&m_distortionMatrixDataCoefficients);*/ } void mitk::UndistortCameraImage::SetUndistortImageFastInfo(float in_dF1, float in_dF2, float in_dPrincipalX, float in_dPrincipalY, float in_Dist[4], float ImageSizeX, float ImageSizeY) { //create new matrix m_DistortionCoeffs = cvCreateMat(4, 1, CV_64FC1); m_CameraMatrix = cvCreateMat(3, 3, CV_64FC1); //set the camera matrix [fx 0 cx; 0 fy cy; 0 0 1]. cvSetReal2D(m_CameraMatrix, 0, 0, in_dF1); cvSetReal2D(m_CameraMatrix, 0, 1, 0.0); cvSetReal2D(m_CameraMatrix, 0, 2, in_dPrincipalX); cvSetReal2D(m_CameraMatrix, 1, 0, 0.0); cvSetReal2D(m_CameraMatrix, 1, 1, in_dF2); cvSetReal2D(m_CameraMatrix, 1, 2, in_dPrincipalY); cvSetReal2D(m_CameraMatrix, 2, 0, 0.0); cvSetReal2D(m_CameraMatrix, 2, 1, 0.0); cvSetReal2D(m_CameraMatrix, 2, 2, 1.0); //set distortions coefficients cvSetReal1D(m_DistortionCoeffs, 0, in_Dist[0]); cvSetReal1D(m_DistortionCoeffs, 1, in_Dist[1]); cvSetReal1D(m_DistortionCoeffs, 2, in_Dist[2]); cvSetReal1D(m_DistortionCoeffs, 3, in_Dist[3]); m_mapX = cvCreateMat(ImageSizeY, ImageSizeX, CV_32FC1); m_mapY = cvCreateMat(ImageSizeY, ImageSizeX, CV_32FC1); - //cv::initUndistortRectifyMap(m_CameraMatrix, m_DistortionCoeffs, m_mapX, m_mapY); - cvInitUndistortMap(m_CameraMatrix, m_DistortionCoeffs, m_mapX, m_mapY); + auto cameraMat = cv::cvarrToMat(m_CameraMatrix); + auto distortionCoeffs = cv::cvarrToMat(m_DistortionCoeffs); + auto mapX = cv::cvarrToMat(m_mapX); + auto mapY = cv::cvarrToMat(m_mapY); + cv::initUndistortRectifyMap(cameraMat, distortionCoeffs, cv::Mat(), cameraMat, mapX.size(), mapX.type(), mapX, mapY); } diff --git a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h index 1f9509b827..cd678889e3 100644 --- a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h +++ b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h @@ -1,125 +1,125 @@ /*============================================================================ 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 __mitkUndistortCameraImage_h #define __mitkUndistortCameraImage_h #include "mitkCommon.h" #include #include "itkObject.h" #include "mitkPoint.h" -#include "opencv2/core.hpp" -#include "opencv2/imgproc.hpp" +#include +#include /*! \brief UndistortCameraImage This class is used to undistort camera images. Before any undistortion the class has to be initialized using the functions: SetFocalLength(),SetPrinzipalPoint() and SetCameraDistortion(). After this you can either use UndistortPixel() to undistort a single pixel's coordinates or UndistortImage() to undistort an OpenCV image. A faster version of UndistortImage() is UndistortImageFast(), however, it has to be initialized once with SetUndistortImageFastInfo() instead of the Set... methods before use. \ingroup Functionalities */ namespace mitk { class MITKOPENCVVIDEOSUPPORT_EXPORT UndistortCameraImage : public itk::Object { public: mitkClassMacroItkParent(UndistortCameraImage,itk::Object); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /// Initialization /// /* * Set the camera's intrinsic focal length */ void SetFocalLength(float fc_x, float fc_y) { m_fcX = fc_x; m_fcY = fc_y; } /* * Set the camera's intrinsic principal point */ void SetPrincipalPoint(float cc_x, float cc_y) { m_ccX = cc_x; m_ccY = cc_y; } /* * Set the camera's intrinsic distortion parameters */ void SetCameraDistortion(float kc1, float kc2, float kc3, float kc4) { m_distortionMatrixData[0] = kc1; m_distortionMatrixData[1] = kc2; m_distortionMatrixData[2] = kc3; m_distortionMatrixData[3] = kc4; } /* * Pre-Calculates matrices for the later use of UndistortImageFast() */ void InitRemapUndistortion(int sizeX, int sizeY); /// USAGE /// /* * Undistort a single pixel, returns undistorted pixel */ mitk::Point2D UndistortPixel(const mitk::Point2D& src); /* * Complete undistortion of an OpenCV image, including all calculations */ void UndistortImage(IplImage* src, IplImage* dst); /* * Complete undistortion of an OpenCV image, using pre-calculated matrices from SetUndistortImageFastInfo() * The use of only a source parameter will cause the source to be overwritten. * NOTE: Using the Fast undistortion methods does not require a initialization via the Set... methods. */ void UndistortImageFast( IplImage * src, IplImage* dst = nullptr ); void SetUndistortImageFastInfo(float in_dF1, float in_dF2, float in_dPrincipalX, float in_dPrincipalY, float in_Dist[4], float ImageSizeX, float ImageSizeY); UndistortCameraImage(); ~UndistortCameraImage() override; protected: // principal point and focal length parameters float m_ccX, m_ccY, m_fcX, m_fcY; // undistortion parameters float m_distortionMatrixData[4]; // intrinsic camera parameters float m_intrinsicMatrixData[9]; // precalculated matrices for fast image undistortion with UndistortImageFast() CvMat * m_mapX, * m_mapY; // intrinsic and undistortion camera matrices CvMat m_intrinsicMatrix, m_distortionMatrix; // temp image IplImage * m_tempImage; CvMat *m_DistortionCoeffs; CvMat *m_CameraMatrix; }; } #endif diff --git a/Modules/OpenIGTLink/mitkIGTLClient.cpp b/Modules/OpenIGTLink/mitkIGTLClient.cpp index 649c6a808d..ea192cbbec 100644 --- a/Modules/OpenIGTLink/mitkIGTLClient.cpp +++ b/Modules/OpenIGTLink/mitkIGTLClient.cpp @@ -1,117 +1,117 @@ /*============================================================================ 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 "mitkIGTLClient.h" //#include "mitkIGTTimeStamp.h" //#include "mitkIGTHardwareException.h" #include "igtlTrackingDataMessage.h" #include #include #include -#include +#include mitk::IGTLClient::IGTLClient(bool ReadFully) : IGTLDevice(ReadFully) { } mitk::IGTLClient::~IGTLClient() { } bool mitk::IGTLClient::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to open the connection if in setup mode. State was " << this->GetState(); return false; } std::string hostname = this->GetHostname(); int portNumber = this->GetPortNumber(); if (portNumber == -1 || hostname.size() <= 0) { //port number or hostname was not correct MITK_WARN << "Port number or hostname was not correct"; return false; } //create a new client socket m_Socket = igtl::ClientSocket::New(); //try to connect to the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> ConnectToServer(hostname.c_str(), portNumber); //check the response if (response != 0) { MITK_ERROR << "The client could not connect to " << hostname << " port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); //inform observers about this new client this->InvokeEvent(NewClientConnectionEvent()); return true; } void mitk::IGTLClient::Receive() { //MITK_INFO << "Trying to receive message"; //try to receive a message, if the socket is not present anymore stop the //communication unsigned int status = this->ReceivePrivate(this->m_Socket); if (status == IGTL_STATUS_NOT_PRESENT) { this->StopCommunicationWithSocket(this->m_Socket); //inform observers about loosing the connection to this socket this->InvokeEvent(LostConnectionEvent()); MITK_WARN("IGTLClient") << "Lost connection to server socket."; } } void mitk::IGTLClient::Send() { mitk::IGTLMessage::Pointer mitkMessage; //get the latest message from the queue mitkMessage = this->m_MessageQueue->PullSendMessage(); // there is no message => return if (mitkMessage.IsNull()) return; if (!this->SendMessagePrivate(mitkMessage, this->m_Socket)) { MITK_WARN("IGTLDevice") << "Could not send the message."; } } void mitk::IGTLClient::StopCommunicationWithSocket(igtl::Socket* /*socket*/) { m_StopCommunicationMutex.lock(); m_StopCommunication = true; m_StopCommunicationMutex.unlock(); } unsigned int mitk::IGTLClient::GetNumberOfConnections() { return this->m_Socket->GetConnected(); } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.cpp b/Modules/OpenIGTLink/mitkIGTLDevice.cpp index 8d531d085d..a9a5640b36 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDevice.cpp @@ -1,496 +1,496 @@ /*============================================================================ 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 "mitkIGTLDevice.h" //#include "mitkIGTException.h" //#include "mitkIGTTimeStamp.h" #include #include #include #include #include #include -#include +#include //remove later #include namespace mitk { itkEventMacroDefinition(MessageSentEvent, itk::AnyEvent); itkEventMacroDefinition(MessageReceivedEvent, itk::AnyEvent); itkEventMacroDefinition(CommandReceivedEvent, itk::AnyEvent); itkEventMacroDefinition(NewClientConnectionEvent, itk::AnyEvent); itkEventMacroDefinition(LostConnectionEvent, itk::AnyEvent); } //TODO: Which timeout is acceptable and also needed to transmit image data? Is there a maximum data limit? static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 100; mitk::IGTLDevice::IGTLDevice(bool ReadFully) : // m_Data(mitk::DeviceDataUnspecified), m_State(mitk::IGTLDevice::Setup), m_Name("Unspecified Device"), m_StopCommunication(false), m_Hostname("127.0.0.1"), m_PortNumber(-1), m_LogMessages(false) { m_ReadFully = ReadFully; // execution rights are owned by the application thread at the beginning m_SendingFinishedMutex.lock(); m_ReceivingFinishedMutex.lock(); m_ConnectingFinishedMutex.lock(); // m_Data = mitk::DeviceDataUnspecified; // m_LatestMessage = igtl::MessageBase::New(); m_MessageFactory = mitk::IGTLMessageFactory::New(); m_MessageQueue = mitk::IGTLMessageQueue::New(); } mitk::IGTLDevice::~IGTLDevice() { /* stop communication and disconnect from igtl device */ if (GetState() == Running) { this->StopCommunication(); this->CloseConnection(); } else if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if (m_SendThread.joinable()) m_SendThread.detach(); if (m_ReceiveThread.joinable()) m_ReceiveThread.detach(); if (m_ConnectThread.joinable()) m_ConnectThread.detach(); } mitk::IGTLDevice::IGTLDeviceState mitk::IGTLDevice::GetState() const { std::lock_guard lock(m_StateMutex); return m_State; } void mitk::IGTLDevice::SetState(IGTLDeviceState state) { itkDebugMacro("setting m_State to " << state); m_StateMutex.lock(); // MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex if (m_State == state) { m_StateMutex.unlock(); return; } m_State = state; m_StateMutex.unlock(); this->Modified(); } bool mitk::IGTLDevice::TestConnection() { return true; } unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket) { // Create a message buffer to receive header igtl::MessageHeader::Pointer headerMsg; headerMsg = igtl::MessageHeader::New(); // Initialize receive buffer headerMsg->InitPack(); // Receive generic header from the socket - int r = - socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 0); + bool timeout = false; + auto r = socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), timeout, 0); //MITK_INFO << "Server received r = " << r; //MITK_INFO << "Received r = " << r; - if (r == 0) //connection error + if (timeout == true) //timeout + { + // a timeout was received, this is no error state, thus, do nothing + return IGTL_STATUS_TIME_OUT; + } + else if (r == 0) //connection error { // an error was received, therefore the communication with this socket // must be stoppedy return IGTL_STATUS_NOT_PRESENT; } - else if (r == -1) //timeout - { - // a timeout was received, this is no error state, thus, do nothing - return IGTL_STATUS_TIME_OUT; - } else if (r == headerMsg->GetPackSize()) { // Deserialize the header and check the CRC // ERROR HERE: This probably means the header data is corrupted... int crcCheck = headerMsg->Unpack(1); if (crcCheck & igtl::MessageHeader::UNPACK_HEADER) { // Allocate a time stamp igtl::TimeStamp::Pointer ts; ts = igtl::TimeStamp::New(); // Get time stamp igtlUint32 sec; igtlUint32 nanosec; headerMsg->GetTimeStamp(ts); ts->GetTimeStamp(&sec, &nanosec); // std::cerr << "Time stamp: " // << sec << "." // << nanosec << std::endl; // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " " // << headerMsg->GetDeviceName() << std::endl; // headerMsg->Print(std::cout); //check the type of the received message //if it is a GET_, STP_ or RTS_ command push it into the command queue //otherwise continue reading the whole message from the socket const char* curDevType = headerMsg->GetDeviceType(); if (std::strstr(curDevType, "GET_") != nullptr || std::strstr(curDevType, "STP_") != nullptr || std::strstr(curDevType, "RTS_") != nullptr) { this->m_MessageQueue->PushCommandMessage(headerMsg); this->InvokeEvent(CommandReceivedEvent()); return IGTL_STATUS_OK; } //Create a message according to the header message igtl::MessageBase::Pointer curMessage; curMessage = m_MessageFactory->CreateInstance(headerMsg); //check if the curMessage is created properly, if not the message type is //not supported and the message has to be skipped if (curMessage.IsNull()) { socket->Skip(headerMsg->GetBodySizeToRead(), 0); // MITK_ERROR("IGTLDevice") << "The received type is not supported. Please " // "add it to the message factory."; return IGTL_STATUS_NOT_FOUND; } //insert the header to the message and allocate the pack curMessage->SetMessageHeader(headerMsg); curMessage->AllocatePack(); // Receive transform data from the socket int receiveCheck = 0; receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(), curMessage->GetPackBodySize(), m_ReadFully); if (receiveCheck > 0) { int c = curMessage->Unpack(1); if (!(c & igtl::MessageHeader::UNPACK_BODY)) { return IGTL_STATUS_CHECKSUM_ERROR; } //check the type of the received message //if it is a command push it into the command queue //otherwise into the normal receive queue //STP_ commands are handled here because they implemented additional //member variables that are not stored in the header message if (std::strstr(curDevType, "STT_") != nullptr) { this->m_MessageQueue->PushCommandMessage(curMessage); this->InvokeEvent(CommandReceivedEvent()); } else { if(m_LogMessages) MITK_INFO << "Received Message: " << mitk::IGTLMessage::New(curMessage)->ToString(); this->m_MessageQueue->PushMessage(curMessage); this->InvokeEvent(MessageReceivedEvent()); } return IGTL_STATUS_OK; } else { MITK_WARN("IGTLDevice") << "Received a valid header but could not " << "read the whole message."; return IGTL_STATUS_UNKNOWN_ERROR; } } else { //CRC check failed MITK_WARN << "CRC Check failed"; return IGTL_STATUS_CHECKSUM_ERROR; } } else { //Message size information and actual data size don't match. //this state is not suppossed to be reached, return unknown error MITK_WARN << "IGTL status unknown"; return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::SendMessage(mitk::IGTLMessage::Pointer msg) { m_MessageQueue->PushSendMessage(msg); } unsigned int mitk::IGTLDevice::SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket) { //check the input message if (msg.IsNull()) { MITK_ERROR("IGTLDevice") << "Could not send message because message is not " "valid. Please check."; return false; } igtl::MessageBase* sendMessage = msg->GetMessage(); // Pack (serialize) and send sendMessage->Pack(); int sendSuccess = socket->Send(sendMessage->GetPackPointer(), sendMessage->GetPackSize()); if (sendSuccess) { if (m_LogMessages) { MITK_INFO << "Send IGTL message: " << msg->ToString(); } this->InvokeEvent(MessageSentEvent()); return IGTL_STATUS_OK; } else { return IGTL_STATUS_UNKNOWN_ERROR; } } void mitk::IGTLDevice::RunCommunication(void (IGTLDevice::*ComFunction)(void), std::mutex& mutex) { if (this->GetState() != Running) return; try { // keep lock until end of scope std::lock_guard communicationFinishedLockHolder(mutex); // Because m_StopCommunication is used by two threads, access has to be guarded // by a mutex. To minimize thread locking, a local copy is used here bool localStopCommunication; // update the local copy of m_StopCommunication this->m_StopCommunicationMutex.lock(); localStopCommunication = this->m_StopCommunication; this->m_StopCommunicationMutex.unlock(); while ((this->GetState() == Running) && (localStopCommunication == false)) { (this->*ComFunction)(); /* Update the local copy of m_StopCommunication */ this->m_StopCommunicationMutex.lock(); localStopCommunication = m_StopCommunication; this->m_StopCommunicationMutex.unlock(); // time to relax, this sets the maximum ever possible framerate to 1000 Hz itksys::SystemTools::Delay(1); } } catch (...) { mutex.unlock(); this->StopCommunication(); MITK_ERROR("IGTLDevice::RunCommunication") << "Error while communicating. Thread stopped."; //mitkThrowException(mitk::IGTException) << "Error while communicating. Thread stopped."; } // StopCommunication was called, thus the mode should be changed back to Ready now // that the tracking loop has ended. //this->SetState(Ready); //this is done elsewhere MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication."; // returning from this function (and ThreadStartCommunication()) // this will end the thread return; } bool mitk::IGTLDevice::StartCommunication() { if (this->GetState() != Ready) return false; // go to mode Running this->SetState(Running); // set a timeout for the sending and receiving this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC); // update the local copy of m_StopCommunication this->m_StopCommunicationMutex.lock(); this->m_StopCommunication = false; this->m_StopCommunicationMutex.unlock(); // transfer the execution rights to tracking thread m_SendingFinishedMutex.unlock(); m_ReceivingFinishedMutex.unlock(); m_ConnectingFinishedMutex.unlock(); // start new threads that execute the communication m_SendThread = std::thread(&IGTLDevice::ThreadStartSending, this); m_ReceiveThread = std::thread(&IGTLDevice::ThreadStartReceiving, this); m_ConnectThread = std::thread(&IGTLDevice::ThreadStartConnecting, this); // mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } bool mitk::IGTLDevice::StopCommunication() { if (this->GetState() == Running) // Only if the object is in the correct state { // m_StopCommunication is used by two threads, so we have to ensure correct // thread handling m_StopCommunicationMutex.lock(); m_StopCommunication = true; m_StopCommunicationMutex.unlock(); // we have to wait here that the other thread recognizes the STOP-command // and executes it m_SendingFinishedMutex.lock(); m_ReceivingFinishedMutex.lock(); m_ConnectingFinishedMutex.lock(); // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock // StopCommunication was called, thus the mode should be changed back // to Ready now that the tracking loop has ended. this->SetState(Ready); } return true; } bool mitk::IGTLDevice::CloseConnection() { if (this->GetState() == Setup) { return true; } else if (this->GetState() == Running) { this->StopCommunication(); } m_Socket->CloseSocket(); /* return to setup mode */ this->SetState(Setup); // this->InvokeEvent(mitk::LostConnectionEvent()); return true; } bool mitk::IGTLDevice::SendRTSMessage(const char* type) { //construct the device type for the return message, it starts with RTS_ and //continues with the requested type std::string returnType("RTS_"); returnType.append(type); //create a return message igtl::MessageBase::Pointer rtsMsg = this->m_MessageFactory->CreateInstance(returnType); //if retMsg is nullptr there is no return message defined and thus it is not //necessary to send one back if (rtsMsg.IsNotNull()) { this->SendMessage(mitk::IGTLMessage::New(rtsMsg)); return true; } else { return false; } } void mitk::IGTLDevice::Connect() { MITK_DEBUG << "mitk::IGTLDevice::Connect();"; } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage2dMessage() { return this->m_MessageQueue->PullImage2dMessage(); } igtl::ImageMessage::Pointer mitk::IGTLDevice::GetNextImage3dMessage() { return this->m_MessageQueue->PullImage3dMessage(); } igtl::TransformMessage::Pointer mitk::IGTLDevice::GetNextTransformMessage() { return this->m_MessageQueue->PullTransformMessage(); } igtl::TrackingDataMessage::Pointer mitk::IGTLDevice::GetNextTrackingDataMessage() { igtl::TrackingDataMessage::Pointer msg = this->m_MessageQueue->PullTrackingMessage(); return msg; } igtl::StringMessage::Pointer mitk::IGTLDevice::GetNextStringMessage() { return this->m_MessageQueue->PullStringMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextMiscMessage() { return this->m_MessageQueue->PullMiscMessage(); } igtl::MessageBase::Pointer mitk::IGTLDevice::GetNextCommand() { return m_MessageQueue->PullCommandMessage(); } void mitk::IGTLDevice::EnableNoBufferingMode(bool enable) { m_MessageQueue->EnableNoBufferingMode(enable); } void mitk::IGTLDevice::EnableNoBufferingMode( mitk::IGTLMessageQueue::Pointer queue, bool enable) { queue->EnableNoBufferingMode(enable); } void mitk::IGTLDevice::ThreadStartSending() { this->RunCommunication(&IGTLDevice::Send, m_SendingFinishedMutex); } void mitk::IGTLDevice::ThreadStartReceiving() { this->RunCommunication(&IGTLDevice::Receive, m_ReceivingFinishedMutex); } void mitk::IGTLDevice::ThreadStartConnecting() { this->RunCommunication(&IGTLDevice::Connect, m_ConnectingFinishedMutex); } diff --git a/Modules/OpenIGTLink/mitkIGTLDevice.h b/Modules/OpenIGTLink/mitkIGTLDevice.h index 684d5953f2..f204bb6dbb 100644 --- a/Modules/OpenIGTLink/mitkIGTLDevice.h +++ b/Modules/OpenIGTLink/mitkIGTLDevice.h @@ -1,408 +1,412 @@ /*============================================================================ 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 MITKIGTLDEVICE_H #define MITKIGTLDEVICE_H #include #include #include "mitkCommon.h" //itk #include "itkObject.h" //igtl #include "igtlSocket.h" #include "igtlMessageBase.h" #include "igtlTransformMessage.h" //mitkIGTL #include "MitkOpenIGTLinkExports.h" #include "mitkIGTLMessageFactory.h" #include "mitkIGTLMessageQueue.h" #include "mitkIGTLMessage.h" +#if !defined(MITK_WINDOWS_NO_UNDEF) && defined(SendMessage) + #undef SendMessage +#endif + namespace mitk { /** * \brief Interface for all OpenIGTLink Devices * * Defines the methods that are common for all devices using OpenIGTLink. It * can open/close a connection, start/stop a communication and send/receive * messages. * * It uses message queues to store the incoming and outgoing mails. They are * configurable, you can set buffering on and off. * * The device is in one of three different states: Setup, Ready or Running. * Setup is the initial state. From this state on you can call * OpenConnection() and arrive in the Ready state. From the Ready state you * call StartCommunication() to arrive in the Running state. Now the device * is continuosly checking for new connections, receiving messages and * sending messages. This runs in a seperate thread. To stop the communication * call StopCommunication() (to arrive in Ready state) or CloseConnection() * (to arrive in the Setup state). * * \ingroup OpenIGTLink * */ class MITKOPENIGTLINK_EXPORT IGTLDevice : public itk::Object { public: mitkClassMacroItkParent(IGTLDevice, itk::Object); IGTLDevice(bool ReadFully); /** * \brief Type for state variable. * The IGTLDevice is always in one of these states. * */ enum IGTLDeviceState { Setup, Ready, Running }; /** * \brief Opens a connection to the device * * This may only be called if there is currently no connection to the * device. If OpenConnection() is successful, the object will change from * Setup state to Ready state. */ virtual bool OpenConnection() = 0; /** * \brief Closes the connection to the device * * This may only be called if there is currently a connection to the * device, but device is not running (e.g. object is in Ready state) */ virtual bool CloseConnection(); /** * \brief Stops the communication between the two devices * * This may only be called if the device is in Running state. */ virtual bool StopCommunication(); /** * \brief Starts the communication between the two devices * * This may only be called if the device is in Ready state. */ bool StartCommunication(); /** * \brief Continuously calls the given function * * This may only be called if the device is in Running state and only from * a seperate thread. * * \param ComFunction function pointer that specifies the method to be executed * \param mutex the mutex that corresponds to the function pointer */ void RunCommunication(void (IGTLDevice::*ComFunction)(void), std::mutex& mutex); /** * \brief Adds the given message to the sending queue * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). Note that the message * is not send directly. This method just adds it to the send queue. * \param msg The message to be added to the sending queue */ void SendMessage(mitk::IGTLMessage::Pointer msg); /** * \brief Returns current object state (Setup, Ready or Running) */ IGTLDeviceState GetState() const; /** * \brief Returns the oldest message in the command queue * \return The oldest message from the command queue. */ igtl::MessageBase::Pointer GetNextCommand(); /** * \brief Returns the oldest message in the receive queue * \return The oldest message from the receive queue */ igtl::ImageMessage::Pointer GetNextImage2dMessage(); igtl::ImageMessage::Pointer GetNextImage3dMessage(); igtl::TransformMessage::Pointer GetNextTransformMessage(); igtl::TrackingDataMessage::Pointer GetNextTrackingDataMessage(); igtl::StringMessage::Pointer GetNextStringMessage(); igtl::MessageBase::Pointer GetNextMiscMessage(); /** * \brief Sets the port number of the device */ itkSetMacro(PortNumber, int); /** * \brief Returns the port number of the device */ itkGetMacro(PortNumber, int); /** * \brief Sets the ip/hostname of the device */ itkSetMacro(Hostname, std::string); /** * \brief Returns the ip/hostname of the device */ itkGetMacro(Hostname, std::string); /** * \brief Returns the name of this device */ itkGetConstMacro(Name, std::string); /** * \brief Sets the name of this device */ itkSetMacro(Name, std::string); /** * \brief Advises this IGTL Device to always block until the whole message is read. */ itkSetMacro(ReadFully, bool); /** * \brief Returns a const reference to the receive queue */ itkGetConstMacro(MessageQueue, mitk::IGTLMessageQueue::Pointer); /** * \brief Returns the message factory */ itkGetMacro(MessageFactory, mitk::IGTLMessageFactory::Pointer); /** * \brief start method for the sending thread. */ void ThreadStartSending(); /** * \brief start method for the receiving thread. */ void ThreadStartReceiving(); /** * \brief start method for the connection thread. */ void ThreadStartConnecting(); /** * \brief TestConnection() tries to connect to a IGTL device on the current * ip and port * * \todo Implement this method. Send a status message and check the answer. * * TestConnection() tries to connect to a IGTL server on the current * ip and port and returns which device it has found. * \return It returns the type of the device that answers. Throws an * exception * if no device is available on that ip/port. * @throw mitk::Exception Throws an exception if there are errors * while connecting to the device. */ virtual bool TestConnection(); /** * \brief Send RTS message of given type */ bool SendRTSMessage(const char* type); /** * \brief Sets the buffering mode of the given queue */ void EnableNoBufferingMode(mitk::IGTLMessageQueue::Pointer queue, bool enable = true); void EnableNoBufferingMode(bool enable = true); /** * \brief Returns the number of connections of this device */ virtual unsigned int GetNumberOfConnections() = 0; itkGetMacro(LogMessages, bool); itkSetMacro(LogMessages, bool); protected: /** * \brief Sends a message. * * This may only be called after the connection to the device has been * established with a call to OpenConnection(). This method uses the given * socket to send the given MessageReceivedEvent * * \param msg the message to be sent * \param socket the socket used to communicate with the other device * * \retval IGTL_STATUS_OK the message was sent * \retval IGTL_STATUS_UNKONWN_ERROR the message was not sent because an * unknown error occurred */ unsigned int SendMessagePrivate(mitk::IGTLMessage::Pointer msg, igtl::Socket::Pointer socket); /** * \brief Call this method to receive a message. * * The message will be saved in the receive queue. */ virtual void Receive() = 0; /** * \brief Call this method to receive a message from the given device. * * The message will be saved in the receive queue. * * \param device the socket that connects this device with the other one. * * \retval IGTL_STATUS_OK a message or a command was received * \retval IGTL_STATUS_NOT_PRESENT the socket is not connected anymore * \retval IGTL_STATUS_TIME_OUT the socket timed out * \retval IGTL_STATUS_CHECKSUM_ERROR the checksum of the received msg was * incorrect * \retval IGTL_STATUS_UNKNOWN_ERROR an unknown error occurred */ unsigned int ReceivePrivate(igtl::Socket* device); /** * \brief Call this method to send a message. The message will be read from * the queue. */ virtual void Send() = 0; /** * \brief Call this method to check for other devices that want to connect * to this one. * * In case of a client this method is doing nothing. In case of a server it * is checking for other devices and if there is one it establishes a * connection. */ virtual void Connect(); /** * \brief Stops the communication with the given socket * */ virtual void StopCommunicationWithSocket(igtl::Socket* socket) = 0; /** * \brief change object state */ void SetState(IGTLDeviceState state); IGTLDevice(); ~IGTLDevice() override; /** current object state (Setup, Ready or Running) */ IGTLDeviceState m_State; /** the name of this device */ std::string m_Name; /** signal used to stop the thread*/ bool m_StopCommunication; /** mutex to control access to m_StopCommunication */ std::mutex m_StopCommunicationMutex; /** mutex used to make sure that the send thread is just started once */ std::mutex m_SendingFinishedMutex; /** mutex used to make sure that the receive thread is just started once */ std::mutex m_ReceivingFinishedMutex; /** mutex used to make sure that the connect thread is just started once */ std::mutex m_ConnectingFinishedMutex; /** mutex to control access to m_State */ mutable std::mutex m_StateMutex; /** the hostname or ip of the device */ std::string m_Hostname; /** the port number of the device */ int m_PortNumber; /** the socket used to communicate with other IGTL devices */ igtl::Socket::Pointer m_Socket; /** The message receive queue */ mitk::IGTLMessageQueue::Pointer m_MessageQueue; /** A message factory that provides the New() method for all msg types */ mitk::IGTLMessageFactory::Pointer m_MessageFactory; bool m_LogMessages; private: /** Sending thread */ std::thread m_SendThread; /** Receiving thread */ std::thread m_ReceiveThread; /** Connecting thread */ std::thread m_ConnectThread; /** Always try to read the full message. */ bool m_ReadFully; }; /** * \brief connect to this Event to get notified when a message was successfully sent * * \note This event is invoked in the communication thread, therefore do not use it to make * changes in the GUI!!! Use the QT signal slot system to decouple this call from the com thread * */ itkEventMacroDeclaration(MessageSentEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a message was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacroDeclaration(MessageReceivedEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when a command was received * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacroDeclaration(CommandReceivedEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when another igtl device * connects with this device. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacroDeclaration(NewClientConnectionEvent, itk::AnyEvent); /** * \brief connect to this Event to get notified when this device looses the * connection to a socket. * * \note Check if you can invoke this events like this or if you have to make * it thread-safe. They are not invoked in the main thread!!! * */ itkEventMacroDeclaration(LostConnectionEvent, itk::AnyEvent); } // namespace mitk #endif /* MITKIGTLDEVICE_H */ diff --git a/Modules/OpenIGTLink/mitkIGTLDummyMessage.h b/Modules/OpenIGTLink/mitkIGTLDummyMessage.h index 9ebd122a2b..13f7ee48e3 100644 --- a/Modules/OpenIGTLink/mitkIGTLDummyMessage.h +++ b/Modules/OpenIGTLink/mitkIGTLDummyMessage.h @@ -1,67 +1,62 @@ /*============================================================================ 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 MITKIGTLDUMMYMESSAGE_H #define MITKIGTLDUMMYMESSAGE_H #include "MitkOpenIGTLinkExports.h" #include "igtlObject.h" #include "igtlStringMessage.h" #include "mitkIGTLMessageCloneHandler.h" namespace mitk { /** * \class IGTLDummyMessage * \brief This class is a dummy message to show how to implement a new message type */ class MITKOPENIGTLINK_EXPORT IGTLDummyMessage : public igtl::StringMessage { public: - typedef IGTLDummyMessage Self; - typedef StringMessage Superclass; - typedef igtl::SmartPointer Pointer; - typedef igtl::SmartPointer ConstPointer; - igtlTypeMacro(mitk::IGTLDummyMessage, igtl::StringMessage); igtlNewMacro(mitk::IGTLDummyMessage); public: /** * Set dummy string */ void SetDummyString( const std::string& dummyString ); /** * Get dummy string */ std::string GetDummyString(); /** * Returns a clone of itself */ igtl::MessageBase::Pointer Clone() override ; protected: IGTLDummyMessage(); ~IGTLDummyMessage() override; std::string m_dummyString; }; mitkIGTMessageCloneClassMacro(IGTLDummyMessage, DummyMsgCloneHandler); } // namespace mitk #endif diff --git a/Modules/OpenIGTLink/mitkIGTLServer.cpp b/Modules/OpenIGTLink/mitkIGTLServer.cpp index e18c9ab5be..f68ad4fa30 100644 --- a/Modules/OpenIGTLink/mitkIGTLServer.cpp +++ b/Modules/OpenIGTLink/mitkIGTLServer.cpp @@ -1,207 +1,207 @@ /*============================================================================ 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 "mitkIGTLServer.h" #include #include #include #include #include -#include +#include mitk::IGTLServer::IGTLServer(bool ReadFully) : IGTLDevice(ReadFully) { } mitk::IGTLServer::~IGTLServer() { } bool mitk::IGTLServer::OpenConnection() { if (this->GetState() != Setup) { mitkThrowException(mitk::Exception) << "Can only try to create a server if in setup mode"; return false; } int portNumber = this->GetPortNumber(); if (portNumber == -1) { //port number was not correct return false; } //create a new server socket m_Socket = igtl::ServerSocket::New(); //try to create the igtl server int response = dynamic_cast(m_Socket.GetPointer())-> CreateServer(portNumber); //check the response if (response != 0) { mitkThrowException(mitk::Exception) << "The server could not be created. Port: " << portNumber; return false; } // everything is initialized and connected so the communication can be started this->SetState(Ready); return true; } bool mitk::IGTLServer::CloseConnection() { //remove all registered clients m_SentListMutex.lock(); m_ReceiveListMutex.lock(); SocketListType allRegisteredSockets(m_RegisteredClients); m_SentListMutex.unlock(); m_ReceiveListMutex.unlock(); this->StopCommunicationWithSocket(allRegisteredSockets); return mitk::IGTLDevice::CloseConnection(); } void mitk::IGTLServer::Connect() { igtl::Socket::Pointer socket; //check if another igtl device wants to connect to this socket socket = ((igtl::ServerSocket*)(this->m_Socket.GetPointer()))->WaitForConnection(1); //if there is a new connection the socket is not null if (socket.IsNotNull()) { //add the new client socket to the list of registered clients m_SentListMutex.lock(); m_ReceiveListMutex.lock(); this->m_RegisteredClients.push_back(socket); m_SentListMutex.unlock(); m_ReceiveListMutex.unlock(); //inform observers about this new client this->InvokeEvent(NewClientConnectionEvent()); MITK_INFO("IGTLServer") << "Connected to a new client: " << socket; } } void mitk::IGTLServer::Receive() { unsigned int status = IGTL_STATUS_OK; SocketListType socketsToBeRemoved; //the server can be connected with several clients, therefore it has to check //all registered clients SocketListIteratorType it; m_ReceiveListMutex.lock(); auto it_end = this->m_RegisteredClients.end(); for (it = this->m_RegisteredClients.begin(); it != it_end; ++it) { //it is possible that ReceivePrivate detects that the current socket is //already disconnected. Therefore, it is necessary to remove this socket //from the registered clients list status = this->ReceivePrivate(*it); if (status == IGTL_STATUS_NOT_PRESENT) { //remember this socket for later, it is not a good idea to remove it //from the list directly because we iterate over the list at this point socketsToBeRemoved.push_back(*it); MITK_WARN("IGTLServer") << "Lost connection to a client socket. "; } else if (status != 1) { MITK_DEBUG("IGTLServer") << "IGTL Message with status: " << status; } } m_ReceiveListMutex.unlock(); if (socketsToBeRemoved.size() > 0) { //remove the sockets that are not connected anymore this->StopCommunicationWithSocket(socketsToBeRemoved); //inform observers about loosing the connection to these sockets this->InvokeEvent(LostConnectionEvent()); } } void mitk::IGTLServer::Send() { //get the latest message from the queue mitk::IGTLMessage::Pointer curMessage = this->m_MessageQueue->PullSendMessage(); // there is no message => return if (curMessage.IsNull()) return; //the server can be connected with several clients, therefore it has to check //all registered clients //sending a message to all registered clients might not be the best solution, //it could be better to store the client together with the requested type. Then //the data would be send to the appropriate client and to noone else. //(I know it is no excuse but PLUS is doing exactly the same, they broadcast //everything) m_SentListMutex.lock(); SocketListIteratorType it; auto it_end = this->m_RegisteredClients.end(); for (it = this->m_RegisteredClients.begin(); it != it_end; ++it) { //maybe there should be a check here if the current socket is still active this->SendMessagePrivate(curMessage, *it); MITK_DEBUG("IGTLServer") << "Sent IGTL Message"; } m_SentListMutex.unlock(); } void mitk::IGTLServer::StopCommunicationWithSocket( SocketListType& toBeRemovedSockets) { for (auto i = toBeRemovedSockets.begin(); i != toBeRemovedSockets.end(); i++) this->StopCommunicationWithSocket(*i); } void mitk::IGTLServer::StopCommunicationWithSocket(igtl::Socket* client) { m_SentListMutex.lock(); m_ReceiveListMutex.lock(); auto i = m_RegisteredClients.begin(); auto end = m_RegisteredClients.end(); while (i != end) { if ((*i) == client) { // //close the socket (*i)->CloseSocket(); //and remove it from the list i = this->m_RegisteredClients.erase(i); MITK_INFO("IGTLServer") << "Removed client socket from server client list."; break; } else { ++i; } } m_SentListMutex.unlock(); m_ReceiveListMutex.unlock(); } unsigned int mitk::IGTLServer::GetNumberOfConnections() { return this->m_RegisteredClients.size(); } diff --git a/Modules/OpenIGTLink/mitkIGTLStatus.h b/Modules/OpenIGTLink/mitkIGTLStatus.h new file mode 100644 index 0000000000..1257cad374 --- /dev/null +++ b/Modules/OpenIGTLink/mitkIGTLStatus.h @@ -0,0 +1,39 @@ +/*============================================================================ + +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 __IGTL_STATUS_H // Same include guard as OpenIGTLink's igtl_status.h file +#define __IGTL_STATUS_H + +// Internal status codes from OpenIGTLink's igtl_status.h file + +#define IGTL_STATUS_INVALID 0 +#define IGTL_STATUS_OK 1 +#define IGTL_STATUS_UNKNOWN_ERROR 2 +#define IGTL_STATUS_PANICK_MODE 3 +#define IGTL_STATUS_NOT_FOUND 4 +#define IGTL_STATUS_ACCESS_DENIED 5 +#define IGTL_STATUS_BUSY 6 +#define IGTL_STATUS_TIME_OUT 7 +#define IGTL_STATUS_OVERFLOW 8 +#define IGTL_STATUS_CHECKSUM_ERROR 9 +#define IGTL_STATUS_CONFIG_ERROR 10 +#define IGTL_STATUS_RESOURCE_ERROR 11 +#define IGTL_STATUS_ILLEGAL_INSTRUCTION 12 +#define IGTL_STATUS_NOT_READY 13 +#define IGTL_STATUS_MANUAL_MODE 14 +#define IGTL_STATUS_DISABLED 15 +#define IGTL_STATUS_NOT_PRESENT 16 +#define IGTL_STATUS_UNKNOWN_VERSION 17 +#define IGTL_STATUS_HARDWARE_FAILURE 18 +#define IGTL_STATUS_SHUT_DOWN 19 + +#endif diff --git a/Modules/Python/CMakeLists.txt b/Modules/Python/CMakeLists.txt index 14a48964fa..161bddb4c7 100644 --- a/Modules/Python/CMakeLists.txt +++ b/Modules/Python/CMakeLists.txt @@ -1,13 +1,8 @@ if(MITK_USE_Python3) - set(OpenCV_DEP ) - if(MITK_USE_OpenCV) - set(OpenCV_DEP OpenCV) - endif() - mitk_create_module( DEPENDS MitkCore PACKAGE_DEPENDS PUBLIC Python3|Python ) add_subdirectory(autoload/PythonService) endif() diff --git a/Modules/QtPython/CMakeLists.txt b/Modules/QtPython/CMakeLists.txt index d497d472ef..433b7ae4f4 100644 --- a/Modules/QtPython/CMakeLists.txt +++ b/Modules/QtPython/CMakeLists.txt @@ -1,18 +1,13 @@ if(MITK_USE_Python3) mitkFunctionCheckCompilerFlags("/wd4273" CMAKE_CXX_FLAGS) - set(OpenCV_DEP ) - if(MITK_USE_OpenCV) - set(OpenCV_DEP OpenCV) - endif() - 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/QtWidgetsExt/include/QmitkHistogram.h b/Modules/QtWidgetsExt/include/QmitkHistogram.h index 6a0138af17..8becdc7e9d 100644 --- a/Modules/QtWidgetsExt/include/QmitkHistogram.h +++ b/Modules/QtWidgetsExt/include/QmitkHistogram.h @@ -1,57 +1,58 @@ /*============================================================================ 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 QMITKHISTOGRAM_H #define QMITKHISTOGRAM_H #include #include #include #include +#include /** \brief Used to create a histogram that can be shown in a Qwt Plot. See QmitkHistogramWidget for an example of its usage. */ class QmitkHistogram : public QwtPlotItem { public: explicit QmitkHistogram(const QString &title = QString::null); explicit QmitkHistogram(const QwtText &title); ~QmitkHistogram() override; void setData(const QwtIntervalSeriesData &data); const QwtIntervalSeriesData &data() const; void setColor(const QColor &); QColor color() const; QRectF boundingRect() const override; void draw(QPainter *, const QwtScaleMap &xMap, const QwtScaleMap &yMap, const QRectF &) const override; void setBaseline(double reference); double baseline() const; protected: virtual void drawBar(QPainter *, Qt::Orientation o, const QRect &) const; private: void init(); class HistogramData; HistogramData *m_Data; }; #endif diff --git a/Modules/QtWidgetsExt/include/QmitkPlotWidget.h b/Modules/QtWidgetsExt/include/QmitkPlotWidget.h index d8849416c1..caf0e86ab5 100644 --- a/Modules/QtWidgetsExt/include/QmitkPlotWidget.h +++ b/Modules/QtWidgetsExt/include/QmitkPlotWidget.h @@ -1,300 +1,301 @@ /*============================================================================ 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 _QmitkPlotWidget_H_ #define _QmitkPlotWidget_H_ #include "MitkQtWidgetsExtExports.h" #include "mitkCommon.h" #include #include #include #include #include #include +#include #include #include /** * Provides a convenient interface for plotting curves using qwt. * Designed for qwt version 5.2.1. * Can be used with a QmitkPlotDialog, which provides a "Close" button. * @see QmitkPlotDialog * * To plot data do the following: * 1. Create two QmitkPlotWidget::DataVector Objects and fill them * with corresponding x/y values. DataVectors are simple stl-vectors * of type std::vector. Please note that the xValues * vector and the yValues vector MUST have the same size. * 2. Instantiate the widget for example like that: * QmitkPlotWidget* widget = new QmitkPlotWidget( this, "widget" ); * widget->SetAxisTitle( QwtPlot::xBottom, "My x asis [mm]" ); * widget->SetAxisTitle( QwtPlot::yLeft, "My y axis [mm]" ); * int curveId = widget->InsertCurve( "My sophisticated data" ); * widget->SetCurveData( curveId, xValues, yValues ); * widget->SetCurvePen( curveId, QPen( red ) ); * widget->SetCurveTitle( curveId, "My curve description" ); * widget->Replot(); * 3. You can modify the behavior of the plot by directly referencing * the QwtPlot instance using the method GetPlot(). * @see QwtPlot * @deprecatedSince{2018_04} Use QmitkChartWidget instead */ class MITKQTWIDGETSEXT_EXPORT QmitkPlotWidget : public QWidget { private: Q_OBJECT public: /** * represents the data type used for scalar values stored * in data arrays. This type is provided by qwt and may not * be changed. */ typedef double ScalarType; /** * This type may be used to store a set of scalar values * representing either x or y coordinates of the data * points that should be rendered. */ typedef std::vector DataVector; /** * convenience type used to store pairs representing x/y coordinates * that should be rendered as a curve by the plot widget */ typedef std::vector> XYDataVector; /** * Standard qt constructor */ QmitkPlotWidget(QWidget *parent = nullptr, const char *title = nullptr, const char *name = nullptr, Qt::WindowFlags f = nullptr); /** * Virtual destructor */ ~QmitkPlotWidget() override; /** * Returns the instance of the plot-widget. This may be used * to modify any detail of the appearance of the plot. */ QwtPlot *GetPlot(); /** * Set the title using (formatted) QwtText object */ void SetPlotTitle(const QwtText &qwt_title); /** * Set plain text title, using default formatting */ void SetPlotTitle(const char *title); /** * Inserts a new curve into the plot-window. * @param title the name of the curve * @param color * @returns the id of the curve. Use this id to * refer to the curve, if you want to modify or add data. */ unsigned int InsertCurve(const char *title, QColor color = QColor(Qt::black)); /** * Sets the title of the given axis. For the set of available axes * @see QwtPlot::Axis. * @param axis the axis for which the description should be set. * @param title the name of the axis. */ void SetAxisTitle(int axis, const char *title); /** * Sets the data for a previously added curve. Data is provided as two vectors of double. * The first vector represents the x coordinates, the second vector represents the y coordinates. * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const DataVector &xValues, const DataVector &yValues); /** * @brief Sets the data with errors for a previously added curve. * * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @param yLowerError the magnitude (>0) of the error in the lesser direction of y * @param yUpperError the magnitude (>0) of the error in the larger direction of y * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const DataVector &xValues, const DataVector &yValues, const DataVector &yLowerError, const DataVector &yUpperError); /** * @brief Sets the data with errors for a previously added curve. * * @param curveId the id of the curve for which data should be added. * @param xValues the x coordinates of the points that define the curve * @param yValues the y coordinates of the points that define the curve * @param xLowerError the magnitude (>0) of the error in the lesser direction of x * @param xUpperError the magnitude (>0) of the error in the larger direction of x * @param yLowerError the magnitude (>0) of the error in the lesser direction of y * @param yUpperError the magnitude (>0) of the error in the larger direction of y * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const DataVector &xValues, const DataVector &yValues, const DataVector &xLowerError, const DataVector &xUpperError, const DataVector &yLowerError, const DataVector &yUpperError); /** * Sets the data for a previously added curve. Data is provided as a vectors of pairs. * The pairs represent x/y coordinates of the points that define the curve. * @param curveId the id of the curve for which data should be added. * @param data the coordinates of the points that define the curve * @returns whether data was added successfully or not */ bool SetCurveData(unsigned int curveId, const XYDataVector &data); /** * Defines how a curve should be drawn. For drawing a curve, a QPen is used. * @param curveId the id of the curve for which appearance should be changed * @param pen a QPen (@see QPen) defining the line style */ void SetCurvePen(unsigned int curveId, const QPen &pen); /** * Assign a brush, which defines the fill pattern of shapes drawn by a QPainter. * In case of brush.style() != QBrush::NoBrush and * style() != QwtPlotCurve::Sticks * the area between the curve and the baseline will be filled. * In case !brush.color().isValid() the area will be filled by pen.color(). * The fill algorithm simply connects the first and the last curve point to the * baseline. So the curve data has to be sorted (ascending or descending). * @param curveId the id of the curve for which appearance should be changed * @param brush a QBrush (@see QBrush) defining the line style */ void SetCurveBrush(unsigned int curveId, const QBrush &brush); /** * Sets the style how the line is drawn for the curve; like, plain line, * or with the data points marked with a symbol; * @param curveId * @param style A QwtPlotCurve::CurveStyle */ void SetCurveStyle(unsigned int curveId, const QwtPlotCurve::CurveStyle style); /** * Sets the style data points are drawn for the curve; like, a line, * or dots; * @param curveId * @param symbol A QwtSymbol */ void SetCurveSymbol(unsigned int curveId, QwtSymbol *symbol); void SetCurveAntialiasingOn(unsigned int curveId); void SetCurveAntialiasingOff(unsigned int curveId); /** * Sets the title of the given curve. The title will be shown in the legend of * the QwtPlot. * @param curveId the id of the curve for which the title should be set * @param title the description of the curve that will be shown in the legend. */ void SetCurveTitle(unsigned int curveId, const char *title); /** * Defines how a curves errors should be drawn. For drawing a QPen is used. * @param curveId the id of the curve for which error appearance should be changed * @param pen a QPen (@see QPen) defining the line style */ void SetErrorPen(unsigned int curveId, const QPen &pen); /** * Defines the style of errors, symbols or as a curve. * @param curveId the id of the curve for which error appearance should be changed * @param drawSmybols true - draw symbols, false - draw curve */ void SetErrorStyleSymbols(unsigned int curveId, bool drawSmybols); /** * Sets the legend of the plot * */ void SetLegend(QwtLegend *legend, QwtPlot::LegendPosition pos = QwtPlot::RightLegend, double ratio = -1); /** * Set a curve's legend attribute * @param curveId the id of the curve * @param attribute the legend attribute to be set */ void SetLegendAttribute(unsigned int curveId, const QwtPlotCurve::LegendAttribute &attribute); /** * Triggers a replot of the curve. Replot should be called once after * setting new data. */ void Replot(); /** * Resets the plot into an empty state */ void Clear(); protected: /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. */ double *ConvertToRawArray(const DataVector &values); /** * Converts the given values into a raw double* array. * A new array is allocated via new and must be deleted[] by the caller. * @param values the x/y values to convert to an array * @param component defines if the x values (0) or the y values(1) should * be converted. Other values than 0 and 1 will not be accepted. */ double *ConvertToRawArray(const XYDataVector &values, unsigned int component); /** * Adds an error interval curve. * * All errors should be absolutes. The magnitude will be used. * * @param curveId Which curve should the error curve be added to * @param lessError Error in the negative direction (value - lessError) * @param moreError Error in the positive direction (value + lessError) * @param isXError Should the error bars be drawn horizontally */ bool AddErrorIntervalCurve(unsigned int curveId, const DataVector &lessError, const DataVector &moreError, bool isXError); QwtPlot *m_Plot; std::vector> m_PlotCurveVector; }; #endif diff --git a/Modules/RT/CMakeLists.txt b/Modules/RT/CMakeLists.txt index 753686d460..50956dfe8b 100644 --- a/Modules/RT/CMakeLists.txt +++ b/Modules/RT/CMakeLists.txt @@ -1,10 +1,7 @@ -if(NOT DEFINED DCMTK_dcmrt_LIBRARY OR DCMTK_dcmrt_LIBRARY) - mitk_create_module( - DEPENDS MitkSceneSerializationBase MitkDICOM - PACKAGE_DEPENDS PUBLIC DCMTK - ) - add_subdirectory(autoload/DICOMRTIO) - add_subdirectory(test) -else() - message("MITK RT Support disabled because the DCMTK dcmrt library not found") -endif() +mitk_create_module( + DEPENDS MitkSceneSerializationBase MitkDICOM + PACKAGE_DEPENDS PRIVATE DCMTK|dcmrt +) + +add_subdirectory(autoload/DICOMRTIO) +add_subdirectory(test) diff --git a/Modules/RT/autoload/DICOMRTIO/CMakeLists.txt b/Modules/RT/autoload/DICOMRTIO/CMakeLists.txt index 54d3ff5335..fe902e05a0 100644 --- a/Modules/RT/autoload/DICOMRTIO/CMakeLists.txt +++ b/Modules/RT/autoload/DICOMRTIO/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE(DICOMRTIO INCLUDE_DIRS PRIVATE src/IO DEPENDS PUBLIC MitkRT MitkContourModel - PACKAGE_DEPENDS PUBLIC DCMTK + PACKAGE_DEPENDS PRIVATE DCMTK|dcmrt AUTOLOAD_WITH MitkCore ) diff --git a/Modules/RTUI/CMakeLists.txt b/Modules/RTUI/CMakeLists.txt index eb039647d2..148b6682b9 100644 --- a/Modules/RTUI/CMakeLists.txt +++ b/Modules/RTUI/CMakeLists.txt @@ -1,5 +1,7 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Qmitk Helper DEPENDS MitkRT - PACKAGE_DEPENDS PUBLIC CTK Qt5|Core + PACKAGE_DEPENDS + PUBLIC Qt5|Widgets + PRIVATE CTK|CTKWidgets ) diff --git a/Modules/ToFHardware/mitkToFOpenCVImageGrabber.cpp b/Modules/ToFHardware/mitkToFOpenCVImageGrabber.cpp index fd8b4e0cb7..561a6386ff 100644 --- a/Modules/ToFHardware/mitkToFOpenCVImageGrabber.cpp +++ b/Modules/ToFHardware/mitkToFOpenCVImageGrabber.cpp @@ -1,176 +1,178 @@ /*============================================================================ 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 "mitkToFOpenCVImageGrabber.h" // mitk includes #include "mitkImageDataItem.h" #include #include "mitkImageReadAccessor.h" #include "vtkSmartPointer.h" #include "vtkColorTransferFunction.h" #include "vtkFloatArray.h" +#include + namespace mitk { ToFOpenCVImageGrabber::ToFOpenCVImageGrabber() { m_CurrentOpenCVIntensityImage = nullptr; m_CurrentOpenCVAmplitudeImage = nullptr; m_CurrentOpenCVDistanceImage = nullptr; m_ImageType = 0; m_ImageDepth = IPL_DEPTH_32F; m_ImageGrabber = nullptr; } ToFOpenCVImageGrabber::~ToFOpenCVImageGrabber() { } cv::Mat ToFOpenCVImageGrabber::GetImage() { m_ImageGrabber->Update(); unsigned int numOfPixel = m_ImageGrabber->GetCaptureWidth()*m_ImageGrabber->GetCaptureHeight(); // copy current mitk images unsigned int dimensions[4]; dimensions[0] = this->m_ImageGrabber->GetCaptureWidth(); dimensions[1] = this->m_ImageGrabber->GetCaptureHeight(); dimensions[2] = 1; dimensions[3] = 1; // create single component float pixel type mitk::PixelType FloatType = MakeScalarPixelType(); ImageReadAccessor imgGrabAcc0(m_ImageGrabber->GetOutput(0), m_ImageGrabber->GetOutput(0)->GetSliceData()); ImageReadAccessor imgGrabAcc1(m_ImageGrabber->GetOutput(1), m_ImageGrabber->GetOutput(1)->GetSliceData()); ImageReadAccessor imgGrabAcc2(m_ImageGrabber->GetOutput(2), m_ImageGrabber->GetOutput(2)->GetSliceData()); mitk::Image::Pointer currentMITKIntensityImage = mitk::Image::New(); currentMITKIntensityImage->Initialize(FloatType, 2, dimensions); currentMITKIntensityImage->SetSlice((float*) imgGrabAcc2.GetData(),0,0,0); mitk::Image::Pointer currentMITKAmplitudeImage = mitk::Image::New(); currentMITKAmplitudeImage->Initialize(FloatType, 2, dimensions); currentMITKAmplitudeImage->SetSlice((float*)imgGrabAcc1.GetData(),0,0,0); mitk::Image::Pointer currentMITKDistanceImage = mitk::Image::New(); currentMITKDistanceImage->Initialize(FloatType, 2, dimensions); currentMITKDistanceImage->SetSlice((float*)imgGrabAcc0.GetData(),0,0,0); // copy mitk images to OpenCV images if (m_ImageDepth==IPL_DEPTH_32F) { if (m_ImageType==1) { ImageReadAccessor currentAmplAcc(currentMITKAmplitudeImage, currentMITKAmplitudeImage->GetSliceData(0, 0, 0)); float* amplitudeFloatData = (float*) currentAmplAcc.GetData(); memcpy(m_CurrentOpenCVAmplitudeImage->imageData,(unsigned char*)amplitudeFloatData,numOfPixel*sizeof(float)); return cv::cvarrToMat(m_CurrentOpenCVAmplitudeImage, false); } else if (m_ImageType==2) { ImageReadAccessor currentIntenAcc(currentMITKIntensityImage, currentMITKIntensityImage->GetSliceData(0, 0, 0)); float* intensityFloatData = (float*) currentIntenAcc.GetData(); memcpy(m_CurrentOpenCVIntensityImage->imageData,(unsigned char*)intensityFloatData,numOfPixel*sizeof(float)); return cv::cvarrToMat(m_CurrentOpenCVIntensityImage, false); } else { ImageReadAccessor currentDistAcc(currentMITKDistanceImage, currentMITKDistanceImage->GetSliceData(0, 0, 0)); float* distanceFloatData = (float*) currentDistAcc.GetData(); memcpy(m_CurrentOpenCVDistanceImage->imageData,(unsigned char*)distanceFloatData,numOfPixel*sizeof(float)); return cv::cvarrToMat(m_CurrentOpenCVDistanceImage, false); } } else { if (m_ImageType==1) { this->MapScalars(currentMITKAmplitudeImage, m_CurrentOpenCVAmplitudeImage); return cv::cvarrToMat(m_CurrentOpenCVAmplitudeImage, false); } else if (m_ImageType==2) { this->MapScalars(currentMITKIntensityImage, m_CurrentOpenCVIntensityImage); return cv::cvarrToMat(m_CurrentOpenCVIntensityImage, false); } else { this->MapScalars(currentMITKDistanceImage, m_CurrentOpenCVDistanceImage); return cv::cvarrToMat(m_CurrentOpenCVDistanceImage, false); } } } void ToFOpenCVImageGrabber::SetImageType(unsigned int imageType) { m_ImageType = imageType; } void ToFOpenCVImageGrabber::SetImageDepth(unsigned int imageDepth) { m_ImageDepth = imageDepth; } void ToFOpenCVImageGrabber::SetToFImageGrabber(ToFImageGrabber::Pointer imageGrabber) { m_ImageGrabber = imageGrabber; } ToFImageGrabber::Pointer ToFOpenCVImageGrabber::GetToFImageGrabber() { return m_ImageGrabber; } void ToFOpenCVImageGrabber::StartCapturing() { if (m_ImageGrabber.IsNotNull()) { m_ImageGrabber->ConnectCamera(); //Initialize cv Images after the camera is conneceted and we know the resolution m_CurrentOpenCVIntensityImage = cvCreateImage(cvSize(m_ImageGrabber->GetCaptureWidth(), m_ImageGrabber->GetCaptureHeight()), m_ImageDepth, 1); m_CurrentOpenCVAmplitudeImage = cvCreateImage(cvSize(m_ImageGrabber->GetCaptureWidth(), m_ImageGrabber->GetCaptureHeight()), m_ImageDepth, 1); m_CurrentOpenCVDistanceImage = cvCreateImage(cvSize(m_ImageGrabber->GetCaptureWidth(), m_ImageGrabber->GetCaptureHeight()), m_ImageDepth, 1); m_ImageGrabber->StartCamera(); } } void ToFOpenCVImageGrabber::StopCapturing() { if (m_ImageGrabber.IsNotNull()) { m_ImageGrabber->StopCamera(); m_ImageGrabber->DisconnectCamera(); } } void ToFOpenCVImageGrabber::MapScalars( mitk::Image::Pointer mitkImage, IplImage* openCVImage) { unsigned int numOfPixel = m_ImageGrabber->GetCaptureWidth()*m_ImageGrabber->GetCaptureHeight(); ImageReadAccessor imgAcc(mitkImage, mitkImage->GetSliceData(0, 0, 0)); float* floatData = (float*)imgAcc.GetData(); vtkSmartPointer colorTransferFunction = vtkSmartPointer::New(); vtkSmartPointer floatArrayInt = vtkSmartPointer::New(); floatArrayInt->Initialize(); floatArrayInt->SetArray(floatData, numOfPixel, 0); mitk::ScalarType min = mitkImage->GetStatistics()->GetScalarValueMin(); mitk::ScalarType max = mitkImage->GetStatistics()->GetScalarValueMaxNoRecompute(); MITK_INFO<<"Minimum: "<RemoveAllPoints(); colorTransferFunction->AddRGBPoint(min, 0, 0, 0); colorTransferFunction->AddRGBPoint(max, 1, 1, 1); colorTransferFunction->SetColorSpaceToHSV(); colorTransferFunction->MapScalarsThroughTable(floatArrayInt, (unsigned char*)openCVImage->imageData, VTK_LUMINANCE); } } // end namespace mitk diff --git a/Modules/ToFHardware/mitkToFOpenCVImageGrabber.h b/Modules/ToFHardware/mitkToFOpenCVImageGrabber.h index 03a64cadd7..292ba8176b 100644 --- a/Modules/ToFHardware/mitkToFOpenCVImageGrabber.h +++ b/Modules/ToFHardware/mitkToFOpenCVImageGrabber.h @@ -1,102 +1,104 @@ /*============================================================================ 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 __mitkToFOpenCVImageGrabber_h #define __mitkToFOpenCVImageGrabber_h #include #include "mitkCommon.h" #include "mitkOpenCVImageSource.h" #include "mitkToFImageGrabber.h" #include "itkObject.h" #include "itkObjectFactory.h" +#include + namespace mitk { /** * @brief TofImageGrabber class providing OpenCV images * * * @ingroup ToFHardware */ class MITKTOFHARDWARE_EXPORT ToFOpenCVImageGrabber : public mitk::OpenCVImageSource { public: ToFOpenCVImageGrabber(); ~ToFOpenCVImageGrabber() override; mitkClassMacro( ToFOpenCVImageGrabber , OpenCVImageSource ); itkFactorylessNewMacro(Self); itkCloneMacro(Self); /*! \brief Get current ToF image. Specify image you want to grab with SetImageType() */ cv::Mat GetImage() override; /*! \brief set type of image you want to grab. 0: Distance image (Default) 1: Amplitude image 2: Intensity image */ void SetImageType(unsigned int imageType); /*! \brief set the depth of the image. Some functions of OpenCV do not support IPL_DEPTH_32F. Warning: changing from default results in a mapping of the pixel value through a lookup table IPL_DEPTH_1U 1 IPL_DEPTH_8U 8 IPL_DEPTH_16U 16 IPL_DEPTH_32F 32 (Default) */ void SetImageDepth(unsigned int imageDepth); /*! \brief set the ImageGrabber used for fetching image data from the camera */ void SetToFImageGrabber(mitk::ToFImageGrabber::Pointer imageGrabber); /*! \brief get the ImageGrabber used for fetching image data from the camera */ mitk::ToFImageGrabber::Pointer GetToFImageGrabber(); void StartCapturing(); void StopCapturing(); protected: /*! \brief map scalars through lookup table \param mitkImage current MITK image \param openCVImage */ void MapScalars(mitk::Image::Pointer mitkImage, IplImage* openCVImage); mitk::ToFImageGrabber::Pointer m_ImageGrabber; ///< ImageGrabber used for fetching ToF image data from the camera unsigned int m_ImageType; ///< type of image currently supplied by this image source /*! \brief image depth currently used by this image source. Warning: Changing from default (IPL_DEPTH_32F) results in a mapping of the pixel value through a lookup table */ unsigned int m_ImageDepth; IplImage* m_CurrentOpenCVIntensityImage; ///< OpenCV image holding the current intensity data IplImage* m_CurrentOpenCVAmplitudeImage; ///< OpenCV image holding the current amplitude data IplImage* m_CurrentOpenCVDistanceImage; ///< OpenCV image holding the current distance data private: }; } //END mitk namespace #endif diff --git a/Modules/ToFProcessing/CMakeLists.txt b/Modules/ToFProcessing/CMakeLists.txt index 5e2e9cc973..47c6001b6a 100644 --- a/Modules/ToFProcessing/CMakeLists.txt +++ b/Modules/ToFProcessing/CMakeLists.txt @@ -1,12 +1,11 @@ MITK_CREATE_MODULE( DEPENDS MitkCameraCalibration - PACKAGE_DEPENDS OpenCV WARNINGS_NO_ERRORS ) if(BUILD_TESTING) add_subdirectory(Testing) endif(BUILD_TESTING) diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp index e7306d8edc..f86fc47521 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp @@ -1,398 +1,398 @@ /*============================================================================ 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 "mitkImageReadAccessor.h" #include -#include "opencv2/imgproc.hpp" +#include mitk::ToFCompositeFilter::ToFCompositeFilter() : m_SegmentationMask(nullptr), m_ImageWidth(0), m_ImageHeight(0), m_ImageSize(0), m_IplDistanceImage(nullptr), m_IplOutputImage(nullptr), m_ItkInputImage(nullptr), m_ApplyTemporalMedianFilter(false), m_ApplyAverageFilter(false), m_ApplyMedianFilter(false), m_ApplyThresholdFilter(false), m_ApplyMaskSegmentation(false), m_ApplyBilateralFilter(false), m_DataBuffer(nullptr), m_DataBufferCurrentIndex(0), m_DataBufferMaxSize(0), m_TemporalMedianFilterNumOfFrames(10), m_ThresholdFilterMin(1), m_ThresholdFilterMax(7000), m_BilateralFilterDomainSigma(2), m_BilateralFilterRangeSigma(60), m_BilateralFilterKernelRadius(0) { } mitk::ToFCompositeFilter::~ToFCompositeFilter() { cvReleaseImage(&(this->m_IplDistanceImage)); cvReleaseImage(&(this->m_IplOutputImage)); if (m_DataBuffer!=nullptr) { delete [] m_DataBuffer; } } void mitk::ToFCompositeFilter::SetInput( const InputImageType* distanceImage ) { this->SetInput(0, distanceImage); } void mitk::ToFCompositeFilter::SetInput( unsigned int idx, const InputImageType* distanceImage ) { if ((distanceImage == nullptr) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to nullptr, reduce the number of inputs by one { this->SetNumberOfIndexedInputs(this->GetNumberOfInputs() - 1); } else { if (idx==0) //create IPL image holding distance data { if (!distanceImage->IsEmpty()) { this->m_ImageWidth = distanceImage->GetDimension(0); this->m_ImageHeight = distanceImage->GetDimension(1); this->m_ImageSize = this->m_ImageWidth * this->m_ImageHeight * sizeof(float); if (this->m_IplDistanceImage != nullptr) { cvReleaseImage(&(this->m_IplDistanceImage)); } ImageReadAccessor distImgAcc(distanceImage, distanceImage->GetSliceData(0,0,0)); float* distanceFloatData = (float*) distImgAcc.GetData(); this->m_IplDistanceImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); if (this->m_IplOutputImage != nullptr) { cvReleaseImage(&(this->m_IplOutputImage)); } this->m_IplOutputImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); CreateItkImage(this->m_ItkInputImage); } } this->ProcessObject::SetNthInput(idx, const_cast(distanceImage)); // Process object is not const-correct so the const_cast is required here } this->CreateOutputsForAllInputs(); } mitk::Image* mitk::ToFCompositeFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFCompositeFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return nullptr; //TODO: geeignete exception werfen return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFCompositeFilter::GenerateData() { // copy input 1...n to output 1...n for (unsigned int idx=0; idxGetNumberOfOutputs(); idx++) { mitk::Image::Pointer outputImage = this->GetOutput(idx); mitk::Image::Pointer inputImage = this->GetInput(idx); if (outputImage.IsNotNull()&&inputImage.IsNotNull()) { ImageReadAccessor inputAcc(inputImage, inputImage->GetSliceData()); outputImage->CopyInformation(inputImage); outputImage->Initialize(inputImage->GetPixelType(),inputImage->GetDimension(),inputImage->GetDimensions()); outputImage->SetSlice(inputAcc.GetData()); } } //mitk::Image::Pointer outputDistanceImage = this->GetOutput(); ImageReadAccessor outputAcc(this->GetOutput(), this->GetOutput()->GetSliceData(0, 0, 0) ); float* outputDistanceFloatData = (float*) outputAcc.GetData(); //mitk::Image::Pointer inputDistanceImage = this->GetInput(); ImageReadAccessor inputAcc(this->GetInput(), this->GetInput()->GetSliceData(0, 0, 0) ); // copy initial distance image to ipl image float* distanceFloatData = (float*)inputAcc.GetData(); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); if (m_ApplyThresholdFilter||m_ApplyMaskSegmentation) { ProcessSegmentation(this->m_IplDistanceImage); } if (this->m_ApplyTemporalMedianFilter||this->m_ApplyAverageFilter) { ProcessStreamedQuickSelectMedianImageFilter(this->m_IplDistanceImage); } if (this->m_ApplyMedianFilter) { ProcessCVMedianFilter(this->m_IplDistanceImage, this->m_IplOutputImage); memcpy( this->m_IplDistanceImage->imageData, this->m_IplOutputImage->imageData, this->m_ImageSize ); } if (this->m_ApplyBilateralFilter) { float* itkFloatData = this->m_ItkInputImage->GetBufferPointer(); memcpy(itkFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); ItkImageType2D::Pointer itkOutputImage = ProcessItkBilateralFilter(this->m_ItkInputImage); memcpy( this->m_IplDistanceImage->imageData, itkOutputImage->GetBufferPointer(), this->m_ImageSize ); //ProcessCVBilateralFilter(this->m_IplDistanceImage, this->m_OutputIplImage, domainSigma, rangeSigma, kernelRadius); //memcpy( distanceFloatData, this->m_OutputIplImage->imageData, distanceImageSize ); } memcpy( outputDistanceFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); } void mitk::ToFCompositeFilter::CreateOutputsForAllInputs() { this->SetNumberOfIndexedOutputs(this->GetNumberOfInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfIndexedInputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } } this->Modified(); } void mitk::ToFCompositeFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if (output->IsInitialized()) return; itkDebugMacro(<<"GenerateOutputInformation()"); output->Initialize(input->GetPixelType(), *input->GetTimeGeometry()); output->SetPropertyList(input->GetPropertyList()->Clone()); } void mitk::ToFCompositeFilter::ProcessSegmentation(IplImage* inputIplImage) { char* segmentationMask; if (m_SegmentationMask.IsNotNull()) { ImageReadAccessor segMaskAcc(m_SegmentationMask, m_SegmentationMask->GetSliceData(0,0,0)); segmentationMask = (char*)segMaskAcc.GetData(); } else { segmentationMask = nullptr; } float *f = (float*)inputIplImage->imageData; for(int i=0; im_ImageWidth*this->m_ImageHeight; i++) { if (this->m_ApplyThresholdFilter) { if (f[i]<=m_ThresholdFilterMin) { f[i] = 0.0; } else if (f[i]>=m_ThresholdFilterMax) { f[i] = 0.0; } } if (this->m_ApplyMaskSegmentation) { if (segmentationMask) { if (segmentationMask[i]==0) { f[i] = 0.0; } } } } } ItkImageType2D::Pointer mitk::ToFCompositeFilter::ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage) { ItkImageType2D::Pointer outputItkImage; BilateralFilterType::Pointer bilateralFilter = BilateralFilterType::New(); bilateralFilter->SetInput(inputItkImage); bilateralFilter->SetDomainSigma(m_BilateralFilterDomainSigma); bilateralFilter->SetRangeSigma(m_BilateralFilterRangeSigma); //bilateralFilter->SetRadius(m_BilateralFilterKernelRadius); outputItkImage = bilateralFilter->GetOutput(); outputItkImage->Update(); return outputItkImage; } void mitk::ToFCompositeFilter::ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage) { int diameter = m_BilateralFilterKernelRadius; double sigmaColor = m_BilateralFilterRangeSigma; double sigmaSpace = m_BilateralFilterDomainSigma; cvSmooth(inputIplImage, outputIplImage, CV_BILATERAL, diameter, 0, sigmaColor, sigmaSpace); } void mitk::ToFCompositeFilter::ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius) { cvSmooth(inputIplImage, outputIplImage, CV_MEDIAN, radius, 0, 0, 0); } void mitk::ToFCompositeFilter::ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage) { float* data = (float*)inputIplImage->imageData; int imageSize = inputIplImage->width * inputIplImage->height; float* tmpArray; if (this->m_TemporalMedianFilterNumOfFrames == 0) { return; } if (m_TemporalMedianFilterNumOfFrames != this->m_DataBufferMaxSize) // reset { //delete current buffer for( int i=0; im_DataBufferMaxSize; i++ ) { delete[] this->m_DataBuffer[i]; } if (this->m_DataBuffer != nullptr) { delete[] this->m_DataBuffer; } this->m_DataBufferMaxSize = m_TemporalMedianFilterNumOfFrames; // create new buffer with current size this->m_DataBuffer = new float*[this->m_DataBufferMaxSize]; for(int i=0; im_DataBufferMaxSize; i++) { this->m_DataBuffer[i] = nullptr; } this->m_DataBufferCurrentIndex = 0; } int currentBufferSize = this->m_DataBufferMaxSize; tmpArray = new float[this->m_DataBufferMaxSize]; // copy data to buffer if (this->m_DataBuffer[this->m_DataBufferCurrentIndex] == nullptr) { this->m_DataBuffer[this->m_DataBufferCurrentIndex] = new float[imageSize]; currentBufferSize = this->m_DataBufferCurrentIndex + 1; } for(int j=0; jm_DataBuffer[this->m_DataBufferCurrentIndex][j] = data[j]; } float tmpValue = 0.0f; for(int i=0; im_DataBuffer[j][i]; } data[i] = tmpValue/currentBufferSize; } else if (m_ApplyTemporalMedianFilter) { for(int j=0; jm_DataBuffer[j][i]; } data[i] = quick_select(tmpArray, currentBufferSize); } } this->m_DataBufferCurrentIndex = (this->m_DataBufferCurrentIndex + 1) % this->m_DataBufferMaxSize; delete[] tmpArray; } #define ELEM_SWAP(a,b) { float t=(a);(a)=(b);(b)=t; } float mitk::ToFCompositeFilter::quick_select(float arr[], int n) { int low = 0; int high = n-1; int median = (low + high)/2; int middle = 0; int ll = 0; int hh = 0; for (;;) { if (high <= low) /* One element only */ return arr[median] ; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; return arr[median] ; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr[middle], arr[low+1]) ; /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]) ; do hh--; while (arr[hh] > arr[low]) ; if (hh < ll) break; ELEM_SWAP(arr[ll], arr[hh]) ; } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr[low], arr[hh]) ; /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } #undef ELEM_SWAP void mitk::ToFCompositeFilter::SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames) { this->m_TemporalMedianFilterNumOfFrames = tmporalMedianFilterNumOfFrames; } void mitk::ToFCompositeFilter::SetThresholdFilterParameter(int min, int max) { if (min > max) { min = max; } this->m_ThresholdFilterMin = min; this->m_ThresholdFilterMax = max; } void mitk::ToFCompositeFilter::SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius = 0) { this->m_BilateralFilterDomainSigma = domainSigma; this->m_BilateralFilterRangeSigma = rangeSigma; this->m_BilateralFilterKernelRadius = kernelRadius; } void mitk::ToFCompositeFilter::CreateItkImage(ItkImageType2D::Pointer &itkInputImage) { itkInputImage = ItkImageType2D::New(); ItkImageType2D::IndexType startIndex; startIndex[0] = 0; // first index on X startIndex[1] = 0; // first index on Y ItkImageType2D::SizeType size; size[0] = this->m_ImageWidth; // size along X size[1] = this->m_ImageHeight; // size along Y ItkImageType2D::RegionType region; region.SetSize( size ); region.SetIndex( startIndex ); itkInputImage->SetRegions( region ); itkInputImage->Allocate(); } diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.h b/Modules/ToFProcessing/mitkToFCompositeFilter.h index 81ce0f269b..eab524fa67 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.h +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.h @@ -1,193 +1,193 @@ /*============================================================================ 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 __mitkToFCompositeFilter_h #define __mitkToFCompositeFilter_h #include #include "mitkImageToImageFilter.h" #include #include -#include "opencv2/core.hpp" +#include typedef itk::Image ItkImageType2D; typedef itk::Image ItkImageType3D; typedef itk::BilateralImageFilter BilateralFilterType; namespace mitk { /** * @brief Applies a common filter-pipeline to the first input of this filter * * This class intends to allow quick preprocessing of (ToF) range data. Input 0 of this filter, holding the range image, * is processed using the following image processing filters: * - threshold filter * - mask segmentation * - temporal median filter * - spatial median filter * - bilateral filter * * @ingroup ToFProcessing */ class MITKTOFPROCESSING_EXPORT ToFCompositeFilter : public ImageToImageFilter { public: mitkClassMacro( ToFCompositeFilter , ImageToImageFilter ); itkFactorylessNewMacro(Self); itkCloneMacro(Self); itkSetMacro(SegmentationMask,mitk::Image::Pointer); itkSetMacro(ApplyTemporalMedianFilter,bool); itkGetConstMacro(ApplyTemporalMedianFilter,bool); itkSetMacro(ApplyAverageFilter,bool); itkGetConstMacro(ApplyAverageFilter,bool); itkSetMacro(ApplyMedianFilter,bool); itkGetConstMacro(ApplyMedianFilter,bool); itkSetMacro(ApplyThresholdFilter,bool); itkGetConstMacro(ApplyThresholdFilter,bool); itkSetMacro(ApplyMaskSegmentation,bool); itkGetConstMacro(ApplyMaskSegmentation,bool); itkSetMacro(ApplyBilateralFilter,bool); itkGetConstMacro(ApplyBilateralFilter,bool); using itk::ProcessObject::SetInput; /*! \brief sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ void SetInput( const InputImageType* distanceImage) override; /*! \brief sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera */ void SetInput(unsigned int idx, const InputImageType* distanceImage) override; /*! \brief returns the input of this filter */ Image* GetInput(); /*! \brief returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); /*! \brief Sets the parameter of the temporal median filter \param tmporalMedianFilterNumOfFrames number of frames to be considered for calulating the temporal median */ void SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames); /*! \brief Sets the parameters (lower, upper threshold) of the threshold filter \param min lower threshold of the threshold filter \param max upper threshold of the threshold filter */ void SetThresholdFilterParameter(int min, int max); /*! \brief Sets the parameters (domain sigma, range sigma, kernel radius) of the bilateral filter \param domainSigma Parameter controlling the smoothing effect of the bilateral filter. Default value: 2 \param rangeSigma Parameter controlling the edge preserving effect of the bilateral filter. Default value: 60 \param kernelRadius radius of the filter mask of the bilateral filter */ void SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius); protected: /*! \brief standard constructor */ ToFCompositeFilter(); /*! \brief standard destructor */ ~ToFCompositeFilter() override; void GenerateOutputInformation() override; /*! \brief method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ void GenerateData() override; /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); /*! \brief Applies a mask and/or threshold segmentation to the input image. All pixels with values outside the mask, below the lower threshold (min) and above the upper threshold (max) are assigned the pixel value 0 */ void ProcessSegmentation(IplImage* inputIplImage); /*! \brief Applies the ITK bilateral filter to the input image */ ItkImageType2D::Pointer ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage); /*! \brief Applies the OpenCV bilateral filter to the input image. */ void ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage); /*! \brief Applies the OpenCV median filter to the input image. */ void ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius = 3); /*! \brief Performs temporal median filter on an image given the number of frames to be considered */ void ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage); /*! \brief Quickselect algorithm * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. */ float quick_select(float arr[], int n); /*! \brief Initialize and allocate a 2D ITK image of dimension m_ImageWidth*m_ImageHeight */ void CreateItkImage(ItkImageType2D::Pointer &itkInputImage); mitk::Image::Pointer m_SegmentationMask; ///< mask image used for segmenting the image int m_ImageWidth; ///< x-dimension of the image int m_ImageHeight; ///< y-dimension of the image int m_ImageSize; ///< size of the image in bytes IplImage* m_IplDistanceImage; ///< OpenCV-representation of the distance image IplImage* m_IplOutputImage; ///< OpenCV-representation of the output image ItkImageType2D::Pointer m_ItkInputImage; ///< ITK representation of the distance image bool m_ApplyTemporalMedianFilter; ///< Flag indicating if the temporal median filter is currently active for processing the distance image bool m_ApplyAverageFilter; ///< Flag indicating if the average filter is currently active for processing the distance image bool m_ApplyMedianFilter; ///< Flag indicating if the spatial median filter is currently active for processing the distance image bool m_ApplyThresholdFilter; ///< Flag indicating if the threshold filter is currently active for processing the distance image bool m_ApplyMaskSegmentation; ///< Flag indicating if a mask segmentation is performed bool m_ApplyBilateralFilter; ///< Flag indicating if the bilateral filter is currently active for processing the distance image float** m_DataBuffer; ///< Buffer used for calculating the pixel-wise median over the last n (m_TemporalMedianFilterNumOfFrames) number of frames int m_DataBufferCurrentIndex; ///< Current index in the buffer of the temporal median filter int m_DataBufferMaxSize; ///< Maximal size for the buffer of the temporal median filter (m_DataBuffer) int m_TemporalMedianFilterNumOfFrames; ///< Number of frames to be used in the calculation of the temporal median int m_ThresholdFilterMin; ///< Lower threshold of the threshold filter. Pixels with values below will be assigned value 0 when applying the threshold filter int m_ThresholdFilterMax; ///< Lower threshold of the threshold filter. Pixels with values above will be assigned value 0 when applying the threshold filter double m_BilateralFilterDomainSigma; ///< Parameter of the bilateral filter controlling the smoothing effect of the filter. Default value: 2 double m_BilateralFilterRangeSigma; ///< Parameter of the bilateral filter controlling the edge preserving effect of the filter. Default value: 60 int m_BilateralFilterKernelRadius; ///< Kernel radius of the bilateral filter mask }; } //END mitk namespace #endif diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h index 1a65814578..ce5d418fce 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h +++ b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h @@ -1,190 +1,192 @@ /*============================================================================ 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 __mitkToFDistanceImageToSurfaceFilter_h #define __mitkToFDistanceImageToSurfaceFilter_h #include #include #include #include #include #include "mitkCameraIntrinsics.h" #include #include #include +#include + namespace mitk { /** * @brief Converts a Time-of-Flight (ToF) distance image to a 3D surface using the pinhole camera model for coordinate computation. * The intrinsic parameters of the camera (FocalLength, PrincipalPoint, InterPixelDistance) are set via SetCameraIntrinsics(). The * measured distance for each pixel corresponds to the distance between the object point and the corresponding image point on the * image plane. * * The coordinate conversion follows the model of a common pinhole camera where the origin of the camera * coordinate system (world coordinates) is at the pinhole * \image html Modules/ToFProcessing/Documentation/PinholeCameraModel.png * The definition of the image plane and its coordinate systems (pixel and mm) is depicted in the following image * \image html Modules/ToFProcessing/Documentation/ImagePlane.png * * @ingroup SurfaceFilters * @ingroup ToFProcessing */ class MITKTOFPROCESSING_EXPORT ToFDistanceImageToSurfaceFilter : public SurfaceSource { public: mitkClassMacro( ToFDistanceImageToSurfaceFilter , SurfaceSource ); itkFactorylessNewMacro(Self); itkCloneMacro(Self); itkSetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkGetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkSetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkGetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkSetMacro(TextureIndex,int); /** * @brief SetTriangulationThreshold Sets a triangulation threshold in order * to remove unusually huge faces from the surface. If this value is set, * the filter will check whether the distance between two neighboring vertices * exceeds the triangulation threshold. If yes, there vertices will not be * triangulated (connected with lines). The vertices will still be added to * the surface, but only as single point (if they have no other neighbors). * @param triangulationThreshold The triangulationThreshold in mm. (not mm*mm!) * @note vtkMath::Distance2BetweenPoints returns the squared distance * between two points and hence we square m_TriangulationThreshold in * order to save run-time. */ void SetTriangulationThreshold( double triangulationThreshold ); itkGetMacro(TriangulationThreshold, double); itkSetMacro(VertexIdList, vtkSmartPointer); itkGetMacro(VertexIdList, vtkSmartPointer); itkSetMacro(GenerateTriangularMesh,bool); itkGetMacro(GenerateTriangularMesh,bool); /** * @brief The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. */ enum ReconstructionModeType{ WithOutInterPixelDistance = 1, WithInterPixelDistance = 2, Kinect = 3}; itkSetEnumMacro(ReconstructionMode,ReconstructionModeType); itkGetEnumMacro(ReconstructionMode,ReconstructionModeType); /*! \brief Set scalar image used as texture of the surface. \param iplScalarImage OpenCV image for texturing */ void SetScalarImage(IplImage* iplScalarImage); /*! \brief Set scalar image used as texture of the surface. \return OpenCV image for texturing */ IplImage* GetScalarImage(); /*! \brief Set width of the scalar image used for texturing the surface \param width width (x-dimension) of the texture image */ void SetTextureImageWidth(int width); /*! \brief Set height of the scalar image used for texturing the surface \param height height (y-dimension) of the texture image */ void SetTextureImageHeight(int height); using itk::ProcessObject::SetInput; /*! \brief Sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage); /*! \brief Sets the input of this filter and the intrinsic parameters \param distanceImage input is the distance image of e.g. a ToF camera \param cameraIntrinsics */ virtual void SetInput( Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \brief Sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput(unsigned int idx, Image* distanceImage); /*! \brief Sets the input of this filter at idx and the intrinsic parameters \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera \param cameraIntrinsics This is the camera model which holds parameters like focal length, pixel size, etc. which are needed for the reconstruction of the surface. */ virtual void SetInput( unsigned int idx, Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \brief Returns the input of this filter */ Image* GetInput(); /*! \brief Returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); protected: /*! \brief Standard constructor */ ToFDistanceImageToSurfaceFilter(); /*! \brief Standard destructor */ ~ToFDistanceImageToSurfaceFilter() override; void GenerateOutputInformation() override; /*! \brief Method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ void GenerateData() override; /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); IplImage* m_IplScalarImage; ///< Scalar image used for surface texturing mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< Specifies the intrinsic parameters int m_TextureImageWidth; ///< Width (x-dimension) of the texture image int m_TextureImageHeight; ///< Height (y-dimension) of the texture image ToFProcessingCommon::ToFPoint2D m_InterPixelDistance; ///< distance in mm between two adjacent pixels on the ToF camera chip int m_TextureIndex; ///< Index of the input used as texture image when no scalar image was set via SetIplScalarImage(). 0 = Distance, 1 = Amplitude, 2 = Intensity bool m_GenerateTriangularMesh; ReconstructionModeType m_ReconstructionMode; ///< The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. vtkSmartPointer m_VertexIdList; ///< Make a vtkIdList to save the ID's of the polyData corresponding to the image pixel ID's. This can be accessed after generate data to obtain the mapping. double m_TriangulationThreshold; }; } //END mitk namespace #endif diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.cpp b/Modules/US/USFilters/mitkUSImageVideoSource.cpp index 539158691c..f95ff55eed 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.cpp +++ b/Modules/US/USFilters/mitkUSImageVideoSource.cpp @@ -1,226 +1,226 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK HEADER #include "mitkUSImageVideoSource.h" #include "mitkImage.h" //Other #include -#include +#include mitk::USImageVideoSource::USImageVideoSource() : m_VideoCapture(new cv::VideoCapture()), m_IsVideoReady(false), m_IsGreyscale(false), m_IsCropped(false), m_ResolutionOverrideWidth(0), m_ResolutionOverrideHeight(0), m_ResolutionOverride(false), m_GrayscaleFilter(mitk::ConvertGrayscaleOpenCVImageFilter::New()), m_CropFilter(mitk::CropOpenCVImageFilter::New()) { } mitk::USImageVideoSource::~USImageVideoSource() { m_VideoCapture->release(); delete m_VideoCapture; } void mitk::USImageVideoSource::SetVideoFileInput(std::string path) { m_VideoCapture->open(path.c_str()); // check if we succeeded if(!m_VideoCapture->isOpened()) { m_IsVideoReady = false; } else { m_IsVideoReady = true; } // if Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetCameraInput(int deviceID) { m_VideoCapture->open(deviceID); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // if Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::ReleaseInput() { m_VideoCapture->release(); delete m_VideoCapture; m_VideoCapture = new cv::VideoCapture(); } void mitk::USImageVideoSource::SetColorOutput(bool isColor){ if ( ! isColor && ! m_IsGreyscale ) { this->PushFilter(m_GrayscaleFilter.GetPointer()); } else if ( isColor && m_IsGreyscale ) { this->RemoveFilter(m_GrayscaleFilter.GetPointer()); } m_IsGreyscale = !isColor; } int mitk::USImageVideoSource::GetImageHeight() { if (m_VideoCapture) { return m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); } else { return 0; } } int mitk::USImageVideoSource::GetImageWidth() { if (m_VideoCapture) { return m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); } else { return 0; } } bool mitk::USImageVideoSource::GetIsReady() { if (!m_VideoCapture) { return false; } return m_VideoCapture->isOpened(); } void mitk::USImageVideoSource::SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY) { m_CropFilter->SetCropRegion(topLeftX, topLeftY, bottomRightX, bottomRightY); if (! m_IsCropped && ! m_CropFilter->GetIsCropRegionEmpty()) { this->PushFilter(m_CropFilter.GetPointer()); m_IsCropped = true; } } void mitk::USImageVideoSource::SetRegionOfInterest(USImageRoi roi) { this->SetRegionOfInterest(roi.topLeftX, roi.topLeftY, roi.bottomRightX, roi.bottomRightY); } void mitk::USImageVideoSource::SetCropping(USImageCropping cropping) { int width = this->GetImageWidth(); int height = this->GetImageHeight(); this->SetRegionOfInterest(cropping.left, cropping.top, width - cropping.right, height - cropping.bottom); } mitk::USImageVideoSource::USImageCropping mitk::USImageVideoSource::GetCropping() { cv::Rect cropRect = m_CropFilter->GetCropRegion(); USImageCropping cropping; cropping.left = cropRect.x; cropping.top = cropRect.y; if ( cropRect.height == 0 ) { cropping.bottom = 0; } else { cropping.bottom = this->GetImageHeight() - (cropRect.y + cropRect.height); } if ( cropRect.width == 0 ) { cropping.right = 0; } else { cropping.right = this->GetImageWidth() - (cropRect.x + cropRect.width); } return cropping; } mitk::USImageVideoSource::USImageRoi mitk::USImageVideoSource::GetRegionOfInterest() { cv::Rect cropRect = m_CropFilter->GetCropRegion(); return USImageRoi(cropRect.x, cropRect.y, cropRect.x + cropRect.width, cropRect.y + cropRect.height); } void mitk::USImageVideoSource::RemoveRegionOfInterest() { this->RemoveFilter(m_CropFilter.GetPointer()); m_IsCropped = false; } void mitk::USImageVideoSource::GetNextRawImage(std::vector& image ) { // loop video if necessary //Commented out because setting and getting of these properties is not supported. Therefore on Linux //you'll always get some Highgui errors from OpenCV /*if (m_VideoCapture->get(CV_CAP_PROP_POS_FRAMES) == m_VideoCapture->get(CV_CAP_PROP_FRAME_COUNT)) { m_VideoCapture->set(CV_CAP_PROP_POS_FRAMES, 0); }*/ if (image.size() != 1) image.resize(1); // retrieve image *m_VideoCapture >> image[0]; // get a new frame from camera } void mitk::USImageVideoSource::GetNextRawImage(std::vector& image ) { if (image.size() != 1) image.resize(1); std::vector cv_img; this->GetNextRawImage(cv_img); // convert to MITK-Image IplImage ipl_img = cvIplImage(cv_img[0]); this->m_OpenCVToMitkFilter->SetOpenCVImage(&ipl_img); this->m_OpenCVToMitkFilter->Update(); // OpenCVToMitkImageFilter returns a standard mitk::image. We then transform it into an USImage image[0] = this->m_OpenCVToMitkFilter->GetOutput(); // clean up cv_img[0].release(); } void mitk::USImageVideoSource::OverrideResolution(int width, int height) { this->m_ResolutionOverrideHeight = height; this->m_ResolutionOverrideWidth = width; if (m_VideoCapture != nullptr) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, width); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, height); } } diff --git a/Plugins/org.blueberry.core.runtime/CMakeLists.txt b/Plugins/org.blueberry.core.runtime/CMakeLists.txt index fe06634e4c..1cfa45d44a 100644 --- a/Plugins/org.blueberry.core.runtime/CMakeLists.txt +++ b/Plugins/org.blueberry.core.runtime/CMakeLists.txt @@ -1,18 +1,18 @@ project(org_blueberry_core_runtime) mitk_create_plugin( EXPORT_DIRECTIVE org_blueberry_core_runtime_EXPORT EXPORTED_INCLUDE_SUFFIXES src src/application src/dynamichelpers src/registry MODULE_DEPENDS PUBLIC mbilog PACKAGE_DEPENDS PUBLIC Poco|Foundation+Util+XML PRIVATE Qt5|Gui+Xml ) -target_compile_definitions(${PLUGIN_TARGET} PUBLIC "$<$:POCO_NO_UNWINDOWS;WIN32_LEAN_AND_MEAN>") +target_compile_definitions(${PLUGIN_TARGET} PUBLIC "$<$:WIN32_LEAN_AND_MEAN>") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/berryConfig.h.in" "${CMAKE_CURRENT_BINARY_DIR}/berryConfig.h" @ONLY) diff --git a/Plugins/org.mitk.gui.qt.dicombrowser/CMakeLists.txt b/Plugins/org.mitk.gui.qt.dicombrowser/CMakeLists.txt index 2939dc3c5c..f8c21fc0fe 100644 --- a/Plugins/org.mitk.gui.qt.dicombrowser/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.dicombrowser/CMakeLists.txt @@ -1,28 +1,29 @@ project(org_mitk_gui_qt_dicombrowser) # Note: # If we use an installed version of DCMTK then DCMTK_DIR points to the subdirectory # of the installation directory (share/dcmtk) that contains DCMTKConfig.cmake. # Therefore we look for the the storescp command in the '../../bin' directory, too. find_program(DCMTK_STORESCP NAMES storescp storescp${DCMTK_CMAKE_DEBUG_POSTFIX} storescp${CMAKE_DEBUG_POSTFIX} PATHS "${MITK_EXTERNAL_PROJECT_PREFIX}/bin" PATH_SUFFIXES Release Debug DOC "Dcmtk storage provider which is used to store dicom files which are transfered over network." NO_DEFAULT_PATH ) mark_as_advanced(DCMTK_STORESCP) if(NOT EXISTS ${DCMTK_STORESCP}) message(WARNING "Couldn't find program storescp: Query/retrieve of the DICOM plugin won't work!") else() configure_file( org_mitk_gui_qt_dicombrowser_config.h.in org_mitk_gui_qt_dicombrowser_config.h @ONLY) MITK_INSTALL_HELPER_APP(EXECUTABLES ${DCMTK_STORESCP}) mitk_create_plugin( EXPORT_DIRECTIVE DICOM_EXPORT EXPORTED_INCLUDE_SUFFIXES src MODULE_DEPENDS MitkContourModel MitkQtWidgetsExt MitkDICOMUI MitkRT MitkRTUI MitkDICOM + PACKAGE_DEPENDS CTK|CTKDICOMWidgets ) endif()