diff --git a/CMake/MITKDashboardScript.TEMPLATE.cmake b/CMake/MITKDashboardScript.TEMPLATE.cmake index 89b6279cf1..663f15eb44 100644 --- a/CMake/MITKDashboardScript.TEMPLATE.cmake +++ b/CMake/MITKDashboardScript.TEMPLATE.cmake @@ -1,153 +1,146 @@ # # OS: Ubuntu 9.04 2.6.28-18-generic # Hardware: x86_64 GNU/Linux # GPU: NA # # Note: The specific version and processor type of this machine should be reported in the # header above. Indeed, this file will be send to the dashboard as a NOTE file. cmake_minimum_required(VERSION 3.14.5 FATAL_ERROR) # # Dashboard properties # set(MY_COMPILER "gcc-4.9.x") # For Windows, e.g. #set(MY_COMPILER "VC12.0") set(CTEST_CMAKE_COMMAND "/usr/bin/cmake") set(CTEST_CMAKE_GENERATOR "Unix Makefiles") set(CTEST_DASHBOARD_ROOT "/opt/dartclients") # For Windows, e.g. #set(CTEST_CMAKE_COMMAND "cmake") #set(CTEST_CMAKE_GENERATOR "Visual Studio 16 2019") #set(CTEST_CMAKE_GENERATOR_PLATFORM "x64") #set(CTEST_DASHBOARD_ROOT "D:/dc") set(MITK_EXTENSIONS # "||" # "https://phabricator.mitk.org/source/mitk-projecttemplate.git|master|MITK-ProjectTemplate" # "https://phabricator.mitk.org/source/mitk-diffusion.git|master|MITK-Diffusion" ) -# The directory containing the Qt binaries -set(QT5_INSTALL_PREFIX "/home/user/Qt/5.12.6/gcc_64") -# For Windows, e.g. -#set(QT5_INSTALL_PREFIX "C:/Qt/5.12.6/msvc2017_64") - -set(QT_BINARY_DIR "${QT5_INSTALL_PREFIX}/bin") - # # Dashboard options # set(WITH_KWSTYLE FALSE) set(WITH_MEMCHECK FALSE) set(WITH_COVERAGE FALSE) set(WITH_DOCUMENTATION FALSE) #set(DOCUMENTATION_ARCHIVES_OUTPUT_DIRECTORY ) # for example: $ENV{HOME}/Projects/Doxygen set(CTEST_BUILD_CONFIGURATION "Release") set(CTEST_TEST_TIMEOUT 500) if(UNIX) set(CTEST_BUILD_FLAGS "-j4") # Use multiple CPU cores to build else() set(CTEST_BUILD_FLAGS "") endif() # experimental: # - run_ctest() macro will be called *ONE* time # - binary directory will *NOT* be cleaned # continuous: # - run_ctest() macro will be called EVERY 5 minutes ... # - binary directory will *NOT* be cleaned # - configure/build will be executed *ONLY* if the repository has been updated # nightly: # - run_ctest() macro will be called *ONE* time # - binary directory *WILL BE* cleaned set(SCRIPT_MODE "experimental") # "experimental", "continuous", "nightly" # # Project specific properties # # In order to shorten the global path length, the build directory for each DartClient # uses the following abrevation sceme: # For build configuration: # Debug -> d # Release -> r # For scripte mode: # continuous -> c # nightly -> n # experimental -> e # Example directory: /MITK-sb-d-n/ for a nightly MITK superbuild in debug mode. set(short_of_ctest_build_configuration "") set(short_of_script_mode "") string(SUBSTRING ${CTEST_BUILD_CONFIGURATION} 0 1 short_of_ctest_build_configuration) string(SUBSTRING ${SCRIPT_MODE} 0 1 short_of_script_mode) set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK") set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK-sb-${short_of_ctest_build_configuration}-${short_of_script_mode}") # Create an initial cache file for MITK. This file is used to configure the MITK-Build. Use ADDITIONAL_CMAKECACHE_OPTION # to configure the MITK-Superbuild. The set(MITK_INITIAL_CACHE " # Example how to set a boolean variable in the MITK-Build via this script: #set(MITK_ENABLE_TOF_HARDWARE \"TRUE\" CACHE INTERNAL \"Enable ToF Hardware\") # Example how to set a path variable in the MITK-Build via this script: #set(MITK_PMD_LIB \"/home/kilgus/thomas/PMDSDK2/Linux_x86_64/bin/libpmdaccess2.so\" CACHE INTERNAL \"PMD lib\") ") set(ADDITIONAL_CMAKECACHE_OPTION " # Superbuild variables are not passed through to the MITK-Build (or any other build like ITK, VTK, ...) # Use the MITK_INITIAL_CACHE the pass variables to the MITK-Build. # add entries like this #MITK_USE_OpenCV:BOOL=OFF CMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} ") # List of test that should be explicitly disabled on this machine set(TEST_TO_EXCLUDE_REGEX "") # set any extra environment variables here -set(ENV{DISPLAY} ":0") +set(ENV{PATH} "$ENV{PATH}") find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) # # Git repository - Overwrite the default value provided by the driver script # # The git repository containing MITK code #set(GIT_REPOSITORY "/home/username/MITK") # The branch of the MITK git repository to check out #set(GIT_BRANCH "bug-xxx-label") ########################################## # WARNING: DO NOT EDIT BEYOND THIS POINT # ########################################## # # Convenient macro allowing to download a file # macro(downloadFile url dest) file(DOWNLOAD "${url}" "${dest}" STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() # # Download and include setup script # if(NOT DEFINED GIT_BRANCH OR GIT_BRANCH STREQUAL "") set(IS_PHABRICATOR_URL FALSE) set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardSetup.cmake") else() set(IS_PHABRICATOR_URL TRUE) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardSetup.cmake?view=raw") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.setup) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/CMake/MITKDashboardSetup.cmake b/CMake/MITKDashboardSetup.cmake index a0e467d953..eb41141d25 100644 --- a/CMake/MITKDashboardSetup.cmake +++ b/CMake/MITKDashboardSetup.cmake @@ -1,166 +1,145 @@ # This file is intended to be included at the end of a custom MITKDashboardScript.TEMPLATE.cmake file list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") # # Automatically determined properties # set(MY_OPERATING_SYSTEM ) if(UNIX) # Download a utility script # See T24757. # if(IS_PHABRICATOR_URL) # set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw") # else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/mitkDetectOS.sh") # endif() set(dest "${CTEST_SCRIPT_DIRECTORY}/mitkDetectOS.sh") downloadFile("${url}" "${dest}") execute_process(COMMAND sh "${dest}" RESULT_VARIABLE _result OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT _result) set(MY_OPERATING_SYSTEM "${_out}") endif() endif() if(NOT MY_OPERATING_SYSTEM) set(MY_OPERATING_SYSTEM "${CMAKE_HOST_SYSTEM}") # Windows 7, Linux-2.6.32, Darwin... endif() site_name(CTEST_SITE) if(NOT DEFINED MITK_USE_Qt5) set(MITK_USE_Qt5 1) endif() -if(MITK_USE_Qt5) - if(NOT QT_QMAKE_EXECUTABLE) - find_program(QT_QMAKE_EXECUTABLE NAMES qmake qmake-qt5 - HINTS ${QT_BINARY_DIR}) - endif() - - execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} --version - OUTPUT_VARIABLE MY_QT_VERSION - RESULT_VARIABLE qmake_error) - if(qmake_error) - message(FATAL_ERROR "Error when executing ${QT_QMAKE_EXECUTABLE} --version\n${qmake_error}") - endif() - - string(REGEX REPLACE ".*Qt version ([0-9.]+) .*" "\\1" MY_QT_VERSION ${MY_QT_VERSION}) -endif() - # # Project specific properties # if(NOT CTEST_BUILD_NAME) if(MITK_USE_Qt5) - set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} Qt${MY_QT_VERSION} ${CTEST_BUILD_CONFIGURATION}") + set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}") else() set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}") endif() set(CTEST_BUILD_NAME "${CTEST_BUILD_NAME}${CTEST_BUILD_NAME_SUFFIX}") endif() set(PROJECT_BUILD_DIR "MITK-build") set(CTEST_PATH "$ENV{PATH}") if(WIN32) if("${CTEST_CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64") set(CMAKE_LIBRARY_ARCHITECTURE x64) else() set(CMAKE_LIBRARY_ARCHITECTURE x86) endif() string(SUBSTRING "${MY_COMPILER}" 2 2 vc_version) set(OPENCV_BIN_DIR "${CTEST_BINARY_DIRECTORY}/ep/${CMAKE_LIBRARY_ARCHITECTURE}/vc${vc_version}/bin") set(BLUEBERRY_RUNTIME_DIR "${CTEST_BINARY_DIRECTORY}/MITK-build/bin/plugins/${CTEST_BUILD_CONFIGURATION}") set(PYTHON_BINARY_DIRS "${CTEST_BINARY_DIRECTORY}/ep/src/CTK-build/CMakeExternals/Install/bin") get_filename_component(_python_dir "${Python3_EXECUTABLE}" DIRECTORY) list(APPEND PYTHON_BINARY_DIRS "${_python_dir}") - set(CTEST_PATH "${CTEST_PATH};${CTEST_BINARY_DIRECTORY}/ep/bin;${QT_BINARY_DIR};${BLUEBERRY_RUNTIME_DIR};${OPENCV_BIN_DIR};${PYTHON_BINARY_DIRS}") + set(CTEST_PATH "${CTEST_PATH};${CTEST_BINARY_DIRECTORY}/ep/bin;${BLUEBERRY_RUNTIME_DIR};${OPENCV_BIN_DIR};${PYTHON_BINARY_DIRS}") endif() set(ENV{PATH} "${CTEST_PATH}") # If the dashscript doesn't define a GIT_REPOSITORY variable, let's define it here. if(NOT DEFINED GIT_REPOSITORY OR GIT_REPOSITORY STREQUAL "") set(GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git") endif() # # Display build info # message("Site name: ${CTEST_SITE}") message("Build name: ${CTEST_BUILD_NAME}") message("Script Mode: ${SCRIPT_MODE}") message("Coverage: ${WITH_COVERAGE}, MemCheck: ${WITH_MEMCHECK}") # # Set initial cache options # if(CTEST_CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(CTEST_USE_LAUNCHERS 1) else() set(CTEST_USE_LAUNCHERS 0) endif() set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} ${CTEST_USE_LAUNCHERS}) if(NOT DEFINED MITK_BUILD_CONFIGURATION) set(MITK_BUILD_CONFIGURATION "All") endif() if(NOT DEFINED MITK_VTK_DEBUG_LEAKS) set(MITK_VTK_DEBUG_LEAKS 1) endif() set(INITIAL_CMAKECACHE_OPTIONS " SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} MITK_VTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} ${ADDITIONAL_CMAKECACHE_OPTION} ") -if(MITK_USE_Qt5) - set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} -QT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}") -endif() - # Write a cache file for populating the MITK initial cache (not the superbuild cache). # This can be used to provide variables which are not passed through the # superbuild process to the MITK configure step) if(MITK_INITIAL_CACHE) set(mitk_cache_file "${CTEST_SCRIPT_DIRECTORY}/mitk_initial_cache.txt") file(WRITE "${mitk_cache_file}" "${MITK_INITIAL_CACHE}") set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} MITK_INITIAL_CACHE_FILE:INTERNAL=${mitk_cache_file} ") endif() if(MITK_EXTENSIONS) set(MITK_EXTENSION_DIRS "") foreach(extension ${MITK_EXTENSIONS}) if(extension MATCHES "[^|]+\\|[^|]+\\|(.+)") if(MITK_EXTENSION_DIRS) set(MITK_EXTENSION_DIRS "${MITK_EXTENSION_DIRS};") endif() set(MITK_EXTENSION_DIRS "${MITK_EXTENSION_DIRS}${CTEST_DASHBOARD_ROOT}/${CMAKE_MATCH_1}") endif() endforeach() endif() # # Download and include dashboard driver script # if(IS_PHABRICATOR_URL) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardDriverScript.cmake?view=raw") else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardDriverScript.cmake") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.driver) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/CMakeExternals/CTK.cmake b/CMakeExternals/CTK.cmake index baab5eaf7f..9324832e57 100644 --- a/CMakeExternals/CTK.cmake +++ b/CMakeExternals/CTK.cmake @@ -1,101 +1,101 @@ #----------------------------------------------------------------------------- # CTK #----------------------------------------------------------------------------- if(MITK_USE_CTK) # Sanity checks if(DEFINED CTK_DIR AND NOT EXISTS ${CTK_DIR}) message(FATAL_ERROR "CTK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj CTK) set(proj_DEPENDENCIES DCMTK) set(CTK_DEPENDS ${proj}) if(NOT DEFINED CTK_DIR) set(revision_tag "78341aba") set(ctk_optional_cache_args ) if(MITK_USE_Python3) list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=ON -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF "-DPYTHON_INCLUDE_DIR:PATH=${Python3_INCLUDE_DIRS}" "-DPYTHON_LIBRARY:FILEPATH=${Python3_LIBRARY_RELEASE}" ) else() list(APPEND ctk_optional_cache_args -DCTK_LIB_Scripting/Python/Widgets:BOOL=OFF -DCTK_ENABLE_Python_Wrapping:BOOL=OFF -DCTK_APP_ctkSimplePythonShell:BOOL=OFF -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=d ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND ctk_optional_cache_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() FOREACH(type RUNTIME ARCHIVE LIBRARY) IF(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) LIST(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) ENDIF() ENDFOREACH() mitk_query_custom_ep_vars() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} GIT_REPOSITORY https://github.com/commontk/CTK GIT_TAG ${revision_tag} UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_GENERATOR_PLATFORM ${gen_platform} CMAKE_ARGS ${ep_common_args} ${ctk_optional_cache_args} # The CTK PluginFramework cannot cope with # a non-empty CMAKE_DEBUG_POSTFIX for the plugin # libraries yet. -DCMAKE_DEBUG_POSTFIX:STRING= -DCTK_QT_VERSION:STRING=5 -DQt5_DIR=${Qt5_DIR} -DGit_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} -DGIT_EXECUTABLE:FILEPATH=${GIT_EXECUTABLE} - -DCTK_BUILD_QTDESIGNER_PLUGINS:BOOL=OFF + -DCTK_BUILD_QTDESIGNER_PLUGINS:BOOL=ON -DCTK_LIB_CommandLineModules/Backend/LocalProcess:BOOL=ON -DCTK_LIB_CommandLineModules/Frontend/QtGui:BOOL=ON -DCTK_LIB_PluginFramework:BOOL=ON -DCTK_LIB_DICOM/Widgets:BOOL=ON -DCTK_LIB_XNAT/Core:BOOL=ON -DCTK_PLUGIN_org.commontk.eventadmin:BOOL=ON -DCTK_PLUGIN_org.commontk.configadmin:BOOL=ON -DCTK_USE_GIT_PROTOCOL:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DPythonQt_URL:STRING=${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/PythonQt_fae23012.tar.gz ${${proj}_CUSTOM_CMAKE_ARGS} CMAKE_CACHE_ARGS ${ep_common_cache_args} ${${proj}_CUSTOM_CMAKE_CACHE_ARGS} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} ${${proj}_CUSTOM_CMAKE_CACHE_DEFAULT_ARGS} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(CTK_DIR ${binary_dir}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/QwtCMakeLists.txt b/CMakeExternals/QwtCMakeLists.txt index e738fcde35..50bd9c2805 100644 --- a/CMakeExternals/QwtCMakeLists.txt +++ b/CMakeExternals/QwtCMakeLists.txt @@ -1,264 +1,264 @@ cmake_minimum_required(VERSION 3.1) project(Qwt) set(${PROJECT_NAME}_MAJOR_VERSION 6) set(${PROJECT_NAME}_MINOR_VERSION 1) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) set(QWT_MOC_HEADERS # General qwt_dyngrid_layout.h qwt_magnifier.h qwt_panner.h qwt_picker.h qwt_text_label.h # QwtPlot qwt_abstract_legend.h qwt_legend.h qwt_legend_label.h qwt_plot.h qwt_plot_renderer.h qwt_plot_canvas.h qwt_plot_panner.h qwt_plot_picker.h qwt_plot_zoomer.h qwt_plot_magnifier.h qwt_sampling_thread.h qwt_scale_widget.h # QwtOpenGL qwt_plot_glcanvas.h # QwtWidgets qwt_abstract_slider.h qwt_abstract_scale.h qwt_analog_clock.h qwt_compass.h qwt_counter.h qwt_dial.h qwt_knob.h qwt_slider.h qwt_thermo.h qwt_wheel.h ) set(QWT_SOURCES # General qwt_abstract_scale_draw.cpp qwt_clipper.cpp qwt_color_map.cpp qwt_column_symbol.cpp qwt_date.cpp qwt_date_scale_draw.cpp qwt_date_scale_engine.cpp qwt_dyngrid_layout.cpp qwt_event_pattern.cpp qwt_graphic.cpp qwt_interval.cpp qwt_interval_symbol.cpp qwt_math.cpp qwt_magnifier.cpp qwt_null_paintdevice.cpp qwt_painter.cpp qwt_painter_command.cpp qwt_panner.cpp qwt_picker.cpp qwt_picker_machine.cpp qwt_pixel_matrix.cpp qwt_point_3d.cpp qwt_point_polar.cpp qwt_round_scale_draw.cpp qwt_scale_div.cpp qwt_scale_draw.cpp qwt_scale_map.cpp qwt_spline.cpp qwt_scale_engine.cpp qwt_symbol.cpp qwt_system_clock.cpp qwt_text_engine.cpp qwt_text_label.cpp qwt_text.cpp qwt_transform.cpp qwt_widget_overlay.cpp # QwtPlot qwt_curve_fitter.cpp qwt_abstract_legend.cpp qwt_legend.cpp qwt_legend_data.cpp qwt_legend_label.cpp qwt_plot.cpp qwt_plot_renderer.cpp qwt_plot_xml.cpp qwt_plot_axis.cpp qwt_plot_curve.cpp qwt_plot_dict.cpp qwt_plot_directpainter.cpp qwt_plot_grid.cpp qwt_plot_histogram.cpp qwt_plot_item.cpp qwt_plot_abstract_barchart.cpp qwt_plot_barchart.cpp qwt_plot_multi_barchart.cpp qwt_plot_intervalcurve.cpp qwt_plot_zoneitem.cpp qwt_plot_tradingcurve.cpp qwt_plot_spectrogram.cpp qwt_plot_spectrocurve.cpp qwt_plot_scaleitem.cpp qwt_plot_legenditem.cpp qwt_plot_seriesitem.cpp qwt_plot_shapeitem.cpp qwt_plot_marker.cpp qwt_plot_textlabel.cpp qwt_plot_layout.cpp qwt_plot_canvas.cpp qwt_plot_panner.cpp qwt_plot_rasteritem.cpp qwt_plot_picker.cpp qwt_plot_zoomer.cpp qwt_plot_magnifier.cpp qwt_plot_rescaler.cpp qwt_point_mapper.cpp qwt_raster_data.cpp qwt_matrix_raster_data.cpp qwt_sampling_thread.cpp qwt_series_data.cpp qwt_point_data.cpp qwt_scale_widget.cpp # QwtSvg qwt_plot_svgitem.cpp # QwtOpenGL qwt_plot_glcanvas.cpp # QwtWidgets qwt_abstract_slider.cpp qwt_abstract_scale.cpp qwt_arrow_button.cpp qwt_analog_clock.cpp qwt_compass.cpp qwt_compass_rose.cpp qwt_counter.cpp qwt_dial.cpp qwt_dial_needle.cpp qwt_knob.cpp qwt_slider.cpp qwt_thermo.cpp qwt_wheel.cpp ) set(_qwt_moc_headers ) foreach(_header ${QWT_MOC_HEADERS}) list(APPEND _qwt_moc_headers src/${_header}) endforeach() set(_qwt_sources ) foreach(_source ${QWT_SOURCES}) list(APPEND _qwt_sources src/${_source}) endforeach() find_package(Qt5Svg REQUIRED) find_package(Qt5OpenGL REQUIRED) find_package(Qt5PrintSupport REQUIRED) find_package(Qt5Concurrent REQUIRED) qt5_wrap_cpp(_qwt_sources ${_qwt_moc_headers}) add_library(qwt SHARED ${_qwt_sources}) target_link_libraries(qwt PUBLIC Qt5::Svg Qt5::OpenGL Qt5::PrintSupport Qt5::Concurrent) target_compile_definitions(qwt PUBLIC QWT_DLL PRIVATE QWT_MAKEDLL) set_target_properties(qwt PROPERTIES SOVERSION ${${PROJECT_NAME}_VERSION} ) # Build the designer plug-in -option(QWT_BUILD_DESIGNER_PLUGIN "Build the Qt Designer plugin" OFF) +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/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt index 2df1db81db..c4254f4df3 100644 --- a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt +++ b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt @@ -1,98 +1,99 @@ option(BUILD_BasicImageProcessingMiniApps "Build commandline tools for Basic Image Processing" OFF) if(BUILD_BasicImageProcessingMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( basicImageProcessingMiniApps FileConverter^^MitkCore ImageTypeConverter^^MitkCore + RectifyImage^^MitkCore SingleImageArithmetic^^MitkCore_MitkBasicImageProcessing TwoImageArithmetic^^MitkCore_MitkBasicImageProcessing ImageAndValueArithmetic^^MitkCore_MitkBasicImageProcessing MaskRangeBasedFiltering^^MitkCore_MitkBasicImageProcessing MaskOutlierFiltering^^MitkCore_MitkBasicImageProcessing ResampleImage^^MitkCore_MitkBasicImageProcessing ResampleMask^^MitkCore_MitkBasicImageProcessing LaplacianOfGaussian^^MitkCore_MitkBasicImageProcessing MultiResolutionPyramid^^MitkCore_MitkBasicImageProcessing ForwardWavelet^^MitkCore_MitkBasicImageProcessing ) foreach(basicImageProcessingMiniApp ${basicImageProcessingMiniApps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${basicImageProcessingMiniApp}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/BasicImageProcessing/MiniApps/RectifyImage.cpp b/Modules/BasicImageProcessing/MiniApps/RectifyImage.cpp new file mode 100644 index 0000000000..664c13adb0 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/RectifyImage.cpp @@ -0,0 +1,194 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include +#include + +template +void RectifyImage(mitk::Image::Pointer inputImage, mitk::Image::Pointer outputImage) +{ + mitk::ImagePixelReadAccessor pixelReadAccess(inputImage); + mitk::ImagePixelWriteAccessor pixelWriteAccess(outputImage); + + const auto DEPTH = static_cast(outputImage->GetDimension(2)); + const auto HEIGHT = static_cast(outputImage->GetDimension(1)); + const auto WIDTH = static_cast(outputImage->GetDimension(0)); + + auto geometry = outputImage->GetGeometry(); + itk::Index<3> index; + mitk::Point3D worldCoords; + + for (index[2] = 0; index[2] < DEPTH; ++index[2]) + { + for (index[1] = 0; index[1] < HEIGHT; ++index[1]) + { + for (index[0] = 0; index[0] < WIDTH; ++index[0]) + { + geometry->IndexToWorld(index, worldCoords); + pixelWriteAccess.SetPixelByIndex(index, pixelReadAccess.GetPixelByWorldCoordinates(worldCoords)); + } + } + } +} + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Rectify Image"); + parser.setCategory("Basic Image Processing"); + parser.setDescription("Resample image based on standard world to index transform"); + parser.setContributor("German Cancer Research Center (DKFZ)"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("input", "i", mitkCommandLineParser::Image, "Input Image", "Path to input image", us::Any(), false); + parser.addArgument("output", "o", mitkCommandLineParser::Image, "Output Image", "Path to output image", us::Any(), false); + + auto parsedArgs = parser.parseArguments(argc, argv); + + if (2 != parsedArgs.size() || 0 == parsedArgs.count("input") || 0 == parsedArgs.count("output")) + return EXIT_FAILURE; + + auto inputImagePath = us::any_value_to_string(parsedArgs["input"]); + mitk::Image::Pointer inputImage; + + try + { + inputImage = dynamic_cast(mitk::IOUtil::Load(inputImagePath)[0].GetPointer()); + } + catch (const mitk::Exception&) + { + return EXIT_FAILURE; + } + + if (3 != inputImage->GetDimension()) + { + MITK_ERROR << "Only 3-d images are supported."; + return EXIT_FAILURE; + } + + auto inputGeometry = inputImage->GetGeometry(); + + mitk::Point3D minInputIndex; + mitk::FillVector3D(minInputIndex, 0.0, 0.0, 0.0); + + mitk::Point3D minInputIndexInWorld; + inputGeometry->IndexToWorld(minInputIndex, minInputIndexInWorld); + + mitk::Point3D maxInputIndex; + for (int i = 0; i < 3; ++i) + maxInputIndex[i] = inputGeometry->GetExtent(i) - 1; + + mitk::Point3D maxInputIndexInWorld; + inputGeometry->IndexToWorld(maxInputIndex, maxInputIndexInWorld); + + mitk::Point3D minOutputIndexInWorld; + for (int i = 0; i < 3; ++i) + minOutputIndexInWorld[i] = std::min(minInputIndexInWorld[i], maxInputIndexInWorld[i]); + + mitk::Point3D maxOutputIndexInWorld; + for (int i = 0; i < 3; ++i) + maxOutputIndexInWorld[i] = std::max(minInputIndexInWorld[i], maxInputIndexInWorld[i]); + + mitk::Vector3D spacing = inputGeometry->GetSpacing(); + auto transform = inputGeometry->GetIndexToWorldTransform()->Clone(); + auto matrix = transform->GetMatrix(); + + for (int i = 0; i < 3; ++i) + { + for (int j = 0; j < 3; ++j) + { + matrix[i][j] = std::abs(matrix[i][j]) / spacing[j]; + } + } + + transform->SetMatrix(matrix); + spacing = transform->TransformVector(spacing); + + mitk::Vector3D outputExtent = (maxOutputIndexInWorld - minOutputIndexInWorld + spacing); + for (int i = 0; i < 3; ++i) + outputExtent[i] /= spacing[i]; + + mitk::Point3D origin = minOutputIndexInWorld; + + mitk::Vector3D right; + mitk::FillVector3D(right, outputExtent[0], 0.0, 0.0); + + mitk::Vector3D down; + mitk::FillVector3D(down, 0.0, outputExtent[1], 0.0); + + auto planeGeometry = mitk::PlaneGeometry::New(); + planeGeometry->InitializeStandardPlane(right, down, &spacing); + planeGeometry->SetOrigin(origin); + planeGeometry->SetImageGeometry(true); + + auto slicedGeometry = mitk::SlicedGeometry3D::New(); + slicedGeometry->InitializeEvenlySpaced(planeGeometry, static_cast(outputExtent[2])); + + auto outputGeometry = mitk::ProportionalTimeGeometry::New(); + outputGeometry->SetTimeStepGeometry(slicedGeometry, 0); + + auto pixelType = inputImage->GetPixelType(); + + auto outputImage = mitk::Image::New(); + outputImage->Initialize(pixelType, *outputGeometry); + + try + { + switch (pixelType.GetComponentType()) + { + case itk::ImageIOBase::CHAR: + RectifyImage(inputImage, outputImage); + break; + + case itk::ImageIOBase::UCHAR: + RectifyImage(inputImage, outputImage); + break; + + case itk::ImageIOBase::SHORT: + RectifyImage(inputImage, outputImage); + break; + + case itk::ImageIOBase::USHORT: + RectifyImage(inputImage, outputImage); + break; + + default: + MITK_ERROR << "Pixel type is not supported."; + return EXIT_FAILURE; + } + } + catch (const mitk::Exception &e) + { + MITK_ERROR << e.GetDescription(); + return EXIT_FAILURE; + } + + auto outputImagePath = us::any_value_to_string(parsedArgs["output"]); + + try + { + mitk::IOUtil::Save(outputImage, outputImagePath); + } + catch (const mitk::Exception &) + { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp index a6f23cf779..643fd7dc94 100644 --- a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp +++ b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp @@ -1,220 +1,217 @@ /*============================================================================ 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 __mitkDICOMPMIO__cpp #define __mitkDICOMPMIO__cpp #include "mitkDICOMPMIO.h" #include "mitkDICOMPMIOMimeTypes.h" #include #include #include #include #include #include #include #include #include #include "mitkParamapPresetsParser.h" // us #include #include // model fit parameters #include "mitkModelFitConstants.h" namespace mitk { DICOMPMIO::DICOMPMIO() : AbstractFileIO(Image::GetStaticNameOfClass(), mitk::MitkDICOMPMIOMimeTypes::DICOMPM_MIMETYPE_NAME(), "DICOM PM") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel DICOMPMIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const Image *PMinput = static_cast(this->GetInput()); if (PMinput) { auto modalityProperty = PMinput->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str()); if (modalityProperty.IsNotNull()) { std::string modality = modalityProperty->GetValueAsString(); if (modality == "PM") { return Supported; } else return Unsupported; } else return Unsupported; } else return Unsupported; } void DICOMPMIO::Write() { ValidateOutputLocation(); mitk::LocaleSwitch localeSwitch("C"); LocalFile localFile(this); const std::string path = localFile.GetFileName(); auto PMinput = dynamic_cast(this->GetInput()); if (PMinput == nullptr) mitkThrow() << "Cannot write non-image data"; // Get DICOM information from referenced image vector> dcmDatasetsSourceImage; std::unique_ptr readFileFormat(new DcmFileFormat()); try { // Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the // property list mitk::StringLookupTableProperty::Pointer filesProp = dynamic_cast(PMinput->GetProperty("referenceFiles").GetPointer()); if (filesProp.IsNull()) { mitkThrow() << "No property with dicom file path."; return; } // returns a list of all referenced files StringLookupTable filesLut = filesProp->GetValue(); const StringLookupTable::LookupTableType &lookUpTableMap = filesLut.GetLookupTable(); for (auto it : lookUpTableMap) { const char *fileName = (it.second).c_str(); if (readFileFormat->loadFile(fileName, EXS_Unknown).good()) { std::unique_ptr readDCMDataset(readFileFormat->getAndRemoveDataset()); dcmDatasetsSourceImage.push_back(std::move(readDCMDataset)); } } } catch (const std::exception &e) { MITK_ERROR << "An error occurred while getting the dicom information: " << e.what() << endl; return; } mitk::Image *mitkPMImage = const_cast(PMinput); // Cast input PMinput to itk image ImageToItk::Pointer PMimageToItkFilter = ImageToItk::New(); PMimageToItkFilter->SetInput(mitkPMImage); // Cast from original itk type to dcmqi input itk image type typedef itk::CastImageFilter castItkImageFilterType; castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New(); castFilter->SetInput(PMimageToItkFilter->GetOutput()); castFilter->Update(); PMitkInternalImageType::Pointer itkParamapImage = castFilter->GetOutput(); // Create PM meta information const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFilePM(); // Convert itk PM images to dicom image MITK_INFO << "Writing PM image: " << path << std::endl; try { // convert from unique to raw pointer vector rawVecDataset; for ( const auto& dcmDataSet : dcmDatasetsSourceImage ) { rawVecDataset.push_back( dcmDataSet.get() ); } std::unique_ptr PMconverter(new dcmqi::ParaMapConverter()); std::unique_ptr PMresult (PMconverter->itkimage2paramap(itkParamapImage, rawVecDataset, tmpMetaInfoFile)); // Write dicom file DcmFileFormat dcmFileFormat(PMresult.get()); std::string filePath = path.substr(0, path.find_last_of(".")); filePath = filePath + ".dcm"; dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit); } catch (const std::exception &e) { MITK_ERROR << "An error occurred during writing the DICOM Paramap: " << e.what() << endl; return; } } const std::string mitk::DICOMPMIO::CreateMetaDataJsonFilePM() const { const mitk::Image *PMimage = dynamic_cast(this->GetInput()); dcmqi::JSONParametricMapMetaInformationHandler PMhandler; // Get Metadata from modelFitConstants std::string parameterName; PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), parameterName); std::string modelName; PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), modelName); mitk::ParamapPresetsParser* pmPresets = mitk::ParamapPresetsParser::New(); // Here the mitkParamapPresets.xml file containing the Coding Schmeme Designator and Code Value are parsed and the relevant values extracted pmPresets->LoadPreset(); auto pmType_parameterName = pmPresets->GetType(parameterName); auto pmType_modelName = pmPresets->GetType(modelName); // Pass codes to Paramap Converter PMhandler.setDerivedPixelContrast("TCS"); PMhandler.setFrameLaterality("U"); PMhandler.setQuantityValueCode(pmType_parameterName.codeValue, pmType_parameterName.codeScheme, parameterName); PMhandler.setMeasurementMethodCode(pmType_modelName.codeValue, pmType_modelName.codeScheme, modelName); PMhandler.setMeasurementUnitsCode("/min", "UCUM", "/m"); PMhandler.setSeriesNumber("1"); PMhandler.setInstanceNumber("1"); PMhandler.setDerivationCode("129104", "DCM", "Perfusion image analysis"); PMhandler.setRealWorldValueSlope("1"); - - return PMhandler.getJSONOutputAsString(); - } std::vector DICOMPMIO::Read() { mitk::LocaleSwitch localeSwitch("C"); std::vector result; return result; } IFileIO::ConfidenceLevel DICOMPMIO::GetReaderConfidenceLevel() const { return Unsupported; } DICOMPMIO *DICOMPMIO::IOClone() const { return new DICOMPMIO(*this); } } // namespace #endif //__mitkDICOMPMIO__cpp diff --git a/Modules/MatchPointRegistration/Helper/mitkMaskedAlgorithmHelper.cpp b/Modules/MatchPointRegistration/Helper/mitkMaskedAlgorithmHelper.cpp index 0b3551dc41..97736cc969 100644 --- a/Modules/MatchPointRegistration/Helper/mitkMaskedAlgorithmHelper.cpp +++ b/Modules/MatchPointRegistration/Helper/mitkMaskedAlgorithmHelper.cpp @@ -1,175 +1,183 @@ /*============================================================================ 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 "mitkMaskedAlgorithmHelper.h" #include // Mitk #include // MatchPoint #include "mapMaskedRegistrationAlgorithmInterface.h" #include namespace mitk { MaskedAlgorithmHelper::MaskedAlgorithmHelper(map::algorithm::RegistrationAlgorithmBase* algorithm) : m_AlgorithmBase(algorithm) { } bool MaskedAlgorithmHelper::HasMaskedRegistrationAlgorithmInterface(const map::algorithm::RegistrationAlgorithmBase* algorithm) { using MaskedInterface2D = const ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<2, 2>; using MaskedInterface3D = const ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3>; return dynamic_cast(algorithm) != nullptr && dynamic_cast(algorithm) != nullptr; }; bool MaskedAlgorithmHelper:: CheckSupport(const mitk::Image* movingMask, const mitk::Image* targetMask) const { if (! m_AlgorithmBase) mapDefaultExceptionStaticMacro(<< "Error, cannot check data. Helper has no algorithm defined."); unsigned int movingDim = m_AlgorithmBase->getMovingDimensions(); unsigned int targetDim = m_AlgorithmBase->getTargetDimensions(); bool result = movingDim == targetDim; if ( movingMask) { result = result && (movingMask->GetDimension() == movingDim); if (movingDim == 2) { typedef itk::Image MaskImageType; mitk::PixelType maskPixelType = mitk::MakePixelType(); result = result && (maskPixelType == movingMask->GetPixelType()); } else if (movingDim == 3) { typedef itk::Image MaskImageType; mitk::PixelType maskPixelType = mitk::MakePixelType(); result = result && (maskPixelType == movingMask->GetPixelType()); } } if ( targetMask) { result = result && (targetMask->GetDimension() == targetDim); if (movingDim == 2) { typedef itk::Image MaskImageType; mitk::PixelType maskPixelType = mitk::MakePixelType(); result = result && (maskPixelType == targetMask->GetPixelType()); } else if (movingDim == 3) { typedef itk::Image MaskImageType; mitk::PixelType maskPixelType = mitk::MakePixelType(); result = result && (maskPixelType == targetMask->GetPixelType()); } } if (movingDim == 2) { typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<2, 2> MaskedInterface; const MaskedInterface* pMaskedReg = dynamic_cast(m_AlgorithmBase.GetPointer()); result = result && pMaskedReg; } else if (movingDim == 3) { typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskedInterface; const MaskedInterface* pMaskedReg = dynamic_cast(m_AlgorithmBase.GetPointer()); result = result && pMaskedReg; } else { result = false; } return result; }; bool MaskedAlgorithmHelper::SetMasks(const mitk::Image* movingMask, const mitk::Image* targetMask) { if (! m_AlgorithmBase) mapDefaultExceptionStaticMacro(<< "Error, cannot set data. Helper has no algorithm defined."); if (! CheckSupport(movingMask, targetMask)) return false; unsigned int movingDim = m_AlgorithmBase->getMovingDimensions(); unsigned int targetDim = m_AlgorithmBase->getTargetDimensions(); if (movingDim!=targetDim) return false; if (movingDim == 2) { return DoSetMasks<2,2>(movingMask, targetMask); } else if (movingDim == 3) { return DoSetMasks<3,3>(movingMask, targetMask); } return false; }; template bool MaskedAlgorithmHelper::DoSetMasks(const mitk::Image* movingMask, const mitk::Image* targetMask) { typedef itk::SpatialObject MovingSpatialType; typedef itk::SpatialObject TargetSpatialType; typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface MaskedRegInterface; MaskedRegInterface* pAlg = dynamic_cast(m_AlgorithmBase.GetPointer()); if (!pAlg) return false; if (movingMask) { AccessFixedTypeByItk(movingMask, DoConvertMask, (MaskPixelType), (VImageDimension1)); typename MovingSpatialType::Pointer movingSpatial = dynamic_cast(m_convertResult.GetPointer()); if (! movingSpatial) mapDefaultExceptionStaticMacro(<< "Error, cannot convert moving mask."); pAlg->setMovingMask(movingSpatial); } + else + { + pAlg->setMovingMask(nullptr); + } if (targetMask) { AccessFixedTypeByItk(targetMask, DoConvertMask, (MaskPixelType), (VImageDimension2)); typename TargetSpatialType::Pointer targetSpatial = dynamic_cast(m_convertResult.GetPointer()); if (! targetSpatial) mapDefaultExceptionStaticMacro(<< "Error, cannot convert moving mask."); pAlg->setTargetMask(targetSpatial); } + else + { + pAlg->setTargetMask(nullptr); + } return true; } template void MaskedAlgorithmHelper::DoConvertMask(const itk::Image* mask) { typedef itk::ImageMaskSpatialObject SpatialType; typename SpatialType::Pointer spatial = SpatialType::New(); spatial->SetImage(mask); m_convertResult = spatial.GetPointer(); } } diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegIOMimeTypes.cpp b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegIOMimeTypes.cpp index 33b7dfdc43..5abb559208 100644 --- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegIOMimeTypes.cpp +++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegIOMimeTypes.cpp @@ -1,125 +1,134 @@ /*============================================================================ 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 "mitkDICOMSegIOMimeTypes.h" #include "mitkIOMimeTypes.h" +#include + #include #include #include #include #include namespace mitk { std::vector MitkDICOMSEGIOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(DICOMSEG_MIMETYPE().Clone()); return mimeTypes; } MitkDICOMSEGIOMimeTypes::MitkDICOMSEGMimeType::MitkDICOMSEGMimeType() : CustomMimeType(DICOMSEG_MIMETYPE_NAME()) { this->AddExtension("dcm"); this->SetCategory(IOMimeTypes::CATEGORY_IMAGES()); this->SetComment("DICOM SEG"); } bool MitkDICOMSEGIOMimeTypes::MitkDICOMSEGMimeType::AppliesTo(const std::string &path) const { - std::ifstream myfile; - myfile.open(path, std::ios::binary); - // myfile.seekg (128); - char *buffer = new char[128]; - myfile.read(buffer, 128); - myfile.read(buffer, 4); - if (std::string(buffer).compare("DICM") != 0) - { - delete[] buffer; - return false; - } - delete[] buffer; - bool canRead(CustomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } // end fix for bug 18572 + const std::size_t offset = 128; + const std::size_t bufferSize = 4; + + std::ifstream myfile(path, std::ifstream::binary); + + if (!myfile.is_open()) + return false; + + myfile.seekg(0, std::ifstream::end); + const auto fileSize = static_cast(myfile.tellg()); + + if (fileSize < offset + bufferSize) + return false; + + myfile.seekg(offset); + std::array buffer; + myfile.read(buffer.data(), bufferSize); + + if (0 != std::string(buffer.data(), bufferSize).compare("DICM")) + return false; DcmFileFormat dcmFileFormat; OFCondition status = dcmFileFormat.loadFile(path.c_str()); if (status.bad()) { canRead = false; } if (!canRead) { return canRead; } OFString modality; OFString sopClassUID; if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good() && dcmFileFormat.getDataset()->findAndGetOFString(DCM_SOPClassUID, sopClassUID).good()) { if (modality.compare("SEG") == 0) {//atm we could read SegmentationStorage files. Other storage classes with "SEG" modality, e.g. SurfaceSegmentationStorage (1.2.840.10008.5.1.4.1.1.66.5), are not supported yet. if (sopClassUID.compare("1.2.840.10008.5.1.4.1.1.66.4") == 0) { canRead = true; } else { canRead = false; } } else { canRead = false; } } return canRead; } MitkDICOMSEGIOMimeTypes::MitkDICOMSEGMimeType *MitkDICOMSEGIOMimeTypes::MitkDICOMSEGMimeType::Clone() const { return new MitkDICOMSEGMimeType(*this); } MitkDICOMSEGIOMimeTypes::MitkDICOMSEGMimeType MitkDICOMSEGIOMimeTypes::DICOMSEG_MIMETYPE() { return MitkDICOMSEGMimeType(); } std::string MitkDICOMSEGIOMimeTypes::DICOMSEG_MIMETYPE_NAME() { // create a unique and sensible name for this mime type return IOMimeTypes::DEFAULT_BASE_NAME() + ".image.dicom.seg"; } } diff --git a/Modules/Pharmacokinetics/include/mitkConcentrationCurveGenerator.h b/Modules/Pharmacokinetics/include/mitkConcentrationCurveGenerator.h index 80c68c0a6b..79b0ac4782 100644 --- a/Modules/Pharmacokinetics/include/mitkConcentrationCurveGenerator.h +++ b/Modules/Pharmacokinetics/include/mitkConcentrationCurveGenerator.h @@ -1,142 +1,157 @@ /*============================================================================ 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 CONCENTRATIONCURVEGENERATOR_H #define CONCENTRATIONCURVEGENERATOR_H #include #include #include "mitkConvertToConcentrationAbsoluteFunctor.h" #include "mitkConvertToConcentrationRelativeFunctor.h" #include "MitkPharmacokineticsExports.h" namespace mitk { /** \class ConcentrationCurveGenerator * \brief Converts a given 4D mitk::Image with MR signal values into a 4D mitk::Image with corresponding contrast agent concentration values * * From a given 4D image, the Generator takes the 3D image of the first time point as baseline image. It then loops over all time steps, casts * the current 3D image to itk and passes it to the ConvertToconcentrationFunctor. The returned 3D image has now values of concentration type and is stored at its timepoint * in the return image. */ class MITKPHARMACOKINETICS_EXPORT ConcentrationCurveGenerator : public itk::Object { public: mitkClassMacroItkParent(ConcentrationCurveGenerator, itk::Object); itkNewMacro(Self); //typedef itk::Image ImageType; typedef itk::Image ConvertedImageType; /** Getter and Setter for 4D mitk::Image*/ itkSetConstObjectMacro(DynamicImage,Image); itkGetConstObjectMacro(DynamicImage,Image); /** Parameters Relevant for conversion Calculation; Have to be Set externally (Sequence Dependend)*/ itkSetMacro(RelaxationTime, double); itkGetConstReferenceMacro(RelaxationTime, double); itkSetMacro(Relaxivity, double); itkGetConstReferenceMacro(Relaxivity, double); itkSetMacro(RecoveryTime, double); itkGetConstReferenceMacro(RecoveryTime, double); itkSetMacro(FlipAngle, double); itkGetConstReferenceMacro(FlipAngle, double); itkSetMacro(Factor, double); itkGetConstReferenceMacro(Factor, double); /** Getter and Setter for T10 Map image*/ itkSetConstObjectMacro(T10Image,Image); itkGetConstObjectMacro(T10Image,Image); itkSetMacro(T2Factor, double); itkGetConstReferenceMacro(T2Factor, double); itkSetMacro(T2EchoTime, double); itkGetConstReferenceMacro(T2EchoTime, double); + /** @brief Calls Convert and returns the 4D mitk::image in Concentration units*/ + itkSetMacro(BaselineStartTimeStep, unsigned int); + itkGetConstReferenceMacro(BaselineStartTimeStep, unsigned int); + + itkSetMacro(BaselineEndTimeStep, unsigned int); + itkGetConstReferenceMacro(BaselineEndTimeStep, unsigned int); + itkSetMacro(isTurboFlashSequence,bool); itkGetConstReferenceMacro(isTurboFlashSequence,bool); itkSetMacro(AbsoluteSignalEnhancement,bool); itkGetConstReferenceMacro(AbsoluteSignalEnhancement,bool); itkSetMacro(RelativeSignalEnhancement,bool); itkGetConstReferenceMacro(RelativeSignalEnhancement,bool); itkSetMacro(UsingT1Map,bool); itkGetConstReferenceMacro(UsingT1Map,bool); itkSetMacro(isT2weightedImage,bool); itkGetConstReferenceMacro(isT2weightedImage,bool); Image::Pointer GetConvertedImage(); protected: ConcentrationCurveGenerator(); ~ConcentrationCurveGenerator() override; - template - mitk::Image::Pointer convertToConcentration(const mitk::Image* inputImage, const mitk::Image* baselineImage); + template + mitk::Image::Pointer convertToConcentration(const itk::Image *itkInputImage, const itk::Image *itkBaselineImage); /** Calls ConvertToconcentrationFunctor for passed 3D itk::image*/ mitk::Image::Pointer ConvertSignalToConcentrationCurve(const mitk::Image* inputImage, const mitk::Image* baselineImage); /** @brief Takes the 3D image of the first timepoint to set as baseline image*/ void PrepareBaselineImage(); + template + void CalculateAverageBaselineImage(const itk::Image *itkBaselineImage); + /** @brief loops over all timepoints, casts the current timepoint 3D mitk::image to itk and passes it to ConvertSignalToConcentrationCurve */ virtual void Convert(); private: Image::ConstPointer m_DynamicImage; Image::ConstPointer m_BaselineImage; Image::ConstPointer m_T10Image; - + Image::Pointer m_ConvertSignalToConcentrationCurve_OutputImage; Image::Pointer m_ConvertedImage; bool m_isT2weightedImage; bool m_isTurboFlashSequence; bool m_AbsoluteSignalEnhancement; bool m_RelativeSignalEnhancement; bool m_UsingT1Map; double m_Factor; //=Repetition Time TR double m_RecoveryTime; //= pre-CA T1 time double m_RelaxationTime; //= contrast agent relaxivity double m_Relaxivity; double m_FlipAngle; double m_T2Factor; double m_T2EchoTime; + // The baseline image is averaged from the signal within time step range [m_BaselineStartTimeStep, m_BaselineEndTimeStep]. + // m_BaselineStartTimeStep is the first time frame, that is included into the baseline averaging (starting with 0). + unsigned int m_BaselineStartTimeStep; + // m_BaselinStopTimeStep is the last time frame, that is included into the baseline averaging. + unsigned int m_BaselineEndTimeStep; }; } #endif // CONCENTRATIONCURVEGENERATOR_H diff --git a/Modules/Pharmacokinetics/src/Common/mitkConcentrationCurveGenerator.cpp b/Modules/Pharmacokinetics/src/Common/mitkConcentrationCurveGenerator.cpp index 49f5081344..f19254394b 100644 --- a/Modules/Pharmacokinetics/src/Common/mitkConcentrationCurveGenerator.cpp +++ b/Modules/Pharmacokinetics/src/Common/mitkConcentrationCurveGenerator.cpp @@ -1,264 +1,324 @@ /*============================================================================ 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 "mitkConcentrationCurveGenerator.h" #include "mitkConvertToConcentrationTurboFlashFunctor.h" #include "mitkConvertT2ConcentrationFunctor.h" #include "mitkConvertToConcentrationViaT1Functor.h" #include "mitkImageTimeSelector.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkModelBase.h" #include "mitkExtractTimeGrid.h" #include "mitkArbitraryTimeGeometry.h" +#include "itkNaryAddImageFilter.h" +#include "mitkImageAccessByItk.h" #include "itkImageIOBase.h" - #include "itkBinaryFunctorImageFilter.h" #include "itkTernaryFunctorImageFilter.h" +#include +#include "itkMeanProjectionImageFilter.h" mitk::ConcentrationCurveGenerator::ConcentrationCurveGenerator() : m_isT2weightedImage(false), m_isTurboFlashSequence(false), m_AbsoluteSignalEnhancement(false), m_RelativeSignalEnhancement(0.0), m_UsingT1Map(false), m_Factor(0.0), m_RecoveryTime(0.0), m_RelaxationTime(0.0), m_Relaxivity(0.0), m_FlipAngle(0.0), m_T2Factor(0.0), m_T2EchoTime(0.0) { } mitk::ConcentrationCurveGenerator::~ConcentrationCurveGenerator() { } mitk::Image::Pointer mitk::ConcentrationCurveGenerator::GetConvertedImage() { if(this->m_DynamicImage.IsNull()) { itkExceptionMacro( << "Dynamic Image not set!"); } else { Convert(); } return m_ConvertedImage; } void mitk::ConcentrationCurveGenerator::Convert() { mitk::Image::Pointer tempImage = mitk::Image::New(); mitk::PixelType pixeltype = mitk::MakeScalarPixelType(); tempImage->Initialize(pixeltype,*this->m_DynamicImage->GetTimeGeometry()); mitk::TimeGeometry::Pointer timeGeometry = (this->m_DynamicImage->GetTimeGeometry())->Clone(); tempImage->SetTimeGeometry(timeGeometry); - PrepareBaselineImage(); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_DynamicImage); for(unsigned int i = 0; i< this->m_DynamicImage->GetTimeSteps(); ++i) { imageTimeSelector->SetTimeNr(i); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer mitkInputImage = imageTimeSelector->GetOutput(); mitk::Image::Pointer outputImage = mitk::Image::New(); outputImage = ConvertSignalToConcentrationCurve(mitkInputImage,this->m_BaselineImage); mitk::ImageReadAccessor accessor(outputImage); tempImage->SetVolume(accessor.GetData(), i); } this->m_ConvertedImage = tempImage; } void mitk::ConcentrationCurveGenerator::PrepareBaselineImage() { - mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); - imageTimeSelector->SetInput(this->m_DynamicImage); - imageTimeSelector->SetTimeNr(0); - imageTimeSelector->UpdateLargestPossibleRegion(); - - this->m_BaselineImage = imageTimeSelector->GetOutput(); - -} - -mitk::Image::Pointer mitk::ConcentrationCurveGenerator::ConvertSignalToConcentrationCurve(const mitk::Image* inputImage, const mitk::Image* baselineImage) -{ - mitk::PixelType m_PixelType = inputImage->GetPixelType(); - mitk::Image::Pointer outputImage; - - if(inputImage->GetPixelType().GetComponentType() != baselineImage->GetPixelType().GetComponentType()) - { - mitkThrow() << "Input Image and Baseline Image have different Pixel Types. Data not supported"; - } - - if(m_PixelType.GetComponentType() == itk::ImageIOBase::USHORT) - { - outputImage = convertToConcentration(inputImage, baselineImage); - } - else if(m_PixelType.GetComponentType() == itk::ImageIOBase::UINT) - { - outputImage = convertToConcentration(inputImage, baselineImage); - } - else if(m_PixelType.GetComponentType() == itk::ImageIOBase::INT) - { - outputImage = convertToConcentration(inputImage, baselineImage); - } - else if(m_PixelType.GetComponentType() == itk::ImageIOBase::SHORT) + mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); + imageTimeSelector->SetInput(this->m_DynamicImage); + imageTimeSelector->SetTimeNr(0); + imageTimeSelector->UpdateLargestPossibleRegion(); + mitk::Image::Pointer baselineImage; + baselineImage = imageTimeSelector->GetOutput(); + + if (m_BaselineStartTimeStep == m_BaselineEndTimeStep) + { + this->m_BaselineImage = imageTimeSelector->GetOutput(); + } + else + { + try { - outputImage = convertToConcentration(inputImage, baselineImage); + AccessFixedDimensionByItk(this->m_DynamicImage, mitk::ConcentrationCurveGenerator::CalculateAverageBaselineImage, 4); } - else if(m_PixelType.GetComponentType() == itk::ImageIOBase::DOUBLE) + catch (itk::ExceptionObject & err) { - outputImage = convertToConcentration(inputImage, baselineImage); + std::cerr << "ExceptionObject in ConcentrationCurveGenerator::CalculateAverageBaselineImage caught!" << std::endl; + std::cerr << err << std::endl; } - else if(m_PixelType.GetComponentType() == itk::ImageIOBase::FLOAT) - { - outputImage = convertToConcentration(inputImage, baselineImage); - } - else - { - mitkThrow() << "PixelType is "< +void mitk::ConcentrationCurveGenerator::CalculateAverageBaselineImage(const itk::Image *itkBaselineImage) +{ + if (itkBaselineImage == NULL) + { + mitkThrow() << "Error in ConcentrationCurveGenerator::CalculateAverageBaselineImage. Input image is NULL."; + } + if (m_BaselineStartTimeStep > m_BaselineEndTimeStep) + { + mitkThrow() << "Error in ConcentrationCurveGenerator::CalculateAverageBaselineImage. End time point is before start time point."; + } + + typedef itk::Image TPixel4DImageType; + typedef itk::Image Double3DImageType; + typedef itk::Image Double4DImageType; + typedef itk::ExtractImageFilter ExtractImageFilterType; + typedef itk::ExtractImageFilter Extract3DImageFilterType; + typedef itk::MeanProjectionImageFilter MeanProjectionImageFilterType; + + typename MeanProjectionImageFilterType::Pointer MeanProjectionImageFilter = MeanProjectionImageFilterType::New(); + typename Extract3DImageFilterType::Pointer Extract3DImageFilter = Extract3DImageFilterType::New(); + typename TPixel4DImageType::RegionType region_input = itkBaselineImage->GetLargestPossibleRegion(); + + if (m_BaselineEndTimeStep > region_input.GetSize()[3]) + { + mitkThrow() << "Error in ConcentrationCurveGenerator::CalculateAverageBaselineImage. End time point is larger than total number of time points."; + } + + typename ExtractImageFilterType::Pointer ExtractFilter = ExtractImageFilterType::New(); + typename TPixel4DImageType::Pointer baselineTimeFrameImage = TPixel4DImageType::New(); + typename TPixel4DImageType::RegionType extractionRegion; + typename TPixel4DImageType::SizeType size_input_aux = region_input.GetSize(); + size_input_aux[3] = m_BaselineEndTimeStep - m_BaselineStartTimeStep + 1; + typename TPixel4DImageType::IndexType start_input_aux = region_input.GetIndex(); + start_input_aux[3] = m_BaselineStartTimeStep; + extractionRegion.SetSize(size_input_aux); + extractionRegion.SetIndex(start_input_aux); + ExtractFilter->SetExtractionRegion(extractionRegion); + ExtractFilter->SetInput(itkBaselineImage); + ExtractFilter->SetDirectionCollapseToSubmatrix(); + try + { + ExtractFilter->Update(); + } + catch (itk::ExceptionObject & err) + { + std::cerr << "ExceptionObject caught!" << std::endl; + std::cerr << err << std::endl; + } + baselineTimeFrameImage = ExtractFilter->GetOutput(); + MeanProjectionImageFilter->SetProjectionDimension(3); + MeanProjectionImageFilter->SetInput(baselineTimeFrameImage); + try + { + MeanProjectionImageFilter->Update(); + } + catch (itk::ExceptionObject & err) + { + std::cerr << "ExceptionObject caught!" << std::endl; + std::cerr << err << std::endl; + } + Extract3DImageFilter->SetInput(MeanProjectionImageFilter->GetOutput()); + size_input_aux[3] = 0; + start_input_aux[3] = 0; + extractionRegion.SetSize(size_input_aux); + extractionRegion.SetIndex(start_input_aux); + Extract3DImageFilter->SetExtractionRegion(extractionRegion); + Extract3DImageFilter->SetDirectionCollapseToSubmatrix(); + try + { + Extract3DImageFilter->Update(); + } + catch (itk::ExceptionObject & err) + { + std::cerr << "ExceptionObject caught!" << std::endl; + std::cerr << err << std::endl; + } + + Image::Pointer mitkBaselineImage = Image::New(); + CastToMitkImage(Extract3DImageFilter->GetOutput(), mitkBaselineImage); + this->m_BaselineImage = mitkBaselineImage; } -template -mitk::Image::Pointer mitk::ConcentrationCurveGenerator::convertToConcentration(const mitk::Image* inputImage, const mitk::Image* baselineImage) + +mitk::Image::Pointer mitk::ConcentrationCurveGenerator::ConvertSignalToConcentrationCurve(const mitk::Image* inputImage,const mitk::Image* baselineImage) { - typedef itk::Image InputImageType; + mitk::PixelType m_PixelType = inputImage->GetPixelType(); + AccessTwoImagesFixedDimensionByItk(inputImage, baselineImage, mitk::ConcentrationCurveGenerator::convertToConcentration, 3); + return m_ConvertSignalToConcentrationCurve_OutputImage; - typename InputImageType::Pointer itkInputImage = InputImageType::New(); - typename InputImageType::Pointer itkBaselineImage = InputImageType::New(); +} - mitk::CastToItkImage(inputImage, itkInputImage ); - mitk::CastToItkImage(baselineImage, itkBaselineImage ); +template +mitk::Image::Pointer mitk::ConcentrationCurveGenerator::convertToConcentration(const itk::Image *itkInputImage, const itk::Image *itkBaselineImage) +{ + typedef itk::Image InputImageType; + typedef itk::Image BaselineImageType; - mitk::Image::Pointer outputImage; - if(this->m_isT2weightedImage) + if (this->m_isT2weightedImage) { - typedef mitk::ConvertT2ConcentrationFunctor ConversionFunctorT2Type; - typedef itk::BinaryFunctorImageFilter FilterT2Type; + typedef mitk::ConvertT2ConcentrationFunctor ConversionFunctorT2Type; + typedef itk::BinaryFunctorImageFilter FilterT2Type; + ConversionFunctorT2Type ConversionT2Functor; ConversionT2Functor.initialize(this->m_T2Factor, this->m_T2EchoTime); typename FilterT2Type::Pointer ConversionT2Filter = FilterT2Type::New(); ConversionT2Filter->SetFunctor(ConversionT2Functor); ConversionT2Filter->SetInput1(itkInputImage); ConversionT2Filter->SetInput2(itkBaselineImage); ConversionT2Filter->Update(); - outputImage = mitk::ImportItkImage(ConversionT2Filter->GetOutput())->Clone(); - } + m_ConvertSignalToConcentrationCurve_OutputImage = mitk::ImportItkImage(ConversionT2Filter->GetOutput())->Clone(); + } else { if(this->m_isTurboFlashSequence) { - typedef mitk::ConvertToConcentrationTurboFlashFunctor ConversionFunctorTurboFlashType; - typedef itk::BinaryFunctorImageFilter FilterTurboFlashType; + typedef mitk::ConvertToConcentrationTurboFlashFunctor ConversionFunctorTurboFlashType; + typedef itk::BinaryFunctorImageFilter FilterTurboFlashType; ConversionFunctorTurboFlashType ConversionTurboFlashFunctor; ConversionTurboFlashFunctor.initialize(this->m_RelaxationTime, this->m_Relaxivity, this->m_RecoveryTime); typename FilterTurboFlashType::Pointer ConversionTurboFlashFilter = FilterTurboFlashType::New(); ConversionTurboFlashFilter->SetFunctor(ConversionTurboFlashFunctor); ConversionTurboFlashFilter->SetInput1(itkInputImage); ConversionTurboFlashFilter->SetInput2(itkBaselineImage); ConversionTurboFlashFilter->Update(); - outputImage = mitk::ImportItkImage(ConversionTurboFlashFilter->GetOutput())->Clone(); + m_ConvertSignalToConcentrationCurve_OutputImage = mitk::ImportItkImage(ConversionTurboFlashFilter->GetOutput())->Clone(); } else if(this->m_UsingT1Map) { - typename InputImageType::Pointer itkT10Image = InputImageType::New(); + typename ConvertedImageType::Pointer itkT10Image = ConvertedImageType::New(); mitk::CastToItkImage(m_T10Image, itkT10Image); - typedef mitk::ConvertToConcentrationViaT1CalcFunctor ConvertToConcentrationViaT1CalcFunctorType; - typedef itk::TernaryFunctorImageFilter FilterT1MapType; + typedef mitk::ConvertToConcentrationViaT1CalcFunctor ConvertToConcentrationViaT1CalcFunctorType; + typedef itk::TernaryFunctorImageFilter FilterT1MapType; ConvertToConcentrationViaT1CalcFunctorType ConversionT1MapFunctor; ConversionT1MapFunctor.initialize(this->m_Relaxivity, this->m_RecoveryTime, this->m_FlipAngle); typename FilterT1MapType::Pointer ConversionT1MapFilter = FilterT1MapType::New(); ConversionT1MapFilter->SetFunctor(ConversionT1MapFunctor); ConversionT1MapFilter->SetInput1(itkInputImage); ConversionT1MapFilter->SetInput2(itkBaselineImage); ConversionT1MapFilter->SetInput3(itkT10Image); ConversionT1MapFilter->Update(); - outputImage = mitk::ImportItkImage(ConversionT1MapFilter->GetOutput())->Clone(); + m_ConvertSignalToConcentrationCurve_OutputImage = mitk::ImportItkImage(ConversionT1MapFilter->GetOutput())->Clone(); } else if(this->m_AbsoluteSignalEnhancement) { - typedef mitk::ConvertToConcentrationAbsoluteFunctor ConversionFunctorAbsoluteType; - typedef itk::BinaryFunctorImageFilter FilterAbsoluteType; + typedef mitk::ConvertToConcentrationAbsoluteFunctor ConversionFunctorAbsoluteType; + typedef itk::BinaryFunctorImageFilter FilterAbsoluteType; ConversionFunctorAbsoluteType ConversionAbsoluteFunctor; ConversionAbsoluteFunctor.initialize(this->m_Factor); typename FilterAbsoluteType::Pointer ConversionAbsoluteFilter = FilterAbsoluteType::New(); ConversionAbsoluteFilter->SetFunctor(ConversionAbsoluteFunctor); ConversionAbsoluteFilter->SetInput1(itkInputImage); ConversionAbsoluteFilter->SetInput2(itkBaselineImage); ConversionAbsoluteFilter->Update(); - outputImage = mitk::ImportItkImage(ConversionAbsoluteFilter->GetOutput())->Clone(); + m_ConvertSignalToConcentrationCurve_OutputImage = mitk::ImportItkImage(ConversionAbsoluteFilter->GetOutput())->Clone(); } else if(this->m_RelativeSignalEnhancement) { - typedef mitk::ConvertToConcentrationRelativeFunctor ConversionFunctorRelativeType; - typedef itk::BinaryFunctorImageFilter FilterRelativeType; + typedef mitk::ConvertToConcentrationRelativeFunctor ConversionFunctorRelativeType; + typedef itk::BinaryFunctorImageFilter FilterRelativeType; ConversionFunctorRelativeType ConversionRelativeFunctor; ConversionRelativeFunctor.initialize(this->m_Factor); typename FilterRelativeType::Pointer ConversionRelativeFilter = FilterRelativeType::New(); ConversionRelativeFilter->SetFunctor(ConversionRelativeFunctor); ConversionRelativeFilter->SetInput1(itkInputImage); ConversionRelativeFilter->SetInput2(itkBaselineImage); ConversionRelativeFilter->Update(); - outputImage = mitk::ImportItkImage(ConversionRelativeFilter->GetOutput())->Clone(); + m_ConvertSignalToConcentrationCurve_OutputImage = mitk::ImportItkImage(ConversionRelativeFilter->GetOutput())->Clone(); } - } - - - return outputImage; + } + return m_ConvertSignalToConcentrationCurve_OutputImage; } diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp index 4bc971d1c4..0b194e4864 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp @@ -1,268 +1,268 @@ /*============================================================================ 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 "QmitkNodeSelectionButton.h" // berry includes #include #include #include "QPainter" #include "QTextDocument" #include "QEvent" #include #include // mitk core #include #include #include #include #include #include // vtk #include QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode, int height) { if (nullptr == dataNode) { return QPixmap(); } const mitk::Image* image = dynamic_cast(dataNode->GetData()); if ((nullptr == image || !image->IsInitialized()) || // -> must be an image (image->GetPixelType().GetNumberOfComponents() != 1)) // -> for now only single component are allowed { auto descManager = QmitkNodeDescriptorManager::GetInstance(); auto desc = descManager->GetDescriptor(dataNode); auto icon = desc->GetIcon(dataNode); auto fallBackMap = icon.pixmap(height, height); return fallBackMap; } mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); int sliceNumber = image->GetDimension(2) / 2; planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Axial, sliceNumber); mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); extractSliceFilter->SetInput(image); extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); extractSliceFilter->SetWorldGeometry(planeGeometry); extractSliceFilter->SetOutputDimensionality(2); extractSliceFilter->SetVtkOutputRequest(true); extractSliceFilter->Update(); vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); mitk::LevelWindow levelWindow; dataNode->GetLevelWindow(levelWindow); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); lookupTable->SetSaturationRange(0.0, 0.0); lookupTable->SetValueRange(0.0, 1.0); lookupTable->SetHueRange(0.0, 0.0); lookupTable->SetRampToLinear(); vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); levelWindowFilter->SetLookupTable(lookupTable); levelWindowFilter->SetInputData(imageData); levelWindowFilter->SetMinOpacity(0.0); levelWindowFilter->SetMaxOpacity(1.0); int dims[3]; imageData->GetDimensions(dims); double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; levelWindowFilter->SetClippingBounds(clippingBounds); levelWindowFilter->Update(); imageData = levelWindowFilter->GetOutput(); QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); thumbnailImage = thumbnailImage.scaledToHeight(height,Qt::SmoothTransformation).rgbSwapped(); return QPixmap::fromImage(thumbnailImage); } QmitkNodeSelectionButton::QmitkNodeSelectionButton(QWidget *parent) : QPushButton(parent), m_OutDatedThumpNail(true), m_DataMTime(0), m_IsOptional(true), m_NodeModifiedObserverTag(0), m_NodeObserved(false) { } QmitkNodeSelectionButton::~QmitkNodeSelectionButton() { this->RemoveNodeObserver(); this->m_SelectedNode = nullptr; } void QmitkNodeSelectionButton::AddNodeObserver() { if (this->m_SelectedNode.IsNotNull()) { if (m_NodeObserved) { MITK_DEBUG << "Invalid observer state in QmitkNodeSelectionButton. There is already a registered observer. Internal logic is not correct. May be an old observer was not removed."; } auto modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkNodeSelectionButton::OnNodeModified); // const cast because we need non const nodes and it seems to be the lesser of two evil. // the changes to the node are only on the observer level. The other option would be to // make the public interface require non const nodes, this we don't want to introduce. auto nonconst_node = const_cast(this->m_SelectedNode.GetPointer()); m_NodeModifiedObserverTag = nonconst_node->AddObserver(itk::ModifiedEvent(), modifiedCommand); m_NodeObserved = true; } } void QmitkNodeSelectionButton::RemoveNodeObserver() { if (this->m_SelectedNode.IsNotNull()) { // const cast because we need non const nodes and it seems to be the lesser of two evil. // the changes to the node are only on the observer level. The other option would be to // make the public interface require non const nodes, this we don't want to introduce. auto nonconst_node = const_cast(this->m_SelectedNode.GetPointer()); nonconst_node->RemoveObserver(m_NodeModifiedObserverTag); } m_NodeObserved = false; } void QmitkNodeSelectionButton::OnNodeModified(const itk::Object * /*caller*/, const itk::EventObject & event) { if (itk::ModifiedEvent().CheckEvent(&event)) { - this->repaint(); + this->update(); } } const mitk::DataNode* QmitkNodeSelectionButton::GetSelectedNode() const { return m_SelectedNode; } void QmitkNodeSelectionButton::SetSelectedNode(const mitk::DataNode* node) { if (m_SelectedNode != node) { this->RemoveNodeObserver(); this->m_SelectedNode = node; this->m_OutDatedThumpNail = true; this->AddNodeObserver(); } this->update(); } void QmitkNodeSelectionButton::SetNodeInfo(QString info) { this->m_Info = info; this->update(); } void QmitkNodeSelectionButton::paintEvent(QPaintEvent *p) { QString stylesheet; ctkPluginContext* context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); ctkServiceReference styleManagerRef = context->getServiceReference(); if (styleManagerRef) { auto styleManager = context->getService(styleManagerRef); stylesheet = styleManager->GetStylesheet(); } QPushButton::paintEvent(p); QPainter painter(this); QTextDocument td(this); td.setDefaultStyleSheet(stylesheet); auto widgetSize = this->size(); QPoint origin = QPoint(5, 5); if (this->m_SelectedNode) { auto iconLength = widgetSize.height() - 10; auto node = this->m_SelectedNode; itk::ModifiedTimeType dataMTime = 0; if (m_SelectedNode->GetData()) { dataMTime = m_SelectedNode->GetData()->GetMTime(); } if (dataMTime>m_DataMTime || this->m_OutDatedThumpNail) { this->m_ThumpNail = GetPixmapFromImageNode(node, iconLength); this->m_OutDatedThumpNail = false; m_DataMTime = dataMTime; } painter.drawPixmap(origin, m_ThumpNail); origin.setX(origin.x() + iconLength + 5); if (this->isEnabled()) { td.setHtml(QString::fromStdString("" + node->GetName() + "")); } else { td.setHtml(QString::fromStdString("" + node->GetName() + "")); } } else { if (this->isEnabled()) { if (this->m_IsOptional) { td.setHtml(QString("") + m_Info + QString("")); } else { td.setHtml(QString("") + m_Info + QString("")); } } else { td.setHtml(QString("") + m_Info + QString("")); } } auto textSize = td.size(); origin.setY( (widgetSize.height() - textSize.height()) / 2.); painter.translate(origin); td.drawContents(&painter); } void QmitkNodeSelectionButton::changeEvent(QEvent *event) { if (event->type() == QEvent::EnabledChange) { - this->repaint(); + this->update(); } } bool QmitkNodeSelectionButton::GetSelectionIsOptional() const { return m_IsOptional; } void QmitkNodeSelectionButton::SetSelectionIsOptional(bool isOptional) { m_IsOptional = isOptional; - this->repaint(); + this->update(); } diff --git a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp index f8902e1204..9154a37010 100644 --- a/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp +++ b/Plugins/org.mitk.gui.qt.matchpoint.algorithm.control/src/internal/QmitkMatchPoint.cpp @@ -1,873 +1,870 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "org_mitk_gui_qt_matchpoint_algorithmcontrol_Activator.h" // Blueberry #include #include #include #include // Mitk #include #include #include #include #include #include #include #include #include #include #include #include // Qmitk #include "QmitkMatchPoint.h" #include #include // Qt #include #include #include #include #include // MatchPoint #include #include #include #include #include #include #include #include #include const std::string QmitkMatchPoint::VIEW_ID = "org.mitk.views.matchpoint.algorithm.control"; QmitkMatchPoint::QmitkMatchPoint() : m_Parent(nullptr), m_LoadedDLLHandle(nullptr), m_LoadedAlgorithm(nullptr) { m_CanLoadAlgorithm = false; m_ValidInputs = false; m_Working = false; m_spSelectedTargetData = nullptr; m_spSelectedMovingData = nullptr; m_spSelectedTargetMaskData = nullptr; m_spSelectedMovingMaskData = nullptr; } QmitkMatchPoint::~QmitkMatchPoint() { // remove selection service berry::ISelectionService* s = this->GetSite()->GetWorkbenchWindow()->GetSelectionService(); if (s) { s->RemoveSelectionListener(m_AlgorithmSelectionListener.data()); } } void QmitkMatchPoint::SetFocus() { } void QmitkMatchPoint::CreateConnections() { connect(m_Controls.targetNodeSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnNodeSelectionChanged(QList))); connect(m_Controls.movingNodeSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnNodeSelectionChanged(QList))); connect(m_Controls.targetMaskNodeSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnNodeSelectionChanged(QList))); connect(m_Controls.movingMaskNodeSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnNodeSelectionChanged(QList))); // ------ // Tab 1 - Shared library loading interface // ------ connect(m_Controls.m_pbLoadSelected, SIGNAL(clicked()), this, SLOT(OnLoadAlgorithmButtonPushed())); // ----- // Tab 2 - Execution // ----- connect(m_Controls.m_pbStartReg, SIGNAL(clicked()), this, SLOT(OnStartRegBtnPushed())); connect(m_Controls.m_pbStopReg, SIGNAL(clicked()), this, SLOT(OnStopRegBtnPushed())); connect(m_Controls.m_pbSaveLog, SIGNAL(clicked()), this, SLOT(OnSaveLogBtnPushed())); } const map::deployment::DLLInfo* QmitkMatchPoint::GetSelectedAlgorithmDLL() const { return m_SelectedAlgorithmInfo; } void QmitkMatchPoint::OnSelectedAlgorithmChanged() { std::stringstream descriptionString; ::map::deployment::DLLInfo::ConstPointer currentItemInfo = GetSelectedAlgorithmDLL(); if (!currentItemInfo) { Error(QStringLiteral("No valid algorithm is selected. ABORTING.")); return; } m_Controls.m_teAlgorithmDetails->updateInfo(currentItemInfo); m_Controls.m_lbSelectedAlgorithm->setText(QString::fromStdString( currentItemInfo->getAlgorithmUID().getName())); // enable loading m_CanLoadAlgorithm = true; this->AdaptFolderGUIElements(); } void QmitkMatchPoint::OnLoadAlgorithmButtonPushed() { map::deployment::DLLInfo::ConstPointer dllInfo = GetSelectedAlgorithmDLL(); if (!dllInfo) { Error(QStringLiteral("No valid algorithm is selected. Cannot load algorithm. ABORTING.")); return; } ::map::deployment::DLLHandle::Pointer tempDLLHandle = ::map::deployment::openDeploymentDLL( dllInfo->getLibraryFilePath()); ::map::algorithm::RegistrationAlgorithmBase::Pointer tempAlgorithm = ::map::deployment::getRegistrationAlgorithm(tempDLLHandle); if (tempAlgorithm.IsNull()) { Error(QStringLiteral("Error. Cannot load selected algorithm.")); return; } this->m_LoadedAlgorithm = tempAlgorithm; this->m_LoadedDLLHandle = tempDLLHandle; this->m_Controls.m_AlgoConfigurator->setAlgorithm(m_LoadedAlgorithm); typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; const MaskRegInterface* pMaskReg = dynamic_cast (m_LoadedAlgorithm.GetPointer()); if (!pMaskReg) { m_spSelectedTargetMaskData = nullptr; m_spSelectedTargetMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; m_spSelectedMovingMaskNode = nullptr; m_Controls.targetMaskNodeSelector->SetCurrentSelection(QmitkAbstractNodeSelectionWidget::NodeList()); m_Controls.movingMaskNodeSelector->SetCurrentSelection(QmitkAbstractNodeSelectionWidget::NodeList()); } this->AdaptFolderGUIElements(); this->ConfigureNodeSelectors(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); this->m_Controls.m_tabs->setCurrentIndex(1); this->m_Controls.m_teLog->clear(); } void QmitkMatchPoint::Error(QString msg) { mitk::StatusBar::GetInstance()->DisplayErrorText(msg.toLatin1()); MITK_ERROR << msg.toStdString().c_str(); m_Controls.m_teLog->append(QStringLiteral("") + msg + QStringLiteral("")); } void QmitkMatchPoint::AdaptFolderGUIElements() { m_Controls.m_pbLoadSelected->setEnabled(m_CanLoadAlgorithm); } void QmitkMatchPoint::CreateQtPartControl(QWidget* parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Parent = parent; m_Controls.m_tabs->setCurrentIndex(0); m_Controls.movingNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.movingNodeSelector->SetSelectionIsOptional(false); m_Controls.targetNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.targetNodeSelector->SetSelectionIsOptional(false); m_Controls.movingMaskNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.movingMaskNodeSelector->SetSelectionIsOptional(true); m_Controls.targetMaskNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.targetMaskNodeSelector->SetSelectionIsOptional(true); m_AlgorithmSelectionListener.reset(new berry::SelectionChangedAdapter(this, &QmitkMatchPoint::OnAlgorithmSelectionChanged)); // register selection listener GetSite()->GetWorkbenchWindow()->GetSelectionService()->AddSelectionListener( m_AlgorithmSelectionListener.data()); this->CreateConnections(); this->AdaptFolderGUIElements(); this->CheckInputs(); this->ConfigureProgressInfos(); this->ConfigureRegistrationControls(); this->ConfigureNodeSelectors(); berry::ISelection::ConstPointer selection = GetSite()->GetWorkbenchWindow()->GetSelectionService()->GetSelection("org.mitk.views.matchpoint.algorithm.browser"); this->UpdateAlgorithmSelection(selection); } mitk::Image::Pointer ExtractFirstFrame(const mitk::Image* dynamicImage) { mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(dynamicImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); return imageTimeSelector->GetOutput(); } bool QmitkMatchPoint::CheckInputs() { if (m_LoadedAlgorithm.IsNull()) { m_spSelectedMovingNode = nullptr; m_spSelectedMovingData = nullptr; m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; m_spSelectedMovingMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { if (m_Controls.movingNodeSelector->GetSelectedNode().IsNull()) { m_spSelectedMovingNode = nullptr; m_spSelectedMovingData = nullptr; } else { m_spSelectedMovingNode = m_Controls.movingNodeSelector->GetSelectedNode(); m_spSelectedMovingData = m_spSelectedMovingNode->GetData(); auto movingImage = dynamic_cast(m_spSelectedMovingNode->GetData()); if (movingImage && movingImage->GetDimension() - 1 == m_LoadedAlgorithm->getMovingDimensions() && movingImage->GetTimeSteps() > 1) { m_spSelectedMovingData = ExtractFirstFrame(movingImage).GetPointer(); m_Controls.m_teLog->append( QStringLiteral("Selected moving image has multiple time steps. First time step is used as moving image.")); } } if (m_Controls.targetNodeSelector->GetSelectedNode().IsNull()) { m_spSelectedTargetNode = nullptr; m_spSelectedTargetData = nullptr; } else { m_spSelectedTargetNode = m_Controls.targetNodeSelector->GetSelectedNode(); m_spSelectedTargetData = m_spSelectedTargetNode->GetData(); auto targetImage = dynamic_cast(m_spSelectedTargetNode->GetData()); if (targetImage && targetImage->GetDimension() - 1 == m_LoadedAlgorithm->getTargetDimensions() && targetImage->GetTimeSteps() > 1) { m_spSelectedTargetData = ExtractFirstFrame(targetImage).GetPointer(); m_Controls.m_teLog->append( QStringLiteral("Selected target image has multiple time steps. First time step is used as target image.")); } } if (m_Controls.movingMaskNodeSelector->GetSelectedNode().IsNull()) { m_spSelectedMovingMaskNode = nullptr; m_spSelectedMovingMaskData = nullptr; } else { m_spSelectedMovingMaskNode = m_Controls.movingMaskNodeSelector->GetSelectedNode(); - m_spSelectedMovingMaskData = nullptr; - - auto movingMaskImage = dynamic_cast(m_spSelectedMovingMaskNode->GetData()); + m_spSelectedMovingMaskData = dynamic_cast(m_spSelectedMovingMaskNode->GetData()); - if (movingMaskImage->GetDimension() - 1 == m_LoadedAlgorithm->getMovingDimensions() - && movingMaskImage->GetTimeSteps() > 1) + if (m_spSelectedMovingMaskData->GetDimension() - 1 == m_LoadedAlgorithm->getMovingDimensions() + && m_spSelectedMovingMaskData->GetTimeSteps() > 1) { - m_spSelectedMovingMaskData = ExtractFirstFrame(movingMaskImage).GetPointer(); + m_spSelectedMovingMaskData = ExtractFirstFrame(m_spSelectedMovingMaskData).GetPointer(); m_Controls.m_teLog->append( QStringLiteral("Selected moving mask has multiple time steps. First time step is used as moving mask.")); } } if (m_Controls.targetMaskNodeSelector->GetSelectedNode().IsNull()) { m_spSelectedTargetMaskNode = nullptr; m_spSelectedTargetMaskData = nullptr; } else { m_spSelectedTargetMaskNode = m_Controls.targetMaskNodeSelector->GetSelectedNode(); - m_spSelectedTargetMaskData = nullptr; - auto targetMaskImage = dynamic_cast(m_spSelectedTargetMaskNode->GetData()); + m_spSelectedTargetMaskData = dynamic_cast(m_spSelectedTargetMaskNode->GetData()); - if (targetMaskImage->GetDimension() - 1 == m_LoadedAlgorithm->getTargetDimensions() - && targetMaskImage->GetTimeSteps() > 1) + if (m_spSelectedTargetMaskData->GetDimension() - 1 == m_LoadedAlgorithm->getTargetDimensions() + && m_spSelectedTargetMaskData->GetTimeSteps() > 1) { - m_spSelectedTargetMaskData = ExtractFirstFrame(targetMaskImage).GetPointer(); + m_spSelectedTargetMaskData = ExtractFirstFrame(m_spSelectedTargetMaskData).GetPointer(); m_Controls.m_teLog->append( QStringLiteral("Selected target mask has multiple time steps. First time step is used as target mask.")); } } } m_ValidInputs = m_spSelectedMovingData.IsNotNull() && m_spSelectedTargetData.IsNotNull(); return m_ValidInputs; } std::string QmitkMatchPoint::GetInputNodeDisplayName(const mitk::DataNode* node) const { std::string result = "UNDEFINED/nullptr"; if (node) { result = node->GetName(); const mitk::PointSet* pointSet = dynamic_cast(node->GetData()); if (pointSet) { mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(node); if (sources.IsNotNull() && sources->Size() > 0) { result = result + " (" + sources->GetElement(0)->GetName() + ")"; } } } return result; } mitk::DataStorage::SetOfObjects::Pointer QmitkMatchPoint::GetRegNodes() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetAll(); mitk::DataStorage::SetOfObjects::Pointer result = mitk::DataStorage::SetOfObjects::New(); for (mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) { if (mitk::MITKRegistrationHelper::IsRegNode(*pos)) { result->push_back(*pos); } } return result; } std::string QmitkMatchPoint::GetDefaultRegJobName() const { mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetRegNodes().GetPointer(); mitk::DataStorage::SetOfObjects::ElementIdentifier estimatedIndex = nodes->Size(); bool isUnique = false; std::string result = "Unnamed Reg"; while (!isUnique) { ++estimatedIndex; result = "Reg #" +::map::core::convert::toStr(estimatedIndex); isUnique = this->GetDataStorage()->GetNamedNode(result) == nullptr; } return result; } void QmitkMatchPoint::ConfigureRegistrationControls() { m_Controls.m_tabSelection->setEnabled(!m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.groupMasks->setEnabled(!m_Working); m_Controls.m_pbStartReg->setEnabled(false); m_Controls.m_pbStopReg->setEnabled(false); m_Controls.m_pbStopReg->setVisible(false); if (m_LoadedAlgorithm.IsNotNull()) { m_Controls.m_tabSettings->setEnabled(!m_Working); m_Controls.m_tabExecution->setEnabled(true); m_Controls.m_pbStartReg->setEnabled(m_ValidInputs && !m_Working); m_Controls.m_leRegJobName->setEnabled(!m_Working); m_Controls.m_checkMapEntity->setEnabled(!m_Working); m_Controls.targetNodeSelector->setEnabled(!m_Working); m_Controls.movingNodeSelector->setEnabled(!m_Working); m_Controls.targetMaskNodeSelector->setEnabled(!m_Working); m_Controls.movingMaskNodeSelector->setEnabled(!m_Working); const IStoppableAlgorithm* pIterativ = dynamic_cast (m_LoadedAlgorithm.GetPointer()); if (pIterativ) { m_Controls.m_pbStopReg->setVisible(pIterativ->isStoppable()); } typedef ::map::algorithm::facet::MaskedRegistrationAlgorithmInterface<3, 3> MaskRegInterface; const MaskRegInterface* pMaskReg = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.groupMasks->setVisible(pMaskReg != nullptr); //if the stop button is set to visible and the algorithm is working -> //then the algorithm is stoppable, thus enable the button. m_Controls.m_pbStopReg->setEnabled(m_Controls.m_pbStopReg->isVisible() && m_Working); this->m_Controls.m_lbLoadedAlgorithmName->setText( QString::fromStdString(m_LoadedAlgorithm->getUID()->toStr())); } else { m_Controls.m_tabSettings->setEnabled(false); m_Controls.m_tabExecution->setEnabled(false); this->m_Controls.m_lbLoadedAlgorithmName->setText( QStringLiteral("no algorithm loaded!")); m_Controls.groupMasks->setVisible(false); } if (!m_Working) { this->m_Controls.m_leRegJobName->setText(QString::fromStdString(this->GetDefaultRegJobName())); } } void QmitkMatchPoint::ConfigureNodeSelectors() { auto isImage = mitk::MITKRegistrationHelper::ImageNodePredicate(); auto isPointSet = mitk::MITKRegistrationHelper::PointSetNodePredicate(); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateBase::Pointer dimensionPredicate = mitk::NodePredicateOr::New(mitk::NodePredicateDimension::New(3), mitk::NodePredicateDimension::New(4)).GetPointer(); mitk::NodePredicateAnd::Pointer maskPredicate = mitk::NodePredicateAnd::New(mitk::NodePredicateOr::New(isLegacyMask, isLabelSet), dimensionPredicate); m_Controls.movingNodeSelector->setEnabled(m_LoadedAlgorithm.IsNotNull()); m_Controls.targetNodeSelector->setEnabled(m_LoadedAlgorithm.IsNotNull()); m_Controls.movingMaskNodeSelector->setEnabled(m_LoadedAlgorithm.IsNotNull()); m_Controls.targetMaskNodeSelector->setEnabled(m_LoadedAlgorithm.IsNotNull()); if (m_LoadedAlgorithm.IsNotNull()) { mitk::NodePredicateBase::ConstPointer dataPredicate; if (m_LoadedAlgorithm->getMovingDimensions() == 2) { dimensionPredicate = mitk::NodePredicateDimension::New(2); } if (mitk::MITKAlgorithmHelper::HasImageAlgorithmInterface(m_LoadedAlgorithm)) { dataPredicate = mitk::NodePredicateAnd::New(isImage, dimensionPredicate); m_Controls.movingNodeSelector->SetInvalidInfo("Select valid moving image."); m_Controls.movingNodeSelector->SetPopUpTitel("Select moving image."); m_Controls.movingNodeSelector->SetPopUpHint("Select the moving image that should be registered onto the target image."); m_Controls.targetNodeSelector->SetInvalidInfo("Select valid target image."); m_Controls.targetNodeSelector->SetPopUpTitel("Select target image."); m_Controls.targetNodeSelector->SetPopUpHint("Select the target image that should be used as reference for the registration."); } if (mitk::MITKAlgorithmHelper::HasPointSetAlgorithmInterface(m_LoadedAlgorithm)) { if (dataPredicate.IsNull()) { dataPredicate = isPointSet; m_Controls.movingNodeSelector->SetInvalidInfo("Select valid moving point set."); m_Controls.movingNodeSelector->SetPopUpTitel("Select moving point set."); m_Controls.movingNodeSelector->SetPopUpHint("Select the moving point set that should be registered onto the target point set."); m_Controls.targetNodeSelector->SetInvalidInfo("Select valid target point set."); m_Controls.targetNodeSelector->SetPopUpTitel("Select target point set."); m_Controls.targetNodeSelector->SetPopUpHint("Select the target point set that should be used as reference for the registration."); } else { dataPredicate = mitk::NodePredicateOr::New(dataPredicate, isPointSet); m_Controls.movingNodeSelector->SetInvalidInfo("Select valid moving data."); m_Controls.movingNodeSelector->SetPopUpTitel("Select moving data."); m_Controls.movingNodeSelector->SetPopUpHint("Select the moving data that should be registered onto the target data. The algorithm supports images as well as point sets."); m_Controls.targetNodeSelector->SetInvalidInfo("Select valid target data."); m_Controls.targetNodeSelector->SetPopUpTitel("Select target data."); m_Controls.targetNodeSelector->SetPopUpHint("Select the target data that should be used as reference for the registration. The algorithm supports images as well as point sets."); } } mitk::NodePredicateBase::ConstPointer nodePredicate = dataPredicate; m_Controls.movingNodeSelector->SetNodePredicate(nodePredicate); m_Controls.targetNodeSelector->SetNodePredicate(nodePredicate); nodePredicate = mitk::NodePredicateAnd::New(maskPredicate, dimensionPredicate); m_Controls.movingMaskNodeSelector->SetEmptyInfo("Select moving mask. (optional)"); m_Controls.movingMaskNodeSelector->SetPopUpTitel("Select moving mask"); m_Controls.movingMaskNodeSelector->SetPopUpHint("Select a segmentation that serves as moving mask for the registration."); m_Controls.targetMaskNodeSelector->SetEmptyInfo("Select target mask. (optional)"); m_Controls.targetMaskNodeSelector->SetPopUpTitel("Select target mask"); m_Controls.targetMaskNodeSelector->SetPopUpHint("Select a segmentation that serves as target mask for the registration."); m_Controls.movingMaskNodeSelector->SetNodePredicate(nodePredicate); m_Controls.targetMaskNodeSelector->SetNodePredicate(nodePredicate); } } void QmitkMatchPoint::ConfigureProgressInfos() { const IIterativeAlgorithm* pIterative = dynamic_cast (m_LoadedAlgorithm.GetPointer()); const IMultiResAlgorithm* pMultiRes = dynamic_cast (m_LoadedAlgorithm.GetPointer()); m_Controls.m_progBarIteration->setVisible(pIterative); m_Controls.m_lbProgBarIteration->setVisible(pIterative); if (pIterative) { QString format = "%p% (%v/%m)"; if (!pIterative->hasMaxIterationCount()) { format = "%v"; m_Controls.m_progBarIteration->setMaximum(0); } else { m_Controls.m_progBarIteration->setMaximum(pIterative->getMaxIterations()); } m_Controls.m_progBarIteration->setFormat(format); } m_Controls.m_progBarLevel->setVisible(pMultiRes); m_Controls.m_lbProgBarLevel->setVisible(pMultiRes); if (pMultiRes) { m_Controls.m_progBarLevel->setMaximum(pMultiRes->getResolutionLevels()); } else { m_Controls.m_progBarLevel->setMaximum(1); } m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); } void QmitkMatchPoint::OnNodeSelectionChanged(QList /*nodes*/) { if (!m_Working) { CheckInputs(); ConfigureRegistrationControls(); } } void QmitkMatchPoint::OnStartRegBtnPushed() { this->m_Working = true; //////////////////////////////// //configure GUI this->ConfigureProgressInfos(); m_Controls.m_progBarIteration->reset(); m_Controls.m_progBarLevel->reset(); this->ConfigureRegistrationControls(); if (m_Controls.m_checkClearLog->checkState() == Qt::Checked) { this->m_Controls.m_teLog->clear(); } ///////////////////////// //create job and put it into the thread pool QmitkRegistrationJob* pJob = new QmitkRegistrationJob(m_LoadedAlgorithm); pJob->setAutoDelete(true); pJob->m_spTargetData = m_spSelectedTargetData; pJob->m_spMovingData = m_spSelectedMovingData; pJob->m_TargetDataUID = mitk::EnsureUID(this->m_spSelectedTargetNode->GetData()); pJob->m_MovingDataUID = mitk::EnsureUID(this->m_spSelectedMovingNode->GetData()); if (m_spSelectedTargetMaskData.IsNotNull()) { pJob->m_spTargetMask = m_spSelectedTargetMaskData; pJob->m_TargetMaskDataUID = mitk::EnsureUID(this->m_spSelectedTargetMaskNode->GetData()); } if (m_spSelectedMovingMaskData.IsNotNull()) { pJob->m_spMovingMask = m_spSelectedMovingMaskData; pJob->m_MovingMaskDataUID = mitk::EnsureUID(this->m_spSelectedMovingMaskNode->GetData()); } pJob->m_JobName = m_Controls.m_leRegJobName->text().toStdString(); pJob->m_StoreReg = true; connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnRegJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnRegJobFinished())); connect(pJob, SIGNAL(RegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), this, SLOT(OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer, const QmitkRegistrationJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); connect(pJob, SIGNAL(AlgorithmStatusChanged(QString)), this, SLOT(OnAlgorithmStatusChanged(QString))); connect(pJob, SIGNAL(AlgorithmIterated(QString, bool, unsigned long)), this, SLOT(OnAlgorithmIterated(QString, bool, unsigned long))); connect(pJob, SIGNAL(LevelChanged(QString, bool, unsigned long)), this, SLOT(OnLevelChanged(QString, bool, unsigned long))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } void QmitkMatchPoint::OnStopRegBtnPushed() { if (m_LoadedAlgorithm.IsNotNull()) { IStoppableAlgorithm* pIterativ = dynamic_cast(m_LoadedAlgorithm.GetPointer()); if (pIterativ && pIterativ->isStoppable()) { if (pIterativ->stopAlgorithm()) { } else { } m_Controls.m_pbStopReg->setEnabled(false); } else { } } } void QmitkMatchPoint::OnSaveLogBtnPushed() { QDateTime currentTime = QDateTime::currentDateTime(); QString fileName = tr("registration_log_") + currentTime.toString(tr("yyyy-MM-dd_hh-mm-ss")) + tr(".txt"); fileName = QFileDialog::getSaveFileName(nullptr, tr("Save registration log"), fileName, tr("Text files (*.txt)")); if (fileName.isEmpty()) { QMessageBox::critical(nullptr, tr("No file selected!"), tr("Cannot save registration log file. Please selected a file.")); } else { std::ofstream file; std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc; file.open(fileName.toStdString().c_str(), iOpenFlag); if (!file.is_open()) { mitkThrow() << "Cannot open or create specified file to save. File path: " << fileName.toStdString(); } file << this->m_Controls.m_teLog->toPlainText().toStdString() << std::endl; file.close(); } } void QmitkMatchPoint::OnRegJobError(QString err) { Error(err); } void QmitkMatchPoint::OnRegJobFinished() { this->m_Working = false; this->GetRenderWindowPart()->RequestUpdate(); this->CheckInputs(); this->ConfigureRegistrationControls(); this->ConfigureProgressInfos(); } void QmitkMatchPoint::OnRegResultIsAvailable(mitk::MAPRegistrationWrapper::Pointer spResultRegistration, const QmitkRegistrationJob* pRegJob) { mitk::DataNode::Pointer spResultRegistrationNode = mitk::generateRegistrationResultNode( pRegJob->m_JobName, spResultRegistration, pRegJob->GetLoadedAlgorithm()->getUID()->toStr(), pRegJob->m_MovingDataUID, pRegJob->m_TargetDataUID); if (pRegJob->m_StoreReg) { m_Controls.m_teLog->append( QStringLiteral(" Storing registration object in data manager ... ")); this->GetDataStorage()->Add(spResultRegistrationNode); this->GetRenderWindowPart()->RequestUpdate(); } if (m_Controls.m_checkMapEntity->checkState() == Qt::Checked) { QmitkMappingJob* pMapJob = new QmitkMappingJob(); pMapJob->setAutoDelete(true); pMapJob->m_spInputData = pRegJob->m_spMovingData; pMapJob->m_InputDataUID = pRegJob->m_MovingDataUID; pMapJob->m_spRegNode = spResultRegistrationNode; pMapJob->m_doGeometryRefinement = false; pMapJob->m_spRefGeometry = pRegJob->m_spTargetData->GetGeometry()->Clone().GetPointer(); pMapJob->m_MappedName = pRegJob->m_JobName + std::string(" mapped moving data"); pMapJob->m_allowUndefPixels = true; pMapJob->m_paddingValue = 100; pMapJob->m_allowUnregPixels = true; pMapJob->m_errorValue = 200; pMapJob->m_InterpolatorLabel = "Linear Interpolation"; pMapJob->m_InterpolatorType = mitk::ImageMappingInterpolator::Linear; connect(pMapJob, SIGNAL(Error(QString)), this, SLOT(OnMapJobError(QString))); connect(pMapJob, SIGNAL(MapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), this, SLOT(OnMapResultIsAvailable(mitk::BaseData::Pointer, const QmitkMappingJob*)), Qt::BlockingQueuedConnection); connect(pMapJob, SIGNAL(AlgorithmInfo(QString)), this, SLOT(OnAlgorithmInfo(QString))); m_Controls.m_teLog->append( QStringLiteral("Started mapping input data...")); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pMapJob); } } void QmitkMatchPoint::OnMapJobError(QString err) { Error(err); } void QmitkMatchPoint::OnMapResultIsAvailable(mitk::BaseData::Pointer spMappedData, const QmitkMappingJob* job) { m_Controls.m_teLog->append(QStringLiteral("Mapped entity stored. Name: ") + QString::fromStdString(job->m_MappedName) + QStringLiteral("")); mitk::DataNode::Pointer spMappedNode = mitk::generateMappedResultNode(job->m_MappedName, spMappedData, job->GetRegistration()->getRegistrationUID(), job->m_InputDataUID, job->m_doGeometryRefinement, job->m_InterpolatorLabel); this->GetDataStorage()->Add(spMappedNode); this->GetRenderWindowPart()->RequestUpdate(); } void QmitkMatchPoint::OnAlgorithmIterated(QString info, bool hasIterationCount, unsigned long currentIteration) { if (hasIterationCount) { m_Controls.m_progBarIteration->setValue(currentIteration); } m_Controls.m_teLog->append(info); } void QmitkMatchPoint::OnLevelChanged(QString info, bool hasLevelCount, unsigned long currentLevel) { if (hasLevelCount) { m_Controls.m_progBarLevel->setValue(currentLevel); } m_Controls.m_teLog->append(QStringLiteral("") + info + QStringLiteral("")); } void QmitkMatchPoint::OnAlgorithmStatusChanged(QString info) { m_Controls.m_teLog->append(QStringLiteral("") + info + QStringLiteral(" ")); } void QmitkMatchPoint::OnAlgorithmInfo(QString info) { m_Controls.m_teLog->append(QStringLiteral("") + info + QStringLiteral("")); } void QmitkMatchPoint::OnAlgorithmSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection) { // check for null selection if (selection.IsNull()) { return; } if (sourcepart != this) { UpdateAlgorithmSelection(selection); } } void QmitkMatchPoint::UpdateAlgorithmSelection(berry::ISelection::ConstPointer selection) { mitk::MAPAlgorithmInfoSelection::ConstPointer currentSelection = selection.Cast(); if (currentSelection) { mitk::MAPAlgorithmInfoSelection::AlgorithmInfoVectorType infoVector = currentSelection->GetSelectedAlgorithmInfo(); if (!infoVector.empty()) { // only the first selection is of interest, the rest will be skipped. this->m_SelectedAlgorithmInfo = infoVector[0]; } } this->OnSelectedAlgorithmChanged(); } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index 5a749d566d..c441d79792 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,622 +1,628 @@ /*============================================================================ 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 "QmitkImageStatisticsView.h" #include // berry includes #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkImageStatisticsContainerManager.h" #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject * /*parent*/, const char * /*name*/) { this->m_CalculationJob = new QmitkImageStatisticsCalculationJob(); } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if (m_selectedPlanarFigure) { m_selectedPlanarFigure->RemoveObserver(m_PlanarFigureObserverTag); } if (!m_CalculationJob->isFinished()) { m_CalculationJob->terminate(); m_CalculationJob->wait(); } this->m_CalculationJob->deleteLater(); } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { m_Controls.setupUi(parent); m_Controls.widget_histogram->SetTheme(this->GetColorTheme()); m_Controls.widget_intensityProfile->SetTheme(this->GetColorTheme()); m_Controls.groupBox_histogram->setVisible(true); m_Controls.groupBox_intensityProfile->setVisible(false); m_Controls.label_currentlyComputingStatistics->setVisible(false); m_Controls.sliderWidget_histogram->setPrefix("Time: "); m_Controls.sliderWidget_histogram->setDecimals(0); m_Controls.sliderWidget_histogram->setVisible(false); m_Controls.sliderWidget_intensityProfile->setPrefix("Time: "); m_Controls.sliderWidget_intensityProfile->setDecimals(0); m_Controls.sliderWidget_intensityProfile->setVisible(false); ResetGUI(); PrepareDataStorageComboBoxes(); m_Controls.widget_statistics->SetDataStorage(this->GetDataStorage()); CreateConnections(); } void QmitkImageStatisticsView::CreateConnections() { connect(this->m_CalculationJob, &QmitkImageStatisticsCalculationJob::finished, this, &QmitkImageStatisticsView::OnStatisticsCalculationEnds, Qt::QueuedConnection); connect(this->m_Controls.checkBox_ignoreZero, &QCheckBox::stateChanged, this, &QmitkImageStatisticsView::OnCheckBoxIgnoreZeroStateChanged); connect(this->m_Controls.sliderWidget_histogram, &ctkSliderWidget::valueChanged, this, &QmitkImageStatisticsView::OnSliderWidgetHistogramChanged); connect(this->m_Controls.sliderWidget_intensityProfile, &ctkSliderWidget::valueChanged, this, &QmitkImageStatisticsView::OnSliderWidgetIntensityProfileChanged); connect(this->m_Controls.imageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnImageSelectorChanged); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); } void QmitkImageStatisticsView::OnCheckBoxIgnoreZeroStateChanged(int state) { m_ForceRecompute = true; if (state != Qt::Unchecked) { this->m_CalculationJob->SetIgnoreZeroValueVoxel(true); } else { this->m_CalculationJob->SetIgnoreZeroValueVoxel(false); } CalculateOrGetStatistics(); } void QmitkImageStatisticsView::OnSliderWidgetHistogramChanged(double value) { unsigned int timeStep = static_cast(value); auto mask = m_selectedMaskNode ? m_selectedMaskNode->GetData() : nullptr; auto imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics( this->GetDataStorage(), m_selectedImageNode->GetData(), mask); HistogramType::ConstPointer histogram = nullptr; if (imageStatistics->TimeStepExists(timeStep)) { histogram = imageStatistics->GetStatisticsForTimeStep(timeStep).m_Histogram; } if (this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) { if (histogram.IsNotNull()) { this->FillHistogramWidget({histogram}, {m_selectedImageNode->GetName()}); } else { HistogramType::Pointer emptyHistogram = HistogramType::New(); this->FillHistogramWidget({emptyHistogram}, {m_selectedImageNode->GetName()}); } } } void QmitkImageStatisticsView::OnSliderWidgetIntensityProfileChanged() { // intensity profile is always computed on request, not stored as node in DataStorage auto image = dynamic_cast(m_selectedImageNode->GetData()); auto planarFigure = dynamic_cast(m_selectedMaskNode->GetData()); if (image && planarFigure && this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) { this->ComputeAndDisplayIntensityProfile(image, planarFigure); } } void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer &) {} void QmitkImageStatisticsView::FillHistogramWidget(const std::vector &histogram, const std::vector &dataLabels) { m_Controls.groupBox_histogram->setVisible(true); m_Controls.widget_histogram->SetTheme(this->GetColorTheme()); m_Controls.widget_histogram->Reset(); m_Controls.widget_histogram->SetHistogram(histogram.front(), dataLabels.front()); connect(m_Controls.widget_histogram, &QmitkHistogramVisualizationWidget::RequestHistogramUpdate, this, &QmitkImageStatisticsView::OnRequestHistogramUpdate); } QmitkChartWidget::ColorTheme QmitkImageStatisticsView::GetColorTheme() const { ctkPluginContext *context = berry::WorkbenchPlugin::GetDefault()->GetPluginContext(); ctkServiceReference styleManagerRef = context->getServiceReference(); if (styleManagerRef) { auto styleManager = context->getService(styleManagerRef); if (styleManager->GetStyle().name == "Dark") { return QmitkChartWidget::ColorTheme::darkstyle; } else { return QmitkChartWidget::ColorTheme::lightstyle; } } return QmitkChartWidget::ColorTheme::darkstyle; } void QmitkImageStatisticsView::OnImageSelectorChanged() { auto selectedImageNode = m_Controls.imageSelector->GetSelectedNode(); if (selectedImageNode != m_selectedImageNode) { m_selectedImageNode = selectedImageNode; if (m_selectedImageNode.IsNotNull()) { ResetGUIDefault(); auto isPlanarFigurePredicate = mitk::GetImageStatisticsPlanarFigurePredicate(); auto isMaskPredicate = mitk::GetImageStatisticsMaskPredicate(); auto hasSameGeometry = mitk::NodePredicateGeometry::New(m_selectedImageNode->GetData()->GetGeometry()); hasSameGeometry->SetCheckPrecision(1e-10); auto isMaskWithGeometryPredicate = mitk::NodePredicateAnd::New(isMaskPredicate, hasSameGeometry); auto isMaskOrPlanarFigureWithGeometryPredicate = mitk::NodePredicateOr::New(isPlanarFigurePredicate, isMaskWithGeometryPredicate); // prevent triggering of computation as the predicate triggers a signalChanged event m_Controls.maskImageSelector->disconnect(); m_Controls.maskImageSelector->SetPredicate(isMaskOrPlanarFigureWithGeometryPredicate); // reset mask to m_Controls.maskImageSelector->SetZeroEntryText(""); m_Controls.checkBox_ignoreZero->setEnabled(true); m_selectedMaskNode = nullptr; m_Controls.widget_statistics->SetMaskNodes({}); CalculateOrGetStatistics(); m_Controls.widget_statistics->SetImageNodes({m_selectedImageNode}); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); } else { m_Controls.widget_statistics->SetImageNodes({}); m_Controls.widget_statistics->SetMaskNodes({}); m_Controls.widget_statistics->Reset(); m_Controls.widget_histogram->Reset(); ResetGUI(); } } } void QmitkImageStatisticsView::OnMaskSelectorChanged() { auto selectedMaskNode = m_Controls.maskImageSelector->GetSelectedNode(); if (selectedMaskNode != m_selectedMaskNode) { m_selectedMaskNode = selectedMaskNode; if (m_selectedMaskNode.IsNotNull()) { m_Controls.widget_statistics->SetMaskNodes({m_selectedMaskNode}); } else { m_Controls.widget_statistics->SetMaskNodes({}); } CalculateOrGetStatistics(); } } void QmitkImageStatisticsView::CalculateOrGetStatistics() { if (this->m_selectedPlanarFigure) { this->m_selectedPlanarFigure->RemoveObserver(this->m_PlanarFigureObserverTag); this->m_selectedPlanarFigure = nullptr; } m_Controls.groupBox_intensityProfile->setVisible(false); m_Controls.widget_statistics->setEnabled(m_selectedImageNode.IsNotNull()); if (m_selectedImageNode != nullptr) { auto image = dynamic_cast(m_selectedImageNode->GetData()); mitk::Image *mask = nullptr; mitk::PlanarFigure *maskPlanarFigure = nullptr; if (image->GetDimension() == 4) { m_Controls.sliderWidget_histogram->setVisible(true); unsigned int maxTimestep = image->GetTimeSteps(); m_Controls.sliderWidget_histogram->setMaximum(maxTimestep - 1); } else { m_Controls.sliderWidget_histogram->setVisible(false); } if (m_selectedMaskNode != nullptr) { mask = dynamic_cast(m_selectedMaskNode->GetData()); if (mask == nullptr) { maskPlanarFigure = dynamic_cast(m_selectedMaskNode->GetData()); } } mitk::ImageStatisticsContainer::ConstPointer imageStatistics; if (mask) { imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image, mask); } else if (maskPlanarFigure) { m_selectedPlanarFigure = maskPlanarFigure; ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction(this, &QmitkImageStatisticsView::CalculateOrGetStatistics); this->m_PlanarFigureObserverTag = m_selectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); if (!maskPlanarFigure->IsClosed()) { ComputeAndDisplayIntensityProfile(image, maskPlanarFigure); } imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image, maskPlanarFigure); } else { imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image); } bool imageStatisticsOlderThanInputs = false; if (imageStatistics && (imageStatistics->GetMTime() < image->GetMTime() || (mask && imageStatistics->GetMTime() < mask->GetMTime()) || (maskPlanarFigure && imageStatistics->GetMTime() < maskPlanarFigure->GetMTime()))) { imageStatisticsOlderThanInputs = true; } if (imageStatistics) { // triggers recomputation when switched between images and the newest one has not 100 bins (default) auto calculatedBins = imageStatistics->GetStatisticsForTimeStep(0).m_Histogram.GetPointer()->Size(); if (calculatedBins != 100) { OnRequestHistogramUpdate(m_Controls.widget_histogram->GetBins()); } } // statistics need to be computed if (!imageStatistics || imageStatisticsOlderThanInputs || m_ForceRecompute) { CalculateStatistics(image, mask, maskPlanarFigure); } // statistics already computed else { // Not an open planar figure: show histogram (intensity profile already shown) if (!(maskPlanarFigure && !maskPlanarFigure->IsClosed())) { if (imageStatistics->TimeStepExists(0)) { auto histogram = imageStatistics->GetStatisticsForTimeStep(0).m_Histogram.GetPointer(); std::string imageNodeName = m_selectedImageNode->GetName(); this->FillHistogramWidget({histogram}, {imageNodeName}); } } } } else { ResetGUI(); } m_ForceRecompute = false; } void QmitkImageStatisticsView::ComputeAndDisplayIntensityProfile(mitk::Image *image, mitk::PlanarFigure *maskPlanarFigure) { mitk::Image::Pointer inputImage; if (image->GetDimension() == 4) { m_Controls.sliderWidget_intensityProfile->setVisible(true); unsigned int maxTimestep = image->GetTimeSteps(); m_Controls.sliderWidget_intensityProfile->setMaximum(maxTimestep - 1); // Intensity profile can only be calculated on 3D, so extract if 4D mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); int currentTimestep = static_cast(m_Controls.sliderWidget_intensityProfile->value()); timeSelector->SetInput(image); timeSelector->SetTimeNr(currentTimestep); timeSelector->Update(); inputImage = timeSelector->GetOutput(); } else { m_Controls.sliderWidget_intensityProfile->setVisible(false); inputImage = image; } auto intensityProfile = mitk::ComputeIntensityProfile(inputImage, maskPlanarFigure); // Don't show histogram for intensity profiles m_Controls.groupBox_histogram->setVisible(false); m_Controls.groupBox_intensityProfile->setVisible(true); m_Controls.widget_intensityProfile->Reset(); m_Controls.widget_intensityProfile->SetIntensityProfile(intensityProfile.GetPointer(), "Intensity Profile of " + m_selectedImageNode->GetName()); } void QmitkImageStatisticsView::ResetGUI() { m_Controls.widget_statistics->Reset(); m_Controls.widget_statistics->setEnabled(false); m_Controls.widget_histogram->Reset(); m_Controls.widget_histogram->setEnabled(false); m_Controls.checkBox_ignoreZero->setEnabled(false); } void QmitkImageStatisticsView::ResetGUIDefault() { m_Controls.widget_histogram->ResetDefault(); m_Controls.checkBox_ignoreZero->setChecked(false); } std::string QmitkImageStatisticsView::GenerateStatisticsNodeName() { - auto statisticsNodeName = m_selectedImageNode->GetName(); - if (m_selectedMaskNode) + std::string statisticsNodeName = ""; + + if (m_selectedImageNode.IsNotNull()) + { + statisticsNodeName = m_selectedImageNode->GetName();; + } + + if (m_selectedMaskNode.IsNotNull()) { statisticsNodeName += "_" + m_selectedMaskNode->GetName(); } - statisticsNodeName += "_statistics"; + statisticsNodeName += "statistics"; return statisticsNodeName; } mitk::DataNode::Pointer QmitkImageStatisticsView::GetNodeForStatisticsContainer( mitk::ImageStatisticsContainer::ConstPointer container) { if (!container) { mitkThrow() << "Given container is null!"; } auto allDataNodes = this->GetDataStorage()->GetAll()->CastToSTLConstContainer(); for (auto node : allDataNodes) { auto nodeData = node->GetData(); if (nodeData && nodeData->GetUID() == container->GetUID()) { return node; } } mitkThrow() << "No DataNode is found which holds the given statistics container!"; } void QmitkImageStatisticsView::HandleExistingStatistics(mitk::Image::ConstPointer image, mitk::BaseData::ConstPointer mask, mitk::ImageStatisticsContainer::Pointer statistic) { auto imageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics( this->GetDataStorage(), image, mask); // if statistics base data already exist: add to existing node if (imageStatistics) { auto node = GetNodeForStatisticsContainer(imageStatistics); node->SetData(statistic); } // statistics base data does not exist: add new node else { auto statisticsNodeName = GenerateStatisticsNodeName(); auto statisticsNode = mitk::CreateImageStatisticsNode(statistic, statisticsNodeName); this->GetDataStorage()->Add(statisticsNode); } } void QmitkImageStatisticsView::SetupRelationRules(mitk::ImageStatisticsContainer::Pointer statistic, mitk::BaseData::ConstPointer mask) { auto imageRule = mitk::StatisticsToImageRelationRule::New(); imageRule->Connect(statistic, m_CalculationJob->GetStatisticsImage()); if (mask) { auto maskRule = mitk::StatisticsToMaskRelationRule::New(); maskRule->Connect(statistic, mask); } } void QmitkImageStatisticsView::OnStatisticsCalculationEnds() { mitk::StatusBar::GetInstance()->Clear(); auto image = m_CalculationJob->GetStatisticsImage(); // get mask mitk::BaseData::ConstPointer mask = nullptr; if (m_CalculationJob->GetMaskImage()) { mask = m_CalculationJob->GetMaskImage(); } else if (m_CalculationJob->GetPlanarFigure()) { mask = m_CalculationJob->GetPlanarFigure(); } // get current statistics auto currentImageStatistics = mitk::ImageStatisticsContainerManager::GetImageStatistics(this->GetDataStorage(), image, mask); if (this->m_CalculationJob->GetStatisticsUpdateSuccessFlag()) // case: calculation was successfull { auto statistic = m_CalculationJob->GetStatisticsData(); SetupRelationRules(statistic, mask); // checks for existing statistic, and add it to data manager HandleExistingStatistics(image, mask, statistic); if (!m_selectedPlanarFigure || m_selectedPlanarFigure->IsClosed()) { this->FillHistogramWidget({m_CalculationJob->GetTimeStepHistogram()}, {m_selectedImageNode->GetName()}); } } else // case: calculation was not successfull { // handle histogram - const HistogramType* emptyHistogram = HistogramType::New(); + auto emptyHistogram = HistogramType::New(); this->FillHistogramWidget({emptyHistogram}, {m_selectedImageNode->GetName()}); // handle statistics mitk::ImageStatisticsContainer::Pointer statistic = mitk::ImageStatisticsContainer::New(); statistic->SetTimeGeometry(const_cast(image->GetTimeGeometry())); // add empty histogram to stastistics for all timesteps for (unsigned int i = 0; i < image->GetTimeSteps(); ++i) { auto statisticObject = mitk::ImageStatisticsContainer::ImageStatisticsObject(); statisticObject.m_Histogram = emptyHistogram; statistic->SetStatisticsForTimeStep(i, statisticObject); } SetupRelationRules(statistic, mask); HandleExistingStatistics(image, mask, statistic); mitk::StatusBar::GetInstance()->DisplayErrorText(m_CalculationJob->GetLastErrorMessage().c_str()); m_Controls.widget_histogram->setEnabled(false); } m_Controls.label_currentlyComputingStatistics->setVisible(false); } void QmitkImageStatisticsView::OnRequestHistogramUpdate(unsigned int nBins) { m_CalculationJob->SetHistogramNBins(nBins); m_CalculationJob->start(); } void QmitkImageStatisticsView::CalculateStatistics(const mitk::Image *image, const mitk::Image *mask, const mitk::PlanarFigure *maskPlanarFigure) { this->m_CalculationJob->Initialize(image, mask, maskPlanarFigure); try { // Compute statistics this->m_CalculationJob->start(); m_Controls.label_currentlyComputingStatistics->setVisible(true); } catch (const mitk::Exception &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.GetDescription()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } catch (const std::runtime_error &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } catch (const std::exception &e) { mitk::StatusBar::GetInstance()->DisplayErrorText(e.what()); m_Controls.label_currentlyComputingStatistics->setVisible(false); } } void QmitkImageStatisticsView::OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) { Q_UNUSED(part); Q_UNUSED(nodes); } void QmitkImageStatisticsView::PrepareDataStorageComboBoxes() { auto isPlanarFigurePredicate = mitk::GetImageStatisticsPlanarFigurePredicate(); auto isMaskPredicate = mitk::GetImageStatisticsMaskPredicate(); auto isImagePredicate = mitk::GetImageStatisticsImagePredicate(); auto isMaskOrPlanarFigurePredicate = mitk::NodePredicateOr::New(isPlanarFigurePredicate, isMaskPredicate); m_Controls.imageSelector->SetDataStorage(GetDataStorage()); m_Controls.imageSelector->SetPredicate(isImagePredicate); m_Controls.maskImageSelector->SetDataStorage(GetDataStorage()); m_Controls.maskImageSelector->SetPredicate(isMaskOrPlanarFigurePredicate); m_Controls.maskImageSelector->SetZeroEntryText(""); } void QmitkImageStatisticsView::Activated() {} void QmitkImageStatisticsView::Deactivated() {} void QmitkImageStatisticsView::Visible() { connect(this->m_Controls.imageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnImageSelectorChanged); connect(this->m_Controls.maskImageSelector, static_cast(&QComboBox::currentIndexChanged), this, &QmitkImageStatisticsView::OnMaskSelectorChanged); OnImageSelectorChanged(); OnMaskSelectorChanged(); } void QmitkImageStatisticsView::Hidden() { m_Controls.imageSelector->disconnect(); m_Controls.maskImageSelector->disconnect(); } void QmitkImageStatisticsView::SetFocus() {} diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp index 7f4bad141b..8a4f70accc 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp @@ -1,918 +1,829 @@ /*============================================================================ 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 "QmitkMeasurementView.h" #include #include #include #include #include #include + #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include + #include -#include +#include #include "mitkPluginActivator.h" #include "usModuleRegistry.h" #include "mitkInteractionEventObserver.h" #include "mitkDisplayInteractor.h" #include "usGetModuleContext.h" #include "usModuleContext.h" #include US_INITIALIZE_MODULE struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_EndPlacementObserverTag(0), m_SelectObserverTag(0), m_StartInteractionObserverTag(0), m_EndInteractionObserverTag(0) { } mitk::PlanarFigure::Pointer m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; }; struct QmitkMeasurementViewData { QmitkMeasurementViewData() : m_LineCounter(0), m_PathCounter(0), m_AngleCounter(0), m_FourPointAngleCounter(0), m_CircleCounter(0), m_EllipseCounter(0), m_DoubleEllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_BezierCurveCounter(0), m_SubdivisionPolygonCounter(0), m_UnintializedPlanarFigure(false), m_ScrollEnabled(true), m_Parent(nullptr), - m_SelectedImageLabel(nullptr), + m_SingleNodeSelectionWidget(nullptr), m_DrawLine(nullptr), m_DrawPath(nullptr), m_DrawAngle(nullptr), m_DrawFourPointAngle(nullptr), m_DrawRectangle(nullptr), m_DrawPolygon(nullptr), m_DrawCircle(nullptr), m_DrawEllipse(nullptr), m_DrawDoubleEllipse(nullptr), m_DrawBezierCurve(nullptr), m_DrawSubdivisionPolygon(nullptr), m_DrawActionsToolBar(nullptr), m_DrawActionsGroup(nullptr), m_SelectedPlanarFiguresText(nullptr), m_CopyToClipboard(nullptr), m_Layout(nullptr) { } unsigned int m_LineCounter; unsigned int m_PathCounter; unsigned int m_AngleCounter; unsigned int m_FourPointAngleCounter; unsigned int m_CircleCounter; unsigned int m_EllipseCounter; unsigned int m_DoubleEllipseCounter; unsigned int m_RectangleCounter; unsigned int m_PolygonCounter; unsigned int m_BezierCurveCounter; unsigned int m_SubdivisionPolygonCounter; QList m_CurrentSelection; std::map m_DataNodeToPlanarFigureData; mitk::DataNode::Pointer m_SelectedImageNode; bool m_UnintializedPlanarFigure; bool m_ScrollEnabled; QWidget* m_Parent; - QLabel* m_SelectedImageLabel; + QmitkSingleNodeSelectionWidget* m_SingleNodeSelectionWidget; QAction* m_DrawLine; QAction* m_DrawPath; QAction* m_DrawAngle; QAction* m_DrawFourPointAngle; QAction* m_DrawRectangle; QAction* m_DrawPolygon; QAction* m_DrawCircle; QAction* m_DrawEllipse; QAction* m_DrawDoubleEllipse; QAction* m_DrawBezierCurve; QAction* m_DrawSubdivisionPolygon; QToolBar* m_DrawActionsToolBar; QActionGroup* m_DrawActionsGroup; QTextBrowser* m_SelectedPlanarFiguresText; QPushButton* m_CopyToClipboard; QGridLayout* m_Layout; }; const std::string QmitkMeasurementView::VIEW_ID = "org.mitk.views.measurement"; QmitkMeasurementView::QmitkMeasurementView() : d(new QmitkMeasurementViewData) { } QmitkMeasurementView::~QmitkMeasurementView() { auto planarFigures = this->GetAllPlanarFigures(); for (auto it = planarFigures->Begin(); it != planarFigures->End(); ++it) this->NodeRemoved(it.Value()); delete d; } void QmitkMeasurementView::CreateQtPartControl(QWidget* parent) { d->m_Parent = parent; - auto selectedImageLabel = new QLabel(tr("Reference Image: ")); - - d->m_SelectedImageLabel = new QLabel; - d->m_SelectedImageLabel->setStyleSheet("font-weight: bold;"); + d->m_SingleNodeSelectionWidget = new QmitkSingleNodeSelectionWidget(); + d->m_SingleNodeSelectionWidget->SetDataStorage(GetDataStorage()); + d->m_SingleNodeSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( + mitk::TNodePredicateDataType::New(), + mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); + d->m_SingleNodeSelectionWidget->SetSelectionIsOptional(true); + d->m_SingleNodeSelectionWidget->SetEmptyInfo(QStringLiteral("Please select a reference image")); + d->m_SingleNodeSelectionWidget->SetPopUpTitel(QStringLiteral("Select a reference image")); d->m_DrawActionsToolBar = new QToolBar; d->m_DrawActionsGroup = new QActionGroup(this); d->m_DrawActionsGroup->setExclusive(true); auto* currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/line.png"), tr("Draw Line")); currentAction->setCheckable(true); d->m_DrawLine = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/path.png"), tr("Draw Path")); currentAction->setCheckable(true); d->m_DrawPath = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/angle.png"), tr("Draw Angle")); currentAction->setCheckable(true); d->m_DrawAngle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/four-point-angle.png"), tr("Draw Four Point Angle")); currentAction->setCheckable(true); d->m_DrawFourPointAngle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/circle.png"), tr("Draw Circle")); currentAction->setCheckable(true); d->m_DrawCircle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/ellipse.png"), tr("Draw Ellipse")); currentAction->setCheckable(true); d->m_DrawEllipse = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/doubleellipse.png"), tr("Draw Double Ellipse")); currentAction->setCheckable(true); d->m_DrawDoubleEllipse = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/rectangle.png"), tr("Draw Rectangle")); currentAction->setCheckable(true); d->m_DrawRectangle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/polygon.png"), tr("Draw Polygon")); currentAction->setCheckable(true); d->m_DrawPolygon = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/beziercurve.png"), tr("Draw Bezier Curve")); currentAction->setCheckable(true); d->m_DrawBezierCurve = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/subdivisionpolygon.png"), tr("Draw Subdivision Polygon")); currentAction->setCheckable(true); d->m_DrawSubdivisionPolygon = currentAction; + d->m_DrawActionsToolBar->setEnabled(false); + // planar figure details text d->m_SelectedPlanarFiguresText = new QTextBrowser; // copy to clipboard button d->m_CopyToClipboard = new QPushButton(tr("Copy to Clipboard")); d->m_Layout = new QGridLayout; - d->m_Layout->addWidget(selectedImageLabel, 0, 0, 1, 1); - d->m_Layout->addWidget(d->m_SelectedImageLabel, 0, 1, 1, 1); + d->m_Layout->addWidget(d->m_SingleNodeSelectionWidget, 0, 0, 1, 2); d->m_Layout->addWidget(d->m_DrawActionsToolBar, 1, 0, 1, 2); d->m_Layout->addWidget(d->m_SelectedPlanarFiguresText, 2, 0, 1, 2); d->m_Layout->addWidget(d->m_CopyToClipboard, 3, 0, 1, 2); d->m_Parent->setLayout(d->m_Layout); this->CreateConnections(); this->AddAllInteractors(); } + void QmitkMeasurementView::CreateConnections() { + connect(d->m_SingleNodeSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkMeasurementView::OnCurrentSelectionChanged); connect(d->m_DrawLine, SIGNAL(triggered(bool)), this, SLOT(OnDrawLineTriggered(bool))); connect(d->m_DrawPath, SIGNAL(triggered(bool)), this, SLOT(OnDrawPathTriggered(bool))); connect(d->m_DrawAngle, SIGNAL(triggered(bool)), this, SLOT(OnDrawAngleTriggered(bool))); connect(d->m_DrawFourPointAngle, SIGNAL(triggered(bool)), this, SLOT(OnDrawFourPointAngleTriggered(bool))); connect(d->m_DrawCircle, SIGNAL(triggered(bool)), this, SLOT(OnDrawCircleTriggered(bool))); connect(d->m_DrawEllipse, SIGNAL(triggered(bool)), this, SLOT(OnDrawEllipseTriggered(bool))); connect(d->m_DrawDoubleEllipse, SIGNAL(triggered(bool)), this, SLOT(OnDrawDoubleEllipseTriggered(bool))); connect(d->m_DrawRectangle, SIGNAL(triggered(bool)), this, SLOT(OnDrawRectangleTriggered(bool))); connect(d->m_DrawPolygon, SIGNAL(triggered(bool)), this, SLOT(OnDrawPolygonTriggered(bool))); connect(d->m_DrawBezierCurve, SIGNAL(triggered(bool)), this, SLOT(OnDrawBezierCurveTriggered(bool))); connect(d->m_DrawSubdivisionPolygon, SIGNAL(triggered(bool)), this, SLOT(OnDrawSubdivisionPolygonTriggered(bool))); connect(d->m_CopyToClipboard, SIGNAL(clicked(bool)), this, SLOT(OnCopyToClipboard(bool))); } +void QmitkMeasurementView::OnCurrentSelectionChanged(QList nodes) +{ + if (nodes.empty() || nodes.front().IsNull()) + { + d->m_SelectedImageNode = nullptr; + d->m_DrawActionsToolBar->setEnabled(false); + } + else + { + d->m_SelectedImageNode = nodes.front(); + d->m_DrawActionsToolBar->setEnabled(true); + } +} + void QmitkMeasurementView::NodeAdded(const mitk::DataNode* node) { // add observer for selection in renderwindow mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(node->GetData()); auto isPositionMarker = false; node->GetBoolProperty("isContourMarker", isPositionMarker); if (planarFigure.IsNotNull() && !isPositionMarker) { auto nonConstNode = const_cast(node); mitk::PlanarFigureInteractor::Pointer interactor = dynamic_cast(node->GetDataInteractor().GetPointer()); if (interactor.IsNull()) { interactor = mitk::PlanarFigureInteractor::New(); auto planarFigureModule = us::ModuleRegistry::GetModule("MitkPlanarFigure"); interactor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule); interactor->SetEventConfig("PlanarFigureConfig.xml", planarFigureModule); } interactor->SetDataNode(nonConstNode); QmitkPlanarFigureData data; data.m_Figure = planarFigure; typedef itk::SimpleMemberCommand SimpleCommandType; typedef itk::MemberCommand MemberCommandType; // add observer for event when figure has been placed auto initializationCommand = SimpleCommandType::New(); initializationCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureInitialized); data.m_EndPlacementObserverTag = planarFigure->AddObserver(mitk::EndPlacementPlanarFigureEvent(), initializationCommand); // add observer for event when figure is picked (selected) auto selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureSelected); data.m_SelectObserverTag = planarFigure->AddObserver(mitk::SelectPlanarFigureEvent(), selectCommand); // add observer for event when interaction with figure starts auto startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction(this, &QmitkMeasurementView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = planarFigure->AddObserver(mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand); // add observer for event when interaction with figure starts auto endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction(this, &QmitkMeasurementView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = planarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand); // adding to the map of tracked planarfigures d->m_DataNodeToPlanarFigureData[nonConstNode] = data; } - - this->CheckForTopMostVisibleImage(); } void QmitkMeasurementView::NodeChanged(const mitk::DataNode* node) { - // DETERMINE IF WE HAVE TO RENEW OUR DETAILS TEXT (ANY NODE CHANGED IN OUR SELECTION?) - auto renewText = false; - - for (int i = 0; i < d->m_CurrentSelection.size(); ++i) + auto it = std::find(d->m_CurrentSelection.begin(), d->m_CurrentSelection.end(), node); + if (it != d->m_CurrentSelection.end()) { - if (node == d->m_CurrentSelection[i]) - { - renewText = true; - break; - } - } - - if (renewText) this->UpdateMeasurementText(); - - this->CheckForTopMostVisibleImage(); -} - -void QmitkMeasurementView::CheckForTopMostVisibleImage(mitk::DataNode* nodeToNeglect) -{ - d->m_SelectedImageNode = this->DetectTopMostVisibleImage(); - - if (d->m_SelectedImageNode.GetPointer() == nodeToNeglect) - d->m_SelectedImageNode = nullptr; - - auto isImage = mitk::TNodePredicateDataType::New(); - auto isHelpherObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)); - auto isNotHelpherObject = mitk::NodePredicateNot::New(isHelpherObject); - - auto nodeElements = this->GetDataStorage()->GetSubset(isNotHelpherObject); - - if (d->m_SelectedImageNode.IsNotNull() && d->m_UnintializedPlanarFigure == false) - { - d->m_SelectedImageLabel->setText(QString::fromStdString(d->m_SelectedImageNode->GetName())); - d->m_DrawActionsToolBar->setEnabled(true); - } - else if (d->m_UnintializedPlanarFigure == false && nodeElements->size() != 0) - { - d->m_SelectedImageLabel->setText(tr("Working without an image...")); - d->m_DrawActionsToolBar->setEnabled(true); - } - else - { - if (d->m_UnintializedPlanarFigure == false) - d->m_SelectedImageLabel->setText(tr("No visible data available.")); - - d->m_DrawActionsToolBar->setEnabled(false); } } void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* node) { auto nonConstNode = const_cast(node); auto it = d->m_DataNodeToPlanarFigureData.find(nonConstNode); auto isFigureFinished = false; auto isPlaced = false; if (it != d->m_DataNodeToPlanarFigureData.end()) { QmitkPlanarFigureData& data = it->second; data.m_Figure->RemoveObserver(data.m_EndPlacementObserverTag); data.m_Figure->RemoveObserver(data.m_SelectObserverTag); data.m_Figure->RemoveObserver(data.m_StartInteractionObserverTag); data.m_Figure->RemoveObserver(data.m_EndInteractionObserverTag); isFigureFinished = data.m_Figure->GetPropertyList()->GetBoolProperty("initiallyplaced", isPlaced); if (!isFigureFinished) // if the property does not yet exist or is false, drop the datanode this->PlanarFigureInitialized(); // normally called when a figure is finished, to reset all buttons d->m_DataNodeToPlanarFigureData.erase( it ); } if (nonConstNode != nullptr) nonConstNode->SetDataInteractor(nullptr); auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto nodes = this->GetDataStorage()->GetDerivations(node, isPlanarFigure); for (unsigned int x = 0; x < nodes->size(); ++x) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(nodes->at(x)->GetData()); if (planarFigure.IsNotNull()) { isFigureFinished = planarFigure->GetPropertyList()->GetBoolProperty("initiallyplaced",isPlaced); if (!isFigureFinished) // if the property does not yet exist or is false, drop the datanode { this->GetDataStorage()->Remove(nodes->at(x)); if (!d->m_DataNodeToPlanarFigureData.empty()) { it = d->m_DataNodeToPlanarFigureData.find(nodes->at(x)); if (it != d->m_DataNodeToPlanarFigureData.end()) { d->m_DataNodeToPlanarFigureData.erase(it); this->PlanarFigureInitialized(); // normally called when a figure is finished, to reset all buttons this->EnableCrosshairNavigation(); } } } } } - - this->CheckForTopMostVisibleImage(nonConstNode); } void QmitkMeasurementView::PlanarFigureSelected(itk::Object* object, const itk::EventObject&) { d->m_CurrentSelection.clear(); - auto it = d->m_DataNodeToPlanarFigureData.begin(); - - while (it != d->m_DataNodeToPlanarFigureData.end()) + auto lambda = [&object](const std::pair& element) { - auto node = it->first; - QmitkPlanarFigureData& data = it->second; - - if (data.m_Figure == object ) - { - node->SetSelected(true); - d->m_CurrentSelection.push_back( node ); - } - else - { - node->SetSelected(false); - } + return element.second.m_Figure == object; + }; - ++it; + auto it = std::find_if(d->m_DataNodeToPlanarFigureData.begin(), d->m_DataNodeToPlanarFigureData.end(), lambda); + if (it != d->m_DataNodeToPlanarFigureData.end()) + { + d->m_CurrentSelection.push_back(it->first); } this->UpdateMeasurementText(); this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::PlanarFigureInitialized() { d->m_UnintializedPlanarFigure = false; d->m_DrawActionsToolBar->setEnabled(true); d->m_DrawLine->setChecked(false); d->m_DrawPath->setChecked(false); d->m_DrawAngle->setChecked(false); d->m_DrawFourPointAngle->setChecked(false); d->m_DrawCircle->setChecked(false); d->m_DrawEllipse->setChecked(false); d->m_DrawDoubleEllipse->setChecked(false); d->m_DrawRectangle->setChecked(false); d->m_DrawPolygon->setChecked(false); d->m_DrawBezierCurve->setChecked(false); d->m_DrawSubdivisionPolygon->setChecked(false); } -void QmitkMeasurementView::SetFocus() -{ - d->m_SelectedImageLabel->setFocus(); -} - void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { - this->CheckForTopMostVisibleImage(); - d->m_CurrentSelection = nodes; this->UpdateMeasurementText(); // bug 16600: deselecting all planarfigures by clicking on datamanager when no node is selected if (d->m_CurrentSelection.size() == 0) { - // bug 18440: resetting the selected image label here because unselecting the - // current node did not reset the label - d->m_SelectedImageLabel->setText(tr("No visible image available.")); - auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto planarFigures = this->GetDataStorage()->GetSubset(isPlanarFigure); // setting all planar figures which are not helper objects not selected for (mitk::DataStorage::SetOfObjects::ConstIterator it = planarFigures->Begin(); it != planarFigures->End(); ++it) { auto node = it.Value(); auto isHelperObject = false; node->GetBoolProperty("helper object", isHelperObject); if (!isHelperObject) node->SetSelected(false); } } for (int i = d->m_CurrentSelection.size() - 1; i >= 0; --i) { auto node = d->m_CurrentSelection[i]; mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(node->GetData()); // the last selected planar figure - if (planarFigure.IsNotNull() && planarFigure->GetPlaneGeometry()) { auto planarFigureInitializedWindow = false; auto linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart()); QmitkRenderWindow* selectedRenderWindow; if (!linkedRenderWindow) return; auto axialRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("axial"); auto sagittalRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("sagittal"); auto coronalRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("coronal"); auto threeDimRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("3d"); if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, threeDimRenderWindow->GetRenderer())) { selectedRenderWindow = threeDimRenderWindow; } else { selectedRenderWindow = nullptr; } auto planeGeometry = dynamic_cast(planarFigure->GetPlaneGeometry()); auto normal = planeGeometry->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer axialPlane = axialRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto axialNormal = axialPlane->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer sagittalPlane = sagittalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto sagittalNormal = sagittalPlane->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer coronalPlane = coronalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto coronalNormal = coronalPlane->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); axialNormal[0] = fabs(axialNormal[0]); axialNormal[1] = fabs(axialNormal[1]); axialNormal[2] = fabs(axialNormal[2]); sagittalNormal[0] = fabs(sagittalNormal[0]); sagittalNormal[1] = fabs(sagittalNormal[1]); sagittalNormal[2] = fabs(sagittalNormal[2]); coronalNormal[0] = fabs(coronalNormal[0]); coronalNormal[1] = fabs(coronalNormal[1]); coronalNormal[2] = fabs(coronalNormal[2]); auto ang1 = angle(normal, axialNormal); auto ang2 = angle(normal, sagittalNormal); auto ang3 = angle(normal, coronalNormal); if (ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = axialRenderWindow; } else { if (ang2 < ang3) { selectedRenderWindow = sagittalRenderWindow; } else { selectedRenderWindow = coronalRenderWindow; } } // re-orient view if (selectedRenderWindow) selectedRenderWindow->GetSliceNavigationController()->ReorientSlices(planeGeometry->GetOrigin(), planeGeometry->GetNormal()); } break; } this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::OnDrawLineTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarLine::New(), QString("Line%1").arg(++d->m_LineCounter)); } void QmitkMeasurementView::OnDrawPathTriggered(bool) { auto propertyFilters = mitk::CoreServices::GetPropertyFilters(); if (propertyFilters != nullptr) { mitk::PropertyFilter filter; filter.AddEntry("ClosedPlanarPolygon", mitk::PropertyFilter::Blacklist); propertyFilters->AddFilter(filter, "PlanarPolygon"); } mitk::PlanarPolygon::Pointer planarFigure = mitk::PlanarPolygon::New(); planarFigure->ClosedOff(); auto node = this->AddFigureToDataStorage( planarFigure, QString("Path%1").arg(++d->m_PathCounter)); node->SetProperty("ClosedPlanarPolygon", mitk::BoolProperty::New(false)); node->SetProperty("planarfigure.isextendable", mitk::BoolProperty::New(true)); } void QmitkMeasurementView::OnDrawAngleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarAngle::New(), QString("Angle%1").arg(++d->m_AngleCounter)); } void QmitkMeasurementView::OnDrawFourPointAngleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarFourPointAngle::New(), QString("Four Point Angle%1").arg(++d->m_FourPointAngleCounter)); } void QmitkMeasurementView::OnDrawCircleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarCircle::New(), QString("Circle%1").arg(++d->m_CircleCounter)); } void QmitkMeasurementView::OnDrawEllipseTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarEllipse::New(), QString("Ellipse%1").arg(++d->m_EllipseCounter)); } void QmitkMeasurementView::OnDrawDoubleEllipseTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarDoubleEllipse::New(), QString("DoubleEllipse%1").arg(++d->m_DoubleEllipseCounter)); } void QmitkMeasurementView::OnDrawBezierCurveTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarBezierCurve::New(), QString("BezierCurve%1").arg(++d->m_BezierCurveCounter)); } void QmitkMeasurementView::OnDrawSubdivisionPolygonTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarSubdivisionPolygon::New(), QString("SubdivisionPolygon%1").arg(++d->m_SubdivisionPolygonCounter)); } void QmitkMeasurementView::OnDrawRectangleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarRectangle::New(), QString("Rectangle%1").arg(++d->m_RectangleCounter)); } void QmitkMeasurementView::OnDrawPolygonTriggered(bool) { auto planarFigure = mitk::PlanarPolygon::New(); planarFigure->ClosedOn(); auto node = this->AddFigureToDataStorage( planarFigure, QString("Polygon%1").arg(++d->m_PolygonCounter)); node->SetProperty("planarfigure.isextendable", mitk::BoolProperty::New(true)); } void QmitkMeasurementView::OnCopyToClipboard(bool) { QApplication::clipboard()->setText(d->m_SelectedPlanarFiguresText->toPlainText(), QClipboard::Clipboard); } mitk::DataNode::Pointer QmitkMeasurementView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name) { auto newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->SetSelected(true); if (d->m_SelectedImageNode.IsNotNull()) { this->GetDataStorage()->Add(newNode, d->m_SelectedImageNode); } else { this->GetDataStorage()->Add(newNode); } for (auto &node : d->m_CurrentSelection) node->SetSelected(false); d->m_CurrentSelection.clear(); d->m_CurrentSelection.push_back(newNode); this->UpdateMeasurementText(); this->DisableCrosshairNavigation(); d->m_DrawActionsToolBar->setEnabled(false); d->m_UnintializedPlanarFigure = true; return newNode; } void QmitkMeasurementView::UpdateMeasurementText() { d->m_SelectedPlanarFiguresText->clear(); QString infoText; QString plainInfoText; int j = 1; mitk::PlanarFigure::Pointer planarFigure; mitk::PlanarAngle::Pointer planarAngle; mitk::PlanarFourPointAngle::Pointer planarFourPointAngle; mitk::DataNode::Pointer node; for (int i = 0; i < d->m_CurrentSelection.size(); ++i, ++j) { plainInfoText.clear(); node = d->m_CurrentSelection[i]; planarFigure = dynamic_cast(node->GetData()); if (planarFigure.IsNull()) continue; if (j > 1) infoText.append("
"); infoText.append(QString("%1
").arg(QString::fromStdString(node->GetName()))); plainInfoText.append(QString("%1").arg(QString::fromStdString(node->GetName()))); planarAngle = dynamic_cast (planarFigure.GetPointer()); if (planarAngle.IsNull()) planarFourPointAngle = dynamic_cast (planarFigure.GetPointer()); double featureQuantity = 0.0; for (unsigned int k = 0; k < planarFigure->GetNumberOfFeatures(); ++k) { if (!planarFigure->IsFeatureActive(k)) continue; featureQuantity = planarFigure->GetQuantity(k); if ((planarAngle.IsNotNull() && k == planarAngle->FEATURE_ID_ANGLE) || (planarFourPointAngle.IsNotNull() && k == planarFourPointAngle->FEATURE_ID_ANGLE)) featureQuantity = featureQuantity * 180 / vnl_math::pi; infoText.append(QString("%1: %2 %3") .arg(QString(planarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(planarFigure->GetFeatureUnit(k)))); plainInfoText.append(QString("\n%1: %2 %3") .arg(QString(planarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(planarFigure->GetFeatureUnit(k)))); if (k + 1 != planarFigure->GetNumberOfFeatures()) infoText.append("
"); } if (j != d->m_CurrentSelection.size()) infoText.append("
"); } d->m_SelectedPlanarFiguresText->setHtml(infoText); } void QmitkMeasurementView::AddAllInteractors() { auto planarFigures = this->GetAllPlanarFigures(); for (auto it = planarFigures->Begin(); it != planarFigures->End(); ++it) this->NodeAdded(it.Value()); } -mitk::DataNode::Pointer QmitkMeasurementView::DetectTopMostVisibleImage() -{ - // get all images from the data storage which are not a segmentation - auto isImage = mitk::TNodePredicateDataType::New(); - auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); - auto isNotBinary = mitk::NodePredicateNot::New(isBinary); - auto isNormalImage = mitk::NodePredicateAnd::New(isImage, isNotBinary); - - auto images = this->GetDataStorage()->GetSubset(isNormalImage); - - mitk::DataNode::Pointer currentNode; - - int maxLayer = std::numeric_limits::min(); - int layer = 0; - - // iterate over selection - for (auto it = images->Begin(); it != images->End(); ++it) - { - auto node = it->Value(); - - if (node.IsNull()) - continue; - - if (node->IsVisible(nullptr) == false) - continue; - - // we also do not want to assign planar figures to helper objects ( even if they are of type image ) - if (node->GetProperty("helper object") != nullptr) - continue; - - node->GetIntProperty("layer", layer); - - if (layer < maxLayer) - { - continue; - } - else - { - maxLayer = layer; - currentNode = node; - } - } - - return currentNode; -} - void QmitkMeasurementView::EnableCrosshairNavigation() { // enable the crosshair navigation // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools // in new interaction framework for (const auto& displayInteractorConfig : m_DisplayInteractorConfigs) { if (displayInteractorConfig.first) { auto displayInteractor = static_cast(us::GetModuleContext()->GetService(displayInteractorConfig.first)); if (displayInteractor != nullptr) { // here the regular configuration is loaded again displayInteractor->SetEventConfig(displayInteractorConfig.second); } } } m_DisplayInteractorConfigs.clear(); d->m_ScrollEnabled = true; } void QmitkMeasurementView::DisableCrosshairNavigation() { // dont deactivate twice, else we will clutter the config list ... if (d->m_ScrollEnabled == false) return; // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts with tools // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction will still be enabled m_DisplayInteractorConfigs.clear(); auto eventObservers = us::GetModuleContext()->GetServiceReferences(); for (const auto& eventObserver : eventObservers) { auto displayInteractor = dynamic_cast(us::GetModuleContext()->GetService(eventObserver)); if (displayInteractor != nullptr) { // remember the original configuration m_DisplayInteractorConfigs.insert(std::make_pair(eventObserver, displayInteractor->GetEventConfig())); // here the alternative configuration is loaded displayInteractor->SetEventConfig("DisplayConfigMITKLimited.xml"); } } d->m_ScrollEnabled = false; } mitk::DataStorage::SetOfObjects::ConstPointer QmitkMeasurementView::GetAllPlanarFigures() const { auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto isNotHelperObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(false)); auto isNotHelperButPlanarFigure = mitk::NodePredicateAnd::New( isPlanarFigure, isNotHelperObject ); return this->GetDataStorage()->GetSubset(isPlanarFigure); } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h index 70d9eafd17..706d9e13d7 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.h @@ -1,87 +1,96 @@ /*============================================================================ 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 QMITK_MEASUREMENT_H__INCLUDED #define QMITK_MEASUREMENT_H__INCLUDED #include #include #include "usServiceRegistration.h" /// forward declarations struct QmitkMeasurementViewData; namespace mitk { class PlanarFigure; } /// /// A view for doing measurements in digital images by means of /// mitk::Planarfigures which can represent drawing primitives (Lines, circles, ...). /// The view consists of only three main elements: /// 1. A toolbar for activating PlanarFigure drawing /// 2. A textbrowser which shows details for the selected PlanarFigures /// 3. A button for copying all details to the clipboard /// class QmitkMeasurementView : public QmitkAbstractView { Q_OBJECT - public: +public: static const std::string VIEW_ID; QmitkMeasurementView(); ~QmitkMeasurementView() override; void CreateQtPartControl(QWidget* parent) override; - void SetFocus() override; + void SetFocus() override { }; void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; void NodeAdded(const mitk::DataNode* node) override; + /** + * @brief Determine if we have to update the information of the currently + * selected planar figures. + */ void NodeChanged(const mitk::DataNode* node) override; void NodeRemoved(const mitk::DataNode* node) override; void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); - protected slots: + +protected Q_SLOTS: + void OnDrawLineTriggered( bool checked = false ); void OnDrawPathTriggered( bool checked = false ); void OnDrawAngleTriggered( bool checked = false ); void OnDrawFourPointAngleTriggered( bool checked = false ); void OnDrawCircleTriggered( bool checked = false ); void OnDrawEllipseTriggered( bool checked = false ); void OnDrawDoubleEllipseTriggered( bool checked = false ); void OnDrawRectangleTriggered( bool checked = false ); void OnDrawPolygonTriggered( bool checked = false ); void OnDrawBezierCurveTriggered( bool checked = false ); void OnDrawSubdivisionPolygonTriggered( bool checked = false ); void OnCopyToClipboard( bool checked = false ); - private: +private: + void CreateConnections(); mitk::DataNode::Pointer AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name); + + void SetAsSelectionListener(bool checked); + void OnCurrentSelectionChanged(QList nodes); + void UpdateMeasurementText(); void AddAllInteractors(); - mitk::DataNode::Pointer DetectTopMostVisibleImage(); void EnableCrosshairNavigation(); void DisableCrosshairNavigation(); void PlanarFigureInitialized(); - void CheckForTopMostVisibleImage(mitk::DataNode* nodeToNeglect = nullptr); mitk::DataStorage::SetOfObjects::ConstPointer GetAllPlanarFigures() const; QmitkMeasurementViewData* d; // holds configuration objects that have been deactivated std::map m_DisplayInteractorConfigs; }; #endif // QMITK_MEASUREMENT_H__INCLUDED diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp index 7bf1533566..3259eceffc 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.cpp @@ -1,183 +1,224 @@ /*============================================================================ 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 "QmitkDataSelectionWidget.h" #include "internal/mitkPluginActivator.h" #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include static mitk::NodePredicateBase::Pointer CreatePredicate(QmitkDataSelectionWidget::PredicateType predicateType) { mitk::NodePredicateAnd::Pointer segmentationPredicate = mitk::NodePredicateAnd::New(); segmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); segmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::NodePredicateAnd::Pointer maskPredicate = mitk::NodePredicateAnd::New(); maskPredicate->AddPredicate(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true))); maskPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(isImage); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); mitk::NodePredicateAnd::Pointer imagePredicate = mitk::NodePredicateAnd::New(); imagePredicate->AddPredicate(validImages); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(segmentationPredicate)); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)))); imagePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); mitk::NodePredicateAnd::Pointer surfacePredicate = mitk::NodePredicateAnd::New(); surfacePredicate->AddPredicate(mitk::TNodePredicateDataType::New()); surfacePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true)))); switch(predicateType) { case QmitkDataSelectionWidget::ImagePredicate: return imagePredicate.GetPointer(); case QmitkDataSelectionWidget::MaskPredicate: return maskPredicate.GetPointer(); case QmitkDataSelectionWidget::SegmentationPredicate: return segmentationPredicate.GetPointer(); case QmitkDataSelectionWidget::SurfacePredicate: return surfacePredicate.GetPointer(); default: assert(false && "Unknown predefined predicate!"); return nullptr; } } QmitkDataSelectionWidget::QmitkDataSelectionWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); m_Controls.helpLabel->hide(); } QmitkDataSelectionWidget::~QmitkDataSelectionWidget() { } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(QmitkDataSelectionWidget::PredicateType predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(QmitkDataSelectionWidget::PredicateType predicate) { - return this->AddDataStorageComboBox("", predicate); + QString hint = "Select node"; + QString popupTitel = "Select node"; + + switch (predicate) + { + case QmitkDataSelectionWidget::ImagePredicate: + hint = "Select an image"; + popupTitel = "Select an image"; + break; + + case QmitkDataSelectionWidget::MaskPredicate: + hint = "Select a binary mask"; + popupTitel = "Select a binary mask"; + break; + + case QmitkDataSelectionWidget::SegmentationPredicate: + hint = "Select an ML segmentation"; + popupTitel = "Select an ML segmentation"; + break; + + case QmitkDataSelectionWidget::SurfacePredicate: + hint = "Select a surface"; + popupTitel = "Select a surface"; + break; + } + + return this->AddDataSelection("", hint, popupTitel, "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(mitk::NodePredicateBase* predicate) { - return this->AddDataStorageComboBox("", predicate); + return this->AddDataSelection("", "Select a node", "Select a node", "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, QmitkDataSelectionWidget::PredicateType predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, QmitkDataSelectionWidget::PredicateType predicate) { - return this->AddDataStorageComboBox(labelText, CreatePredicate(predicate)); + return this->AddDataSelection(labelText, info, popupHint, popupTitel, CreatePredicate(predicate)); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate) { int row = m_Controls.gridLayout->rowCount(); if (!labelText.isEmpty()) { QLabel* label = new QLabel(labelText, m_Controls.dataSelectionWidget); label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); m_Controls.gridLayout->addWidget(label, row, 0); } - QmitkDataStorageComboBox* comboBox = new QmitkDataStorageComboBox(this->GetDataStorage(), predicate, m_Controls.dataSelectionWidget); - connect(comboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSelectionChanged(const mitk::DataNode *))); - comboBox->SetAutoSelectNewItems(true); - m_Controls.gridLayout->addWidget(comboBox, row, 1); + QmitkSingleNodeSelectionWidget* nodeSelection = new QmitkSingleNodeSelectionWidget(m_Controls.dataSelectionWidget); - m_DataStorageComboBoxes.push_back(comboBox); - return static_cast(m_DataStorageComboBoxes.size() - 1); + nodeSelection->SetSelectionIsOptional(false); + nodeSelection->SetAutoSelectNewNodes(false); + nodeSelection->SetInvalidInfo(info); + nodeSelection->SetPopUpTitel(popupTitel); + nodeSelection->SetPopUpHint(popupHint); + nodeSelection->SetDataStorage(this->GetDataStorage()); + nodeSelection->SetNodePredicate(predicate); + nodeSelection->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + nodeSelection->setMinimumSize(0, 40); + + connect(nodeSelection, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSelectionChanged(QList))); + m_Controls.gridLayout->addWidget(nodeSelection, row, 1); + + m_NodeSelectionWidgets.push_back(nodeSelection); + return static_cast(m_NodeSelectionWidgets.size() - 1); } mitk::DataStorage::Pointer QmitkDataSelectionWidget::GetDataStorage() const { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); assert(ref == true); mitk::IDataStorageService* service = mitk::PluginActivator::getContext()->getService(ref); assert(service); return service->GetDefaultDataStorage()->GetDataStorage(); } mitk::DataNode::Pointer QmitkDataSelectionWidget::GetSelection(unsigned int index) { - assert(index < m_DataStorageComboBoxes.size()); - return m_DataStorageComboBoxes[index]->GetSelectedNode(); + assert(index < m_NodeSelectionWidgets.size()); + return m_NodeSelectionWidgets[index]->GetSelectedNode(); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, PredicateType predicate) { this->SetPredicate(index, CreatePredicate(predicate)); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate) { - assert(index < m_DataStorageComboBoxes.size()); - m_DataStorageComboBoxes[index]->SetPredicate(predicate); + assert(index < m_NodeSelectionWidgets.size()); + m_NodeSelectionWidgets[index]->SetNodePredicate(predicate); } void QmitkDataSelectionWidget::SetHelpText(const QString& text) { if (!text.isEmpty()) { m_Controls.helpLabel->setText(text); if (!m_Controls.helpLabel->isVisible()) m_Controls.helpLabel->show(); } else { m_Controls.helpLabel->hide(); } } -void QmitkDataSelectionWidget::OnSelectionChanged(const mitk::DataNode* selection) +void QmitkDataSelectionWidget::OnSelectionChanged(QList selection) { - std::vector::iterator it = std::find(m_DataStorageComboBoxes.begin(), m_DataStorageComboBoxes.end(), sender()); - assert(it != m_DataStorageComboBoxes.end()); + std::vector::iterator it = std::find(m_NodeSelectionWidgets.begin(), m_NodeSelectionWidgets.end(), sender()); + assert(it != m_NodeSelectionWidgets.end()); - emit SelectionChanged(std::distance(m_DataStorageComboBoxes.begin(), it), selection); + const mitk::DataNode* result = nullptr; + if (!selection.empty()) + { + result = selection.front(); + } + emit SelectionChanged(std::distance(m_NodeSelectionWidgets.begin(), it), result); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h index 23502425f4..2b485e207e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidget.h @@ -1,66 +1,66 @@ /*============================================================================ 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 QmitkDataSelectionWidget_h #define QmitkDataSelectionWidget_h #include #include #include #include namespace mitk { class NodePredicateBase; } -class QmitkDataStorageComboBox; +class QmitkSingleNodeSelectionWidget; class QmitkDataSelectionWidget : public QWidget { Q_OBJECT public: enum PredicateType { ImagePredicate, MaskPredicate, SegmentationPredicate, SurfacePredicate }; explicit QmitkDataSelectionWidget(QWidget* parent = nullptr); ~QmitkDataSelectionWidget() override; - unsigned int AddDataStorageComboBox(PredicateType predicate); - unsigned int AddDataStorageComboBox(mitk::NodePredicateBase* predicate = nullptr); - unsigned int AddDataStorageComboBox(const QString &labelText, PredicateType predicate); - unsigned int AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataSelection(PredicateType predicate); + unsigned int AddDataSelection(mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, PredicateType predicate); + unsigned int AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate = nullptr); mitk::DataStorage::Pointer GetDataStorage() const; mitk::DataNode::Pointer GetSelection(unsigned int index); void SetPredicate(unsigned int index, PredicateType predicate); void SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate); void SetHelpText(const QString& text); signals: void SelectionChanged(unsigned int index, const mitk::DataNode* selection); private slots: - void OnSelectionChanged(const mitk::DataNode* selection); + void OnSelectionChanged(QList selection); private: Ui::QmitkDataSelectionWidgetControls m_Controls; - std::vector m_DataStorageComboBoxes; + std::vector m_NodeSelectionWidgets; }; #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui index 1849a496d9..95f4cf4bf3 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui @@ -1,64 +1,82 @@ QmitkDataSelectionWidgetControls 0 0 333 191 - + + 0 + + + 0 + + + 0 + + 0 Data Selection - + + 0 + + + 0 + + + 0 + + 0 - + 0 0 color: red true diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui index 8f55f99d5d..cfa09e6ac2 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationControls.ui @@ -1,760 +1,761 @@ QmitkMultiLabelSegmentationControls 0 0 459 844 0 0 0 0 MS Shell Dlg 2 8 50 false false false false QmitkSegmentation 0 0 Data Selection Patient Image - - - - 0 - 0 - - - + + + + 0 + 40 + + + Create a new segmentation session ... :/multilabelsegmentation/NewSegmentationSession_48x48.png:/multilabelsegmentation/NewSegmentationSession_48x48.png 28 28 N true Segmentation - - - - 0 - 0 - - - + + + + 0 + 40 + + + Layers true false Add a layer to the current segmentation session ... :/Qmitk/AddLayer_48x48.png:/Qmitk/AddLayer_48x48.png 28 28 true Delete the active layer ... :/Qmitk/DeleteLayer_48x48.png:/Qmitk/DeleteLayer_48x48.png 28 28 true Qt::Horizontal 0 20 Change to the previous available layer ... :/Qmitk/PreviousLayer_48x48.png:/Qmitk/PreviousLayer_48x48.png 28 28 true Change to the next available layer ... :/Qmitk/NextLayer_48x48.png:/Qmitk/NextLayer_48x48.png 28 28 true 0 0 50 30 40 30 12 Switch to a layer 0 Labels true Add a new label to the current segmentation session ... :/multilabelsegmentation/NewLabel_48x48.png:/multilabelsegmentation/NewLabel_48x48.png 28 28 N true Lock/Unlock exterior ... :/Qmitk/UnlockExterior_48x48.png :/Qmitk/LockExterior_48x48.png:/Qmitk/UnlockExterior_48x48.png 28 28 true true Qt::Horizontal 0 20 0 34 Show a table with all labels in the current segmentation session >> 28 28 true false Qt::NoArrow 0 0 0 20 0 0 QTabWidget::tab-bar { alignment: middle; } 0 true false 2D Tools 0 0 50 false 0 0 50 false Qt::Vertical 20 40 3D Tools 0 0 50 false 0 0 50 false Qt::Vertical 20 40 0 0 Interpolation 2 QLayout::SetMinimumSize 2 2 2 2 0 0 Disabled 2D Interpolation 3D Interpolation 0 0 1 0 0 QLayout::SetMinimumSize 0 0 0 0 0 0 0 0 50 false 0 0 QLayout::SetMinimumSize 0 0 0 0 0 0 0 50 50 false 0 0 Qt::Vertical 20 40 m_LabelSetWidget groupBox_DataSelection m_tw2DTools m_gbInterpolation groupBox_Layer groupBox_Labels - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
- + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkLabelSetWidget QWidget
Qmitk/QmitkLabelSetWidget.h
1
QmitkSliceBasedInterpolatorWidget QWidget
QmitkSliceBasedInterpolatorWidget.h
1
QmitkSurfaceBasedInterpolatorWidget QWidget
QmitkSurfaceBasedInterpolatorWidget.h
1
QmitkToolReferenceDataSelectionBox.h QmitkToolGUIArea.h QmitkToolSelectionBox.h
diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp index 56f18be8af..3c7e865e3c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,1203 +1,1062 @@ /*============================================================================ 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 "QmitkMultiLabelSegmentationView.h" // blueberry #include #include // mitk #include "mitkApplicationCursor.h" #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" #include "mitkToolManagerProvider.h" -//#include "mitkSegmentationObjectFactory.h" #include "mitkInteractionEventObserver.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" #include "mitkSegTool2D.h" #include "mitkImageTimeSelector.h" +#include "mitkNodePredicateFunction.h" // Qmitk #include "QmitkNewSegmentationDialog.h" #include "QmitkRenderWindow.h" #include "QmitkSegmentationOrganNamesHandling.cpp" // us #include #include #include #include #include // Qt #include #include #include #include #include #include "tinyxml.h" #include #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : m_Parent(nullptr), m_IRenderWindowPart(nullptr), m_ToolManager(nullptr), m_ReferenceNode(nullptr), m_WorkingNode(nullptr), m_AutoSelectionEnabled(false), m_MouseCursorSet(false) { m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(isMask)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); } QmitkMultiLabelSegmentationView::~QmitkMultiLabelSegmentationView() { - // m_ToolManager->ActivateTool(-1); - /* - todo: check this - m_Controls.m_SliceBasedInterpolatorWidget->EnableInterpolation(false); - ctkPluginContext* context = mitk::PluginActivator::getContext(); - ctkServiceReference ppmRef = context->getServiceReference(); - mitk::PlanePositionManagerService* service = context->getService(ppmRef); - service->RemoveAllPlanePositions(); - context->ungetService(ppmRef); - */ - // m_ToolManager->SetReferenceData(nullptr); - // m_ToolManager->SetWorkingData(nullptr); - - // m_ServiceRegistration.Unregister(); - // Loose LabelSetConnections OnLooseLabelSetConnection(); } void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls.setupUi(parent); // *------------------------ // * Shortcuts // *------------------------ QShortcut* visibilityShortcut = new QShortcut(QKeySequence("CTRL+H"), parent); connect(visibilityShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated); QShortcut* labelToggleShortcut = new QShortcut(QKeySequence("CTRL+L"), parent); connect(labelToggleShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated); // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ - m_Controls.m_cbReferenceNodeSelector->SetAutoSelectNewItems(true); - m_Controls.m_cbReferenceNodeSelector->SetPredicate(m_ReferencePredicate); - m_Controls.m_cbReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ReferenceNodeSelector->SetNodePredicate(m_ReferencePredicate); + m_Controls.m_ReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_ReferenceNodeSelector->SetInvalidInfo("Select an image"); + m_Controls.m_ReferenceNodeSelector->SetPopUpTitel("Select an image"); + m_Controls.m_ReferenceNodeSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); + - m_Controls.m_cbWorkingNodeSelector->SetAutoSelectNewItems(true); - m_Controls.m_cbWorkingNodeSelector->SetPredicate(m_SegmentationPredicate); - m_Controls.m_cbWorkingNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_WorkingNodeSelector->SetNodePredicate(m_SegmentationPredicate); + m_Controls.m_WorkingNodeSelector->SetDataStorage(this->GetDataStorage()); + m_Controls.m_WorkingNodeSelector->SetInvalidInfo("Select a segmentation"); + m_Controls.m_WorkingNodeSelector->SetPopUpTitel("Select a segmentation"); + m_Controls.m_WorkingNodeSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); - connect(m_Controls.m_cbReferenceNodeSelector, - SIGNAL(OnSelectionChanged(const mitk::DataNode *)), + connect(m_Controls.m_ReferenceNodeSelector, + SIGNAL(CurrentSelectionChanged(QList)), this, - SLOT(OnReferenceSelectionChanged(const mitk::DataNode *))); + SLOT(OnReferenceSelectionChanged(QList))); - connect(m_Controls.m_cbWorkingNodeSelector, - SIGNAL(OnSelectionChanged(const mitk::DataNode *)), + connect(m_Controls.m_WorkingNodeSelector, + SIGNAL(CurrentSelectionChanged(QList)), this, - SLOT(OnSegmentationSelectionChanged(const mitk::DataNode *))); + SLOT(OnSegmentationSelectionChanged(QList))); // *------------------------ // * ToolManager // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); // use the same ToolManager instance for our 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); // *------------------------ // * LabelSetWidget // *------------------------ m_Controls.m_LabelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls.m_LabelSetWidget->SetOrganColors(mitk::OrganNamesHandling::GetDefaultOrganColorString()); m_Controls.m_LabelSetWidget->hide(); // *------------------------ // * Interpolation // *------------------------ m_Controls.m_SurfaceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); m_Controls.m_SliceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); connect(m_Controls.m_cbInterpolation, SIGNAL(activated(int)), this, SLOT(OnInterpolationSelectionChanged(int))); m_Controls.m_cbInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->hide(); QString segTools2D = tr("Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D Correction 'Live Wire'"); QString segTools3D = tr("Threshold 'Two Thresholds' 'Auto Threshold' 'Multiple Otsu'"); std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = m_ToolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // *------------------------ // * ToolSelection 2D // *------------------------ m_Controls.m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer2D); m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); // todo: "Correction // 'Live Wire'" m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls.m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int))); // *------------------------ // * ToolSelection 3D // *------------------------ m_Controls.m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer3D); m_Controls.m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); // todo add : FastMarching3D RegionGrowing Watershed m_Controls.m_ManualToolSelectionBox3D->SetLayoutColumns(2); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); // *------------------------* // * Connect PushButtons (pb) // *------------------------* connect(m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT(OnNewLabel())); connect(m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT(OnNewSegmentationSession())); connect(m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT(OnShowLabelTable(bool))); // *------------------------* // * Connect LabelSetWidget // *------------------------* connect(m_Controls.m_LabelSetWidget, SIGNAL(goToLabel(const mitk::Point3D &)), this, SLOT(OnGoToLabel(const mitk::Point3D &))); connect(m_Controls.m_LabelSetWidget, SIGNAL(resetView()), this, SLOT(OnResetView())); // *------------------------* // * DATA SLECTION WIDGET // *------------------------* m_IRenderWindowPart = this->GetRenderWindowPart(); if (m_IRenderWindowPart) { QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); - // m_Controls.m_LabelSetWidget->SetRenderWindowPart(this->m_IRenderWindowPart); } // this->InitializeListeners(); connect(m_Controls.m_btAddLayer, SIGNAL(clicked()), this, SLOT(OnAddLayer())); connect(m_Controls.m_btDeleteLayer, SIGNAL(clicked()), this, SLOT(OnDeleteLayer())); connect(m_Controls.m_btPreviousLayer, SIGNAL(clicked()), this, SLOT(OnPreviousLayer())); connect(m_Controls.m_btNextLayer, SIGNAL(clicked()), this, SLOT(OnNextLayer())); connect(m_Controls.m_btLockExterior, SIGNAL(toggled(bool)), this, SLOT(OnLockExteriorToggled(bool))); connect(m_Controls.m_cbActiveLayer, SIGNAL(currentIndexChanged(int)), this, SLOT(OnChangeLayer(int))); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setEnabled(false); // Make sure the GUI notices if appropriate data is already present on creation - this->OnReferenceSelectionChanged(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); - this->OnSegmentationSelectionChanged(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); + m_Controls.m_ReferenceNodeSelector->SetAutoSelectNewNodes(true); + m_Controls.m_WorkingNodeSelector->SetAutoSelectNewNodes(true); } void QmitkMultiLabelSegmentationView::Activated() { - m_ToolManager->SetReferenceData(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); - m_ToolManager->SetWorkingData(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); + m_ToolManager->SetReferenceData(m_Controls.m_ReferenceNodeSelector->GetSelectedNode()); + m_ToolManager->SetWorkingData(m_Controls.m_WorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Deactivated() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Visible() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Hidden() { // Not yet implemented } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { if (!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if (width == false) { return 100; } else { return preferredResult; } } /************************************************************************/ /* protected slots */ /************************************************************************/ void QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); bool isVisible = false; workingNode->GetBoolProperty("visible", isVisible); workingNode->SetVisibility(!isVisible); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated() { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); WaitCursorOn(); workingImage->GetActiveLabelSet()->SetNextActiveLabel(); workingImage->Modified(); WaitCursorOff(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkMultiLabelSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } } void QmitkMultiLabelSegmentationView::OnNewLabel() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (!workingNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); if (!workingImage) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { return; } QString segName = dialog->GetSegmentationName(); if (segName.isEmpty()) { segName = "Unnamed"; } workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(workingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkMultiLabelSegmentationView::OnShowLabelTable(bool value) { if (value) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { - mitk::DataNode *referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); + mitk::DataNode *referenceNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); if (!referenceNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } m_ToolManager->ActivateTool(-1); mitk::Image::ConstPointer referenceImage = dynamic_cast(referenceNode->GetData()); assert(referenceImage); if (referenceImage->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Generate a static mask?"), tr("The selected image has multiple time steps. You can either generate a simple/static masks resembling the geometry of the first timestep of the image. Or you can generate a dynamic mask that equals the selected image in geometry and number of timesteps; thus a dynamic mask can change over time (e.g. according to the image)."), tr("Yes, generate a static mask"), tr("No, generate a dynamic mask"), QString(), 0, 0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(referenceImage); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = referenceImage->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(referenceImage->GetGeometry(), 0); newImage->SetTimeGeometry(newTimeGeometry); referenceImage = newImage; } } QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); if (!ok) { return; } this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "New Segmentation Session", "Could not create a new segmentation session.\n"); return; } this->WaitCursorOff(); mitk::DataNode::Pointer workingNode = mitk::DataNode::New(); workingNode->SetData(workingImage); workingNode->SetName(newName.toStdString()); workingImage->GetExteriorLabel()->SetProperty("name.parent", mitk::StringProperty::New(referenceNode->GetName().c_str())); workingImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newName.toStdString().c_str())); if (!GetDataStorage()->Exists(workingNode)) { GetDataStorage()->Add(workingNode, referenceNode); } + m_Controls.m_WorkingNodeSelector->SetCurrentSelectedNode(workingNode); + OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_IRenderWindowPart) m_IRenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { if (m_IRenderWindowPart) m_IRenderWindowPart->ForceImmediateUpdate(); } void QmitkMultiLabelSegmentationView::OnAddLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QString question = "Do you really want to add a layer to the current segmentation session?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; try { WaitCursorOn(); workingImage->AddLayer(); WaitCursorOff(); } catch ( mitk::Exception& e ) { WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information( m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); if (workingImage->GetNumberOfLayers() < 2) return; QString question = "Do you really want to delete the current layer?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) { return; } try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Delete Layer", "Could not delete the currently active layer. See error log for details.\n"); return; } UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() - 1); } void QmitkMultiLabelSegmentationView::OnNextLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() + 1); } void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeactivateActiveTool() { m_ToolManager->ActivateTool(-1); } void QmitkMultiLabelSegmentationView::OnLockExteriorToggled(bool checked) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } -void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(const mitk::DataNode* node) +void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(QList /*nodes*/) { m_ToolManager->ActivateTool(-1); - m_ReferenceNode = const_cast(node); + auto refNode = m_Controls.m_ReferenceNodeSelector->GetSelectedNode(); + m_ReferenceNode = refNode; m_ToolManager->SetReferenceData(m_ReferenceNode); if (m_ReferenceNode.IsNotNull()) { - if (m_AutoSelectionEnabled) + auto geometryCheck = [refNode](const mitk::DataNode * segNode) { - // if an image is selected find a possible working / segmentation image - mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDataStorage()->GetDerivations(m_ReferenceNode, m_SegmentationPredicate); - if (derivations->Size() != 0) - { - // use the first segmentation child node - m_WorkingNode = derivations->ElementAt(0); - m_ToolManager->SetWorkingData(m_WorkingNode); + return QmitkMultiLabelSegmentationView::CheckForSameGeometry(refNode,segNode); + }; - m_Controls.m_cbWorkingNodeSelector->blockSignals(true); - m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(m_WorkingNode); - m_Controls.m_cbWorkingNodeSelector->blockSignals(false); - } - else if (derivations->size() == 0) - { - m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); - } + mitk::NodePredicateFunction::Pointer hasCorrectGeo = mitk::NodePredicateFunction::New(geometryCheck); + auto segPredicate = mitk::NodePredicateAnd::New(m_SegmentationPredicate.GetPointer(), hasCorrectGeo.GetPointer()); + + m_Controls.m_WorkingNodeSelector->SetNodePredicate(segPredicate); - // hide all image and segmentation nodes to later show only the automatically selected ones + if (m_AutoSelectionEnabled) + { + // hide all image nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) { (*iter)->SetVisibility(false); } - - mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) - { - (*iter)->SetVisibility(false); - } } m_ReferenceNode->SetVisibility(true); - - // check match of segmentation and reference image geometries - if (m_WorkingNode.IsNotNull()) - { - mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); - assert(workingImage); - - mitk::Image* referenceImage = dynamic_cast(node->GetData()); - assert(referenceImage); - - if (!this->CheckForSameGeometry(referenceImage, workingImage)) - { - return; - } - m_WorkingNode->SetVisibility(true); - } } UpdateControls(); - if (m_WorkingNode.IsNotNull()) - { - m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); - mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - } } -void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(const mitk::DataNode* node) +void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(QList /*nodes*/) { m_ToolManager->ActivateTool(-1); if (m_WorkingNode.IsNotNull()) OnLooseLabelSetConnection(); - m_WorkingNode = const_cast(node); + m_WorkingNode = m_Controls.m_WorkingNodeSelector->GetSelectedNode(); m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { OnEstablishLabelSetConnection(); if (m_AutoSelectionEnabled) { - // if a segmentation is selected find a possible reference image - mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(m_WorkingNode, m_ReferencePredicate); - if (sources->Size() != 0) - { - m_ReferenceNode = sources->ElementAt(0); - m_ToolManager->SetReferenceData(m_ReferenceNode); - - m_Controls.m_cbReferenceNodeSelector->blockSignals(true); - m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(m_ReferenceNode); - m_Controls.m_cbReferenceNodeSelector->blockSignals(false); - } - else if(sources->size() == 0) - { - m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); - } - - // hide all image and segmentation nodes to later show only the automatically selected ones - mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) - { - (*iter)->SetVisibility(false); - } - + // hide all segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_WorkingNode->SetVisibility(true); - - // check match of segmentation and reference image geometries - if (m_ReferenceNode.IsNotNull()) - { - mitk::Image* referenceImage = dynamic_cast(m_ReferenceNode->GetData()); - assert(referenceImage); - - mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); - assert(workingImage); - - if (!this->CheckForSameGeometry(referenceImage, workingImage)) - { - return; - } - m_ReferenceNode->SetVisibility(true); - } } UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); m_Controls.m_swInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->show(); } else if (index == 2) { m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(1); m_Controls.m_swInterpolation->show(); } else { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(2); m_Controls.m_swInterpolation->hide(); } } /************************************************************************/ /* protected */ /************************************************************************/ -void QmitkMultiLabelSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) -{ - if (m_AutoSelectionEnabled) - { - // automatically set the reference node and the working node of the multi label plugin - if (1 == nodes.size()) - { - mitk::DataNode::Pointer selectedNode = nodes.at(0); - if (selectedNode.IsNull()) - { - return; - } - - // check selected node - mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(selectedNode->GetData()); - if (labelSetImage.IsNotNull()) - { - // reset the image / reference node selector in case the current selected segmentation has no image parent - m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); - // selected a label set image (a segmentation ( working node) - m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(selectedNode); - return; - } - - mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); - if (selectedImage.IsNotNull()) - { - // reset the segmentation / working node selector in case the current selected image has no segmentation child - m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); - // selected an image (a reference node) - m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(selectedNode); - return; - } - } - } -} - void QmitkMultiLabelSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Parent && m_WorkingNode.IsNotNull()) { m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(prefs->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(prefs->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage; mitk::DataNode* segmentation; // iterate all segmentations (binary (single label) and LabelSetImages) mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateOr::Pointer allSegmentationsPredicate = mitk::NodePredicateOr::New(isBinaryPredicate, m_SegmentationPredicate); mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(allSegmentationsPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator it = allSegmentations->begin(); it != allSegmentations->end(); ++it) { segmentation = *it; labelSetImage = dynamic_cast(segmentation->GetData()); if (nullptr != labelSetImage) { // segmentation node is a multi label segmentation segmentation->SetProperty("labelset.contour.active", drawOutline); //segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } else if (nullptr != segmentation->GetData()) { // node is actually a 'single label' segmentation, // but its outline property can be set in the 'multi label' segmentation preference page as well bool isBinary = false; segmentation->GetBoolProperty("binary", isBinary); if (isBinary) { segmentation->SetProperty("outline binary", drawOutline); segmentation->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } } else { // "interpolation feedback" data nodes have binary flag but don't have a data set. So skip them for now. MITK_INFO << "DataNode " << segmentation->GetName() << " doesn't contain a base data."; } } } } -void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode *) -{ - /* - bool isHelperObject(false); - node->GetBoolProperty("helper object", isHelperObject); - if (isHelperObject) return; - - if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) - { - mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); - - if (workingImage->GetNumberOfLabels() > 2) - m_Controls.m_LabelSetWidget->show(); - else - m_Controls.m_LabelSetWidget->hide(); - } - */ -} - void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) { return; } if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext *context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService *service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; } } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Reset LabelSetWidget Events workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::SetFocus() { } void QmitkMultiLabelSegmentationView::UpdateControls() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasValidWorkingNode = workingNode != nullptr; m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_gbInterpolation->setEnabled(false); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_LabelSetWidget->setEnabled(false); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btLockExterior->setChecked(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setChecked(false); m_Controls.m_pbShowLabelTable->setEnabled(false); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); if (hasValidWorkingNode) { // TODO adapt tool manager so that this check is done there, e.g. convenience function mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); hasValidWorkingNode = workingImage != nullptr; if (hasValidWorkingNode) { m_Controls.m_pbNewLabel->setEnabled(true); m_Controls.m_btLockExterior->setEnabled(true); m_Controls.m_pbShowLabelTable->setEnabled(true); m_Controls.m_gbInterpolation->setEnabled(true); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_btAddLayer->setEnabled(true); int activeLayer = workingImage->GetActiveLayer(); int numberOfLayers = workingImage->GetNumberOfLayers(); m_Controls.m_cbActiveLayer->blockSignals(true); m_Controls.m_cbActiveLayer->clear(); for (unsigned int lidx = 0; lidx < workingImage->GetNumberOfLayers(); ++lidx) { m_Controls.m_cbActiveLayer->addItem(QString::number(lidx)); } m_Controls.m_cbActiveLayer->setCurrentIndex(activeLayer); m_Controls.m_cbActiveLayer->blockSignals(false); m_Controls.m_cbActiveLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btDeleteLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btPreviousLayer->setEnabled(activeLayer > 0); m_Controls.m_btNextLayer->setEnabled(activeLayer != numberOfLayers - 1); m_Controls.m_btLockExterior->setChecked(workingImage->GetLabel(0, activeLayer)->GetLocked()); m_Controls.m_pbShowLabelTable->setChecked(workingImage->GetNumberOfLabels() > 1 /*1st is exterior*/); //MLI TODO //m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } } if (hasValidWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); } } void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = nullptr; m_Parent->setEnabled(false); } void QmitkMultiLabelSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkMultiLabelSegmentationView::SetMouseCursor(const us::ModuleResource resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) this->ResetMouseCursor(); if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { us::Module* module = us::GetModuleContext()->GetModule(); std::vector resources = module->FindResources("/", "*", true); for (std::vector::iterator iter = resources.begin(); iter != resources.end(); ++iter) { MITK_INFO << iter->GetResourcePath(); } m_Interactor = mitk::SegmentationInteractor::New(); if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) { MITK_WARN << "Error loading state machine"; } if (!m_Interactor->SetEventConfig("ConfigSegmentation.xml", module)) { MITK_WARN << "Error loading state machine configuration"; } // Register as listener via micro services us::ServiceProperties props; props["name"] = std::string("SegmentationInteraction"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } -bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const +bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) { bool isSameGeometry(true); + auto image1 = dynamic_cast(node1->GetData()); + assert(image1); + + auto image2 = dynamic_cast(node2->GetData()); + assert(image2); + if (image1 && image2) { mitk::BaseGeometry::Pointer geo1 = image1->GetGeometry(); mitk::BaseGeometry::Pointer geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } - -QString QmitkMultiLabelSegmentationView::GetLastFileOpenPath() -{ - return this->GetPreferences()->Get("LastFileOpenPath", ""); -} - -void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString &path) -{ - this->GetPreferences()->Put("LastFileOpenPath", path); - this->GetPreferences()->Flush(); -} diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h index ce5f44b385..e8ec36913e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h @@ -1,182 +1,172 @@ /*============================================================================ 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 QmitkMultiLabelSegmentationView_h #define QmitkMultiLabelSegmentationView_h #include #include "mitkSegmentationInteractor.h" #include #include "ui_QmitkMultiLabelSegmentationControls.h" // berry #include class QmitkRenderWindow; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_multilabelsegmentation_internal */ class QmitkMultiLabelSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { Q_OBJECT public: static const std::string VIEW_ID; QmitkMultiLabelSegmentationView(); ~QmitkMultiLabelSegmentationView() override; typedef std::map NodeTagMapType; // GUI setup void CreateQtPartControl(QWidget *parent) override; // ILifecycleAwarePart interface public: void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; virtual int GetSizeFlags(bool width); virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); protected slots: // reaction to the shortcut for toggling the visibility of the working node void OnVisibilityShortcutActivated(); // reaction to the shortcut for iterating over all labels void OnLabelToggleShortcutActivated(); // reaction to the selection of any 2D segmentation tool void OnManualTool2DSelected(int id); // reaction to button "New Label" void OnNewLabel(); // reaction to button "Show Label Table" void OnShowLabelTable(bool value); // reaction to button "New Segmentation Session" void OnNewSegmentationSession(); // reaction to signal "goToLabel" from labelset widget void OnGoToLabel(const mitk::Point3D &pos); void OnResetView(); // reaction to the button "Add Layer" void OnAddLayer(); // reaction to the button "Delete Layer" void OnDeleteLayer(); // reaction to the button "Previous Layer" void OnPreviousLayer(); // reaction to the button "Next Layer" void OnNextLayer(); // reaction to the combobox change "Change Layer" void OnChangeLayer(int); // reaction to the button "Deactive Active Tool" void OnDeactivateActiveTool(); // reaction to the button "Lock exterior" void OnLockExteriorToggled(bool); // reaction to the selection of a new patient (reference) image in the DataStorage combobox - void OnReferenceSelectionChanged(const mitk::DataNode* node); + void OnReferenceSelectionChanged(QList nodes); // reaction to the selection of a new Segmentation (working) image in the DataStorage combobox - void OnSegmentationSelectionChanged(const mitk::DataNode* node); + void OnSegmentationSelectionChanged(QList nodes); // reaction to ... void OnInterpolationSelectionChanged(int); protected: - // reimplemented from QmitkAbstractView - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; - // reimplemented from QmitkAbstractView void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; - // reimplemented from QmitkAbstractView - void NodeAdded(const mitk::DataNode* node) override; - // reimplemented from QmitkAbstractView void NodeRemoved(const mitk::DataNode* node) override; void OnEstablishLabelSetConnection(); void OnLooseLabelSetConnection(); void SetFocus() override; void UpdateControls(); void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource, int hotspotX, int hotspotY); void InitializeListeners(); /// \brief Checks if two images have the same size and geometry - bool CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const; - - QString GetLastFileOpenPath(); - - void SetLastFileOpenPath(const QString &path); + static bool CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2); /// \brief the Qt parent of our GUI (NOT of this object) QWidget *m_Parent; /// \brief Qt GUI file Ui::QmitkMultiLabelSegmentationControls m_Controls; mitk::IRenderWindowPart *m_IRenderWindowPart; mitk::ToolManager *m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; mitk::SegmentationInteractor::Pointer m_Interactor; /** * Reference to the service registration of the observer, * it is needed to unregister the observer on unload. */ us::ServiceRegistration m_ServiceRegistration; }; #endif // QmitkMultiLabelSegmentationView_h diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp index f19ce8cd51..64c496cda8 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp @@ -1,140 +1,140 @@ /*============================================================================ 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 "QmitkBooleanOperationsWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include static const char* const HelpText = "Select two different masks above"; std::string GetPrefix(mitk::BooleanOperation::Type type) { switch (type) { case mitk::BooleanOperation::Difference: return "DifferenceFrom_"; case mitk::BooleanOperation::Intersection: return "IntersectionWith_"; case mitk::BooleanOperation::Union: return "UnionWith_"; default: assert(false && "Unknown boolean operation type"); return "UNKNOWN_BOOLEAN_OPERATION_WITH_"; } } void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetBoolProperty("binary", true); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); } QmitkBooleanOperationsWidget::QmitkBooleanOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::MaskPredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::MaskPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::MaskPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::MaskPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect(m_Controls.differenceButton, SIGNAL(clicked()), this, SLOT(OnDifferenceButtonClicked())); connect(m_Controls.intersectionButton, SIGNAL(clicked()), this, SLOT(OnIntersectionButtonClicked())); connect(m_Controls.unionButton, SIGNAL(clicked()), this, SLOT(OnUnionButtonClicked())); } QmitkBooleanOperationsWidget::~QmitkBooleanOperationsWidget() { } void QmitkBooleanOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNotNull() && node1.IsNotNull() && node0 != node1) { dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } else { dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } } void QmitkBooleanOperationsWidget::EnableButtons(bool enable) { m_Controls.differenceButton->setEnabled(enable); m_Controls.intersectionButton->setEnabled(enable); m_Controls.unionButton->setEnabled(enable); } void QmitkBooleanOperationsWidget::OnDifferenceButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Difference); } void QmitkBooleanOperationsWidget::OnIntersectionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Intersection); } void QmitkBooleanOperationsWidget::OnUnionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Union); } void QmitkBooleanOperationsWidget::DoBooleanOperation(mitk::BooleanOperation::Type type) { mitk::SliceNavigationController* timeNavigationController = this->GetTimeNavigationController(); assert(timeNavigationController != nullptr); mitk::Image::Pointer segmentation0 = static_cast(m_Controls.dataSelectionWidget->GetSelection(0)->GetData()); mitk::Image::Pointer segmentation1 = static_cast(m_Controls.dataSelectionWidget->GetSelection(1)->GetData()); mitk::Image::Pointer result; try { mitk::BooleanOperation booleanOperation(type, segmentation0, segmentation1, timeNavigationController->GetTime()->GetPos()); result = booleanOperation.GetResult(); } catch (const mitk::Exception &exception) { MITK_ERROR << "Boolean operation failed: " << exception.GetDescription(); } assert(result.IsNotNull()); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; AddToDataStorage( dataSelectionWidget->GetDataStorage(), result, GetPrefix(type) + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.cpp index 7f2bbc3d65..5a1017530d 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ConvertToMl/QmitkConvertToMlWidget.cpp @@ -1,65 +1,65 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkConvertToMlWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include "src/internal/QmitkConvertToMultiLabelSegmentationAction.h" QmitkConvertToMlWidget::QmitkConvertToMlWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImagePredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate); - connect(m_Controls.dataSelectionWidget, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(SelectionChanged())); + connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(SelectionChanged())); connect(m_Controls.pushButton, SIGNAL(clicked()), this, SLOT(Convert())); } QmitkConvertToMlWidget::~QmitkConvertToMlWidget() { } void QmitkConvertToMlWidget::SelectionChanged() { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); if (node0.IsNotNull()) { this->EnableButtons(); } else { this->EnableButtons(false); } } void QmitkConvertToMlWidget::EnableButtons(bool enable) { m_Controls.pushButton->setEnabled(enable); } void QmitkConvertToMlWidget::Convert() { auto node = m_Controls.dataSelectionWidget->GetSelection(0); QmitkConvertToMultiLabelSegmentationAction converter; QList list; list.append(node); converter.SetDataStorage(m_Controls.dataSelectionWidget->GetDataStorage()); converter.Run(list); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp index 93b3df1e6c..c56528a31e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp @@ -1,318 +1,318 @@ /*============================================================================ 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 "QmitkImageMaskingWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include #include #include #include #include #include #include static const char* const HelpText = "Select a patient image and a mask"; QmitkImageMaskingWidget::QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImagePredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::MaskPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::MaskPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); // mitk::IDataStorageService::Pointer service = // berry::Platform::GetServiceRegistry().GetServiceById(mitk::IDataStorageService::ID); // assert(service.IsNotNull()); mitk::DataStorage::Pointer ds = m_Controls.dataSelectionWidget->GetDataStorage(); m_Controls.m_LabelSetWidget->SetDataStorage(ds); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_MaskStampWidget->SetDataStorage(ds); this->EnableButtons(false); connect (m_Controls.rbMaskImage, SIGNAL(toggled(bool)), this, SLOT(OnImageMaskingToggled(bool))); connect (m_Controls.rbMaskSurface, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceMaskingToggled(bool))); connect (m_Controls.btnMaskImage, SIGNAL(pressed()), this, SLOT(OnMaskImagePressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged( 0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkImageMaskingWidget::~QmitkImageMaskingWidget() { } void QmitkImageMaskingWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { if( m_Controls.rbMaskImage->isChecked() ) { dataSelectionWidget->SetHelpText(HelpText); } else { dataSelectionWidget->SetHelpText("Select a patient image and a surface"); } this->EnableButtons(false); } else { this->SelectionControl(index, selection); } } void QmitkImageMaskingWidget::SelectionControl(unsigned int index, const mitk::DataNode*) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); //if Image-Masking is enabled, check if image-dimension of reference and binary image is identical if( m_Controls.rbMaskImage->isChecked() ) { if( dataSelectionWidget->GetSelection(0) == dataSelectionWidget->GetSelection(1) ) { dataSelectionWidget->SetHelpText("Select two different images above"); this->EnableButtons(false); return; } } dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } void QmitkImageMaskingWidget::EnableButtons(bool enable) { m_Controls.btnMaskImage->setEnabled(enable); } void QmitkImageMaskingWidget::OnImageMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a patient image and a mask"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::MaskPredicate); } } void QmitkImageMaskingWidget::OnSurfaceMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a patient image and a surface"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::SurfacePredicate); } } void QmitkImageMaskingWidget::OnMaskImagePressed() { //Disable Buttons during calculation and initialize Progressbar this->EnableButtons(false); mitk::ProgressBar::GetInstance()->AddStepsToDo(4); mitk::ProgressBar::GetInstance()->Progress(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; //create result image, get mask node and reference image mitk::Image::Pointer resultImage(nullptr); mitk::DataNode::Pointer maskingNode = dataSelectionWidget->GetSelection(1); mitk::Image::Pointer referenceImage = static_cast(dataSelectionWidget->GetSelection(0)->GetData()); if(referenceImage.IsNull() || maskingNode.IsNull() ) { MITK_ERROR << "Selection does not contain an image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain an image", QMessageBox::Ok ); m_Controls.btnMaskImage->setEnabled(true); return; } //Do Image-Masking if (m_Controls.rbMaskImage->isChecked()) { mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer maskImage = dynamic_cast ( maskingNode->GetData() ); if( referenceImage->GetLargestPossibleRegion().GetSize() != maskImage->GetLargestPossibleRegion().GetSize() ) { mitk::PadImageFilter::Pointer padImageFilter = mitk::PadImageFilter::New(); padImageFilter->SetInput(0, maskImage); padImageFilter->SetInput(1, referenceImage); padImageFilter->SetPadConstant(0); padImageFilter->SetBinaryFilter(false); padImageFilter->SetLowerThreshold(0); padImageFilter->SetUpperThreshold(1); MITK_INFO << "Padding mask ..."; padImageFilter->Update(); maskImage = padImageFilter->GetOutput(); } if(maskImage.IsNull() ) { MITK_ERROR << "Selection does not contain a binary image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a binary image", QMessageBox::Ok ); this->EnableButtons(); return; } resultImage = this->MaskImage( referenceImage, maskImage ); } //Do Surface-Masking else { mitk::ProgressBar::GetInstance()->Progress(); //1. convert surface to image mitk::Surface::Pointer surface = dynamic_cast ( maskingNode->GetData() ); //TODO Get 3D Surface of current time step if(surface.IsNull()) { MITK_ERROR << "Selection does not contain a surface"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer maskImage = this->ConvertSurfaceToImage( referenceImage, surface ); //2. mask reference image with mask image if(maskImage.IsNotNull() && referenceImage->GetLargestPossibleRegion().GetSize() == maskImage->GetLargestPossibleRegion().GetSize() ) { resultImage = this->MaskImage( referenceImage, maskImage ); } } mitk::ProgressBar::GetInstance()->Progress(); if( resultImage.IsNull() ) { MITK_ERROR << "Masking failed"; QMessageBox::information( this, "Image and Surface Masking", "Masking failed. For more information please see logging window.", QMessageBox::Ok ); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(4); return; } //Add result to data storage this->AddToDataStorage( dataSelectionWidget->GetDataStorage(), resultImage, dataSelectionWidget->GetSelection(0)->GetName() + "_" + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(); } mitk::Image::Pointer QmitkImageMaskingWidget::MaskImage(mitk::Image::Pointer referenceImage, mitk::Image::Pointer maskImage ) { mitk::Image::Pointer resultImage(nullptr); mitk::MaskImageFilter::Pointer maskFilter = mitk::MaskImageFilter::New(); maskFilter->SetInput( referenceImage ); maskFilter->SetMask( maskImage ); //MLI TODO //if ( m_Controls.m_chkMakeOutputBinary->isChecked() ) //{ // maskFilter->SetInsideValue(1.0); // maskFilter->SetOutsideValue(0.0); // maskFilter->SetOverrideOutsideValue(true); // maskFilter->SetOverrideInsideValue(true); //} //maskFilter->SetOverrideOutsideValue( m_Controls.m_chkOverwriteBackground->isChecked() ); //maskFilter->SetOverrideInsideValue( m_Controls.m_chkOverwriteForeground->isChecked() ); //maskFilter->SetInsideValue( m_Controls.m_leForegroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); //maskFilter->SetOutsideValue( m_Controls.m_leBackgroundValue->text().toFloat() );//referenceImage->GetStatistics()->GetScalarValueMin() ); try { maskFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } resultImage = maskFilter->GetOutput(); return resultImage; } mitk::Image::Pointer QmitkImageMaskingWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::ProgressBar::GetInstance()->Progress(); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(image); try { surfaceToImageFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer resultImage = mitk::Image::New(); resultImage = surfaceToImageFilter->GetOutput(); return resultImage; } void QmitkImageMaskingWidget::AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent ) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp index 06e3f9d5b4..6167294496 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp @@ -1,250 +1,250 @@ /*============================================================================ 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 "QmitkMorphologicalOperationsWidget.h" #include #include #include #include #include static const char* const HelpText = "Select a mask above"; QmitkMorphologicalOperationsWidget::QmitkMorphologicalOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.m_DataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::MaskPredicate); + m_Controls.m_DataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::MaskPredicate); m_Controls.m_DataSelectionWidget->SetHelpText(HelpText); // mitk::IDataStorageService::Pointer service = // berry::Platform::GetServiceRegistry().GetServiceById(mitk::IDataStorageService::ID); // assert(service.IsNotNull()); mitk::DataStorage::Pointer ds = m_Controls.m_DataSelectionWidget->GetDataStorage(); m_Controls.m_LabelSetWidget->SetDataStorage(ds); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_ToolSelectionBox->SetGenerateAccelerators(true); m_Controls.m_ToolSelectionBox->SetToolGUIArea( m_Controls.m_ToolGUIContainer ); m_Controls.m_ToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); m_Controls.m_ToolSelectionBox->SetDisplayedToolGroups("Median Dilate Erode Open Close 'Fill Holes' 'Keep N Largest' 'Split' 'Region Selector'"); // m_Controls.m_LabelSetWidget->SetDataStorage( *(this->GetDataStorage()) ); connect(m_Controls.btnClosing, SIGNAL(clicked()), this, SLOT(OnClosingButtonClicked())); connect(m_Controls.btnOpening, SIGNAL(clicked()), this, SLOT(OnOpeningButtonClicked())); connect(m_Controls.btnDilatation, SIGNAL(clicked()), this, SLOT(OnDilatationButtonClicked())); connect(m_Controls.btnErosion, SIGNAL(clicked()), this, SLOT(OnErosionButtonClicked())); connect(m_Controls.btnFillHoles, SIGNAL(clicked()), this, SLOT(OnFillHolesButtonClicked())); connect(m_Controls.radioButtonMorphoCross, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); connect(m_Controls.radioButtonMorphoBall, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); connect(m_Controls.m_DataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if (m_Controls.m_DataSelectionWidget->GetSelection(0).IsNotNull()) this->OnSelectionChanged(0, m_Controls.m_DataSelectionWidget->GetSelection(0)); } QmitkMorphologicalOperationsWidget::~QmitkMorphologicalOperationsWidget() { } void QmitkMorphologicalOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); if (node.IsNotNull()) { m_Controls.m_DataSelectionWidget->SetHelpText(""); this->EnableButtons(true); } else { m_Controls.m_DataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } } void QmitkMorphologicalOperationsWidget::EnableButtons(bool enable) { m_Controls.btnClosing->setEnabled(enable); m_Controls.btnDilatation->setEnabled(enable); m_Controls.btnErosion->setEnabled(enable); m_Controls.btnFillHoles->setEnabled(enable); m_Controls.btnOpening->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnRadioButtonsClicked() { bool enable = m_Controls.radioButtonMorphoBall->isChecked(); m_Controls.sliderMorphFactor->setEnabled(enable); m_Controls.spinBoxMorphFactor->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnClosingButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); bool ball = m_Controls.radioButtonMorphoBall->isChecked(); mitk::MorphologicalOperations::StructuralElementType structuralElement = ball ? mitk::MorphologicalOperations::Ball : mitk::MorphologicalOperations::Cross; try { mitk::MorphologicalOperations::Closing(image, m_Controls.spinBoxMorphFactor->value(), structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnOpeningButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); bool ball = m_Controls.radioButtonMorphoBall->isChecked(); mitk::MorphologicalOperations::StructuralElementType structuralElement = ball ? mitk::MorphologicalOperations::Ball : mitk::MorphologicalOperations::Cross; try { mitk::MorphologicalOperations::Opening(image, m_Controls.spinBoxMorphFactor->value(), structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnDilatationButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); bool ball = m_Controls.radioButtonMorphoBall->isChecked(); mitk::MorphologicalOperations::StructuralElementType structuralElement = ball ? mitk::MorphologicalOperations::Ball : mitk::MorphologicalOperations::Cross; try { mitk::MorphologicalOperations::Dilate(image, m_Controls.spinBoxMorphFactor->value(), structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnErosionButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); bool ball = m_Controls.radioButtonMorphoBall->isChecked(); mitk::MorphologicalOperations::StructuralElementType structuralElement = ball ? mitk::MorphologicalOperations::Ball : mitk::MorphologicalOperations::Cross; try { mitk::MorphologicalOperations::Erode(image, m_Controls.spinBoxMorphFactor->value(), structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnFillHolesButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* m_DataSelectionWidget = m_Controls.m_DataSelectionWidget; mitk::DataNode::Pointer node = m_DataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); try { mitk::MorphologicalOperations::FillHoles(image); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp index 683383c07c..fe8e47e8e8 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp @@ -1,175 +1,175 @@ /*============================================================================ 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 "QmitkSurfaceToImageWidget.h" #include #include #include #include #include #include #include #include static const char* const HelpText = "Select a patient image and a surface"; QmitkSurfaceToImageWidget::QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.m_DataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImagePredicate); - m_Controls.m_DataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SurfacePredicate); + m_Controls.m_DataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate); + m_Controls.m_DataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SurfacePredicate); m_Controls.m_DataSelectionWidget->SetHelpText(HelpText); // mitk::IDataStorageService* service = // berry::Platform::GetServiceRegistry().GetServiceById(mitk::IDataStorageService::ID); // assert(service.IsNotNull()); mitk::DataStorage::Pointer ds = m_Controls.m_DataSelectionWidget->GetDataStorage(); m_Controls.m_LabelSetWidget->SetDataStorage(ds); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_SurfaceStampWidget->SetDataStorage(ds); this->EnableButtons(false); m_Controls.m_chkMakeOutputBinary->setChecked(true); connect (m_Controls.btnSurface2Image, SIGNAL(pressed()), this, SLOT(OnSurface2ImagePressed())); connect(m_Controls.m_DataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect (m_Controls.m_chkMakeOutputBinary, SIGNAL(toggled(bool)), this, SLOT(OnMakeOutputBinaryChanged(bool))); if( m_Controls.m_DataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.m_DataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged( 0, m_Controls.m_DataSelectionWidget->GetSelection(0)); } } QmitkSurfaceToImageWidget::~QmitkSurfaceToImageWidget() { } void QmitkSurfaceToImageWidget::EnableButtons(bool enable) { m_Controls.btnSurface2Image->setEnabled(enable); m_Controls.m_chkMakeOutputBinary->setEnabled(enable); m_Controls.m_chkOverwriteBackground->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked()); m_Controls.m_leForegroundValue->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked()); m_Controls.m_leBackgroundValue->setEnabled(enable && !m_Controls.m_chkMakeOutputBinary->isChecked()); } void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { mitk::DataNode::Pointer imageNode = m_Controls.m_DataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer surfaceNode = m_Controls.m_DataSelectionWidget->GetSelection(1); if (imageNode.IsNull() || surfaceNode.IsNull() ) { m_Controls.m_DataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } else { mitk::Image::Pointer image = dynamic_cast( m_Controls.m_DataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( m_Controls.m_DataSelectionWidget->GetSelection(1)->GetData() ); if( image->GetTimeSteps() != surface->GetTimeSteps() ) { m_Controls.m_DataSelectionWidget->SetHelpText("Image and surface are of different size"); this->EnableButtons(false); } else { m_Controls.m_DataSelectionWidget->SetHelpText(""); this->EnableButtons(); } } } void QmitkSurfaceToImageWidget::OnSurface2ImagePressed() { this->EnableButtons(false); mitk::Image::Pointer image = dynamic_cast( m_Controls.m_DataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( m_Controls.m_DataSelectionWidget->GetSelection(1)->GetData() ); if( image.IsNull() || surface.IsNull()) { MITK_ERROR << "Selection does not contain an image and/or a surface"; QMessageBox::information( this, "Surface To Image", "Selection does not contain an image and/or a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer resultImage(nullptr); resultImage = this->ConvertSurfaceToImage( image, surface ); if( resultImage.IsNull() ) { QMessageBox::information( this, "Surface to Image", "Could not stamp surface.\n See error log for details.", QMessageBox::Ok ); this->EnableButtons(); return; } //create name for result node std::string nameOfResultImage = m_Controls.m_DataSelectionWidget->GetSelection(0)->GetName(); nameOfResultImage.append("_"); nameOfResultImage.append(m_Controls.m_DataSelectionWidget->GetSelection(1)->GetName()); //create data node and add to data storage mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); resultNode->SetData( resultImage ); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(m_Controls.m_chkMakeOutputBinary->isChecked()) ); m_Controls.m_DataSelectionWidget->GetDataStorage()->Add(resultNode, m_Controls.m_DataSelectionWidget->GetSelection(0)); this->EnableButtons(); } mitk::Image::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::SurfaceStampImageFilter::Pointer filter = mitk::SurfaceStampImageFilter::New(); filter->SetInput(image); filter->SetSurface(surface); filter->SetMakeOutputBinary(m_Controls.m_chkMakeOutputBinary->isChecked()); filter->SetOverwriteBackground(m_Controls.m_chkOverwriteBackground->isChecked()); filter->SetForegroundValue(m_Controls.m_leForegroundValue->text().toFloat()); filter->SetBackgroundValue(m_Controls.m_leBackgroundValue->text().toFloat()); try { filter->Update(); } catch(mitk::Exception& e) { MITK_ERROR << "exception caught: " << e.GetDescription(); return nullptr; } mitk::Image::Pointer resultImage = filter->GetOutput(); return resultImage; } void QmitkSurfaceToImageWidget::OnMakeOutputBinaryChanged(bool value) { m_Controls.m_chkOverwriteBackground->setEnabled(!value); m_Controls.m_leForegroundValue->setEnabled(!value); m_Controls.m_leBackgroundValue->setEnabled(!value); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/Manual.dox b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/Manual.dox index 13e39a1f86..e752436edf 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/Manual.dox +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/Manual.dox @@ -1,88 +1,89 @@ -/** +/** \page org_mitk_gui_qt_pharmacokinetics_mri The DCE MR Perfusion Datafit View \imageMacro{pharmacokinetics_mri_doc.svg,"Icon of the DCE MR Perfusion View",3.0} \tableofcontents \section FIT_DCE_Introduction Introduction For pharmacokinetic analysis of DCE MRI/CT data using compartment models in non-linear least square fitting the DCE MR Perfusion Datafit plugin can be used. \section FIT_DCE_Contact Contact information This plug-in is being developed by Charlotte Debus and the SIDT group (Software development for Integrated Diagnostics and Therapy) at the German Cancer Research Center (DKFZ). If you have any questions, need support, find a bug or have a feature request, feel free to contact us at www.mitk.org. \subsection FIT_DCE_Cite Citation information If you use the view for your research please cite our work as reference:\n\n Debus C and Floca R, Ingrisch M, Kompan I, Maier-Hein K, Abdollahi A, Nolden M, MITK-ModelFit: generic open-source framework for model fits and their exploration in medical imaging – design, implementation and application on the example of DCE-MRI (arXiv:1807.07353) \section FIT_DCE_General General information \imageMacro{dce_mri_init.png, "Example screen shot showing the view at first start.", 10} For pharmacokinetic analysis of DCE MRI/CT data using compartment models in non-linear least square fitting the DCE MR Perfusion Datafit view can be used. In principle, every model can be fitted on the entire image. However, for model configuration reasons (e.g. AIF required) and computational time cost, this is often not advisable. Therefore, apart from the image to be fitted (Selected Time Series), a ROI segmentation can be defined (Selected Mask), within which model fitting is performed. The view currently offers voxel wise and/or ROI averaged fits of intensity-time curves with different quantitative and semi-quantitative models. If a mask is selected, ROI-based fitting (fit average curve within ROI) is enabled (radio button Fitting Strategy – Pixel based / ROI based). \subsection FIT_DCE_General_models Supported models Currently the following pharmacokinetic models for gadolinium-based contrast agent are available: - The Descriptive Brix model \ref FIT_DCE_lit_ref1 "[1]" - A semi-quantitative three segment linear model (3SL) - The standard tofts model \ref FIT_DCE_lit_ref2 "[2]" - The extended Tofts model \ref FIT_DCE_lit_ref3 "[3]" - The two compartment exchange model (2CXM) \ref FIT_DCE_lit_ref4 "[4, 5]" \section FIT_DCE_Settings Model Settings \imageMacro{dce_mri_config.png, "Example screenshot showing the config settings of the view.", 10} \subsection FIT_DCE_Settings_model Model specific settings Selecting one of the \ref FIT_DCE_General_models "supported models" will open below tabs for further configuration of the model. - The descriptive Brix model requires only definition of the duration of the bolus, i.e. the overall time of the injection (Injection Time [min]) - The 3SL is a semi-quantitative descriptive model that distinguishes three different segments of the signal: A constant baseline, the initial fast rise (wash-in) and the final slow rise / signal decrease (washout). Each of these segments is approximated by a linear curve, with change points in-between. It requires no further configuration - The standard Tofts model, the extended Tofts model and the 2CXM are all three compartment models that require the input of the concentration time curve in the tissue feeding artery, the AIF. In the DCE MRI Model fitting plugin, the arterial input function can be defined in several ways. For patient individual image derived AIFs, select the radio button "Select AIF from Image". In that case, a segmentation ROI for the artery has to be given to the tool (Drop-down menu AIF Mask from Data Manager). In cases, where the respective artery does not lie in the same image as the investigated tissue (e.g. in animal experiments, where a slice through the heart is used for AIF extraction), a dedicated AIF image can be selected from the Data Manager. The other option is to define the AIF via an external file (e.g. for population derived AIFs or AIFs from blood sampling). By clicking the Browse button, one can select a csv file that holds the arterial intensity values and corresponding timepoints (in tuple format (Time, Value)). Caution: the file may not contain a header line, but the first line must start with Time and Intensity values. Furthermore, the hematocrit level has to be set (from 0 to 1) for conversion from whole blood to plasma concentration. It is set to the literature default value of 0.45. \subsection FIT_DCE_Settings_start Start parameter \imageMacro{dce_mri_start.png, "Example screen shot for start parameter settings.", 10} In cases of noisy data it can be useful to define the initial starting values of the parameter estimates, at which optimization starts, in order to prevent optimization results in local optima. Each model has default scalar values (applied to every voxel) for initial values of each parameter, however these can be adjusted. Moreover, initial values can also be defined locally for each individual voxel via starting value images. \subsection FIT_DCE_Settings_constraint Constraint settings \imageMacro{dce_mri_constraint.png, "Example screen shot for constraint settings.", 10} To limit the fitting search space and to exclude unphysical/illogical results for model parameter estimates, constraints to individual parameters as well as combinations can be imposed. Each model has default constraints, however, new ones can be defined or removed by the + and – buttons in the table. The first column specifies the parameter(s) involved in the constraint (if multiple selected, their sum will be used) by selection in the drop down menu. The second column defines whether the constraints defines an upper or lower boundary. Value and Width define the actual constraint value, that should not be crossed, and a certain tolerance width. \subsection FIT_DCE_Settings_concentration Signal to concentration conversion settings \imageMacro{dce_mri_concentration.png, "Example screen shot for concentration conversion settings.", 10} Most models require concentration values as input rather than raw signal intensities (i.e. all compartment models). The DCE MR Perfusion view offers conversion to concentration by means of relative and absolute signal enhancement as well as a special conversion for turbo flash sequences. +For the conversion methods, a baseline image prior to contrast agent arrival is required. In many data sets, multiple baseline images are available. The "Baseline Range Selection" allows for selection of a range of time frames, from which the average image (along the time dimension) is calculated and set as baseline input image. Remark: The number of the first time frame is 0. \section FIT_DCE_Fitting Executing a fit After configuration of the entire fit routine, the respective time series to be fitted and eventually the ROI mask have to be selected. If only an image is needed, selection of the respective time series in the data manager is sufficient. If a mask is to be selected as well, image and mask have to be selected by holding the shift key and selecting them in this order from the Data manager.\n\n In order to distinguish results from different model fits to the data, a Fitting name can be defined in the bottom field. As default, the name of the model and the fitting strategy (pixel/ROI) are given. This name will then be appended by the respective parameter name.\n\n For development purposes and evaluation of the fits, the option "Generate debug parameter images" is available. Enabling this option will result in additional parameter maps displaying the status of the optimizer at fit termination, like needed optimization time, number of iterations, constraint violations and reasons for fit termination (criterion reached, maximum number of iterations, etc.).\n\n After all necessary configurations are set, the button "Start Modelling" is enabled, which starts the fitting routine. Progress can be seen in the message box on the bottom. Resulting parameter maps will afterwards be added to the data manager as sub-nodes to the analyzed 4D image. \section FIT_DCE_lit References/Literature - \anchor FIT_DCE_lit_ref1 [1] Brix G, Semmler W, Port R, Schad LR, Layer G, Lorenz WJ. Pharmacokinetic parameters in CNS Gd-DTPA enhanced MR imaging. J Comput Assist Tomogr. 1991;15:621–8. - \anchor FIT_DCE_lit_ref2 [2] Tofts PS, Kermode AG. Measurement of the blood-brain barrier permeability and leakage space using dynamic MR imaging. 1. Fundamental concepts. Magn Reson Med. 1991;17:357–67. - \anchor FIT_DCE_lit_ref3 [3] Sourbron SP, Buckley DL. On the scope and interpretation of the Tofts models for DCE-MRI. Magn Reson Med. 2011;66:735–45. - \anchor FIT_DCE_lit_ref4 [4] Brix G, Kiessling F, Lucht R, Darai S, Wasser K, Delorme S, et al. Microcirculation and microvasculature in breast tumors: Pharmacokinetic analysis of dynamic MR image series. Magn Reson Med. 2004;52:420–9. - \anchor FIT_DCE_lit_ref5 [5] Sourbron, Buckley. Tracer kinetic modelling in MRI: estimating perfusion and capillary permeability - pdf. Phys Med Biol. 2012. http://iopscience.iop.org/article/10.1088/0031-9155/57/2/R1/pdf. Accessed 1 May 2016. */ diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_concentration.png b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_concentration.png index 5ac03206ef..5ba06abe29 100644 Binary files a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_concentration.png and b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_concentration.png differ diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_config.png b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_config.png index 1d6bc35cea..b2ac30d6da 100644 Binary files a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_config.png and b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_config.png differ diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_constraint.png b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_constraint.png index 5ac03206ef..1848b5fb8f 100644 Binary files a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_constraint.png and b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/documentation/UserManual/dce_mri_constraint.png differ diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp index 3cd5da7b70..6634588751 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.cpp @@ -1,1394 +1,1429 @@ /*============================================================================ 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 "MRPerfusionView.h" #include "boost/tokenizer.hpp" #include "boost/math/constants/constants.hpp" #include #include "mitkWorkbenchUtil.h" #include "mitkAterialInputFunctionGenerator.h" #include "mitkConcentrationCurveGenerator.h" #include #include #include #include "mitkThreeStepLinearModelFactory.h" #include "mitkThreeStepLinearModelParameterizer.h" #include #include #include #include #include "mitkTwoCompartmentExchangeModelFactory.h" #include "mitkTwoCompartmentExchangeModelParameterizer.h" #include "mitkNumericTwoCompartmentExchangeModelFactory.h" #include "mitkNumericTwoCompartmentExchangeModelParameterizer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK #include #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include #include -//#include -//#include + const std::string MRPerfusionView::VIEW_ID = "org.mitk.gui.qt.pharmacokinetics.mri"; inline double convertToDouble(const std::string& data) { std::istringstream stepStream(data); stepStream.imbue(std::locale("C")); double value = 0.0; if (!(stepStream >> value) || !(stepStream.eof())) { mitkThrow() << "Cannot convert string to double. String: " << data; } return value; } void MRPerfusionView::SetFocus() { m_Controls.btnModelling->setFocus(); } void MRPerfusionView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.btnModelling->setEnabled(false); m_Controls.errorMessageLabel->hide(); this->InitModelComboBox(); connect(m_Controls.btnModelling, SIGNAL(clicked()), this, SLOT(OnModellingButtonClicked())); connect(m_Controls.comboModel, SIGNAL(currentIndexChanged(int)), this, SLOT(OnModellSet(int))); connect(m_Controls.radioPixelBased, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); //AIF setting m_Controls.groupAIF->hide(); m_Controls.btnAIFFile->setEnabled(false); m_Controls.btnAIFFile->setEnabled(false); m_Controls.radioAIFImage->setChecked(true); m_Controls.comboAIFMask->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFMask->SetPredicate(m_IsMaskPredicate); m_Controls.comboAIFMask->setVisible(true); m_Controls.comboAIFMask->setEnabled(true); m_Controls.comboAIFImage->SetDataStorage(this->GetDataStorage()); m_Controls.comboAIFImage->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.comboAIFImage->setEnabled(false); m_Controls.checkDedicatedAIFImage->setEnabled(true); m_Controls.HCLSpinBox->setValue(mitk::AterialInputFunctionGenerator::DEFAULT_HEMATOCRIT_LEVEL); + m_Controls.spinBox_baselineEndTimeStep->setMinimum(0); + m_Controls.spinBox_baselineStartTimeStep->setMinimum(0); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.labelAIFMask, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFMask, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.checkDedicatedAIFImage, SLOT(setVisible(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setVisible(bool))); connect(m_Controls.checkDedicatedAIFImage, SIGNAL(toggled(bool)), m_Controls.comboAIFImage, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFImage, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.btnAIFFile, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), m_Controls.aifFilePath, SLOT(setEnabled(bool))); connect(m_Controls.radioAIFFile, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.btnAIFFile, SIGNAL(clicked()), this, SLOT(LoadAIFfromFile())); //Brix setting m_Controls.groupDescBrix->hide(); connect(m_Controls.injectiontime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Num2CX setting m_Controls.groupNum2CXM->hide(); connect(m_Controls.odeStepSize, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); //Model fit configuration m_Controls.groupBox_FitConfiguration->hide(); m_Controls.checkBox_Constraints->setEnabled(false); m_Controls.constraintManager->setEnabled(false); m_Controls.initialValuesManager->setEnabled(false); m_Controls.initialValuesManager->setDataStorage(this->GetDataStorage()); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.initialValuesManager, SIGNAL(initialValuesChanged(void)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_StartParameters, SIGNAL(toggled(bool)), m_Controls.initialValuesManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setEnabled(bool))); connect(m_Controls.checkBox_Constraints, SIGNAL(toggled(bool)), m_Controls.constraintManager, SLOT(setVisible(bool))); //Concentration m_Controls.groupConcentration->hide(); m_Controls.groupBoxTurboFlash->hide(); m_Controls.radioButtonNoConversion->setChecked(true); m_Controls.factorSpinBox->setEnabled(false); + m_Controls.spinBox_baselineStartTimeStep->setEnabled(false); + m_Controls.spinBox_baselineEndTimeStep->setEnabled(false); m_Controls.groupBox_viaT1Map->hide(); + m_Controls.spinBox_baselineStartTimeStep->setValue(0); + m_Controls.spinBox_baselineEndTimeStep->setValue(0); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), m_Controls.groupBoxTurboFlash, SLOT(setVisible(bool))); connect(m_Controls.radioButtonTurboFlash, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxationtime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.recoverytime, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.relaxivity, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButton_absoluteEnhancement, SIGNAL(toggled(bool)), m_Controls.factorSpinBox, SLOT(setEnabled(bool))); connect(m_Controls.radioButton_relativeEnchancement, SIGNAL(toggled(bool)), m_Controls.factorSpinBox, SLOT(setEnabled(bool))); + connect(m_Controls.factorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); + connect(m_Controls.spinBox_baselineStartTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); + connect(m_Controls.spinBox_baselineEndTimeStep, SIGNAL(valueChanged(int)), this, SLOT(UpdateGUIControls())); connect(m_Controls.radioButtonUsingT1, SIGNAL(toggled(bool)), m_Controls.groupBox_viaT1Map, SLOT(setVisible(bool))); connect(m_Controls.radioButtonUsingT1, SIGNAL(toggled(bool)), this, SLOT(UpdateGUIControls())); connect(m_Controls.FlipangleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.RelaxivitySpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); connect(m_Controls.TRSpinBox, SIGNAL(valueChanged(double)), this, SLOT(UpdateGUIControls())); m_Controls.ComboT1Map->SetDataStorage(this->GetDataStorage()); m_Controls.ComboT1Map->SetPredicate(m_IsNoMaskImagePredicate); m_Controls.ComboT1Map->setEnabled(false); connect(m_Controls.radioButtonUsingT1, SIGNAL(toggled(bool)), m_Controls.ComboT1Map, SLOT(setEnabled(bool))); UpdateGUIControls(); } bool MRPerfusionView::IsTurboFlashSequenceFlag() const { return this->m_Controls.radioButtonTurboFlash->isChecked(); }; void MRPerfusionView::UpdateGUIControls() { m_Controls.lineFitName->setPlaceholderText(QString::fromStdString(this->GetDefaultFitName())); m_Controls.lineFitName->setEnabled(!m_FittingInProgress); m_Controls.checkBox_Constraints->setEnabled(m_modelConstraints.IsNotNull()); bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr || dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; m_Controls.groupAIF->setVisible(isToftsFactory || is2CXMFactory); m_Controls.groupDescBrix->setVisible(isDescBrixFactory); m_Controls.groupNum2CXM->setVisible(isNum2CXMFactory); m_Controls.groupConcentration->setVisible(isToftsFactory || is2CXMFactory); m_Controls.groupBox_FitConfiguration->setVisible(m_selectedModelFactory); m_Controls.groupBox->setEnabled(!m_FittingInProgress); m_Controls.comboModel->setEnabled(!m_FittingInProgress); m_Controls.groupAIF->setEnabled(!m_FittingInProgress); m_Controls.groupDescBrix->setEnabled(!m_FittingInProgress); m_Controls.groupNum2CXM->setEnabled(!m_FittingInProgress); m_Controls.groupConcentration->setEnabled(!m_FittingInProgress); m_Controls.groupBox_FitConfiguration->setEnabled(!m_FittingInProgress); m_Controls.radioROIbased->setEnabled(m_selectedMask.IsNotNull()); m_Controls.btnModelling->setEnabled(m_selectedImage.IsNotNull() && m_selectedModelFactory.IsNotNull() && !m_FittingInProgress && CheckModelSettings()); + + m_Controls.spinBox_baselineStartTimeStep->setEnabled(m_Controls.radioButtonTurboFlash->isChecked() || m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1->isChecked()); + m_Controls.spinBox_baselineEndTimeStep->setEnabled(m_Controls.radioButton_absoluteEnhancement->isChecked() || m_Controls.radioButton_relativeEnchancement->isChecked() || m_Controls.radioButtonUsingT1->isChecked() || m_Controls.radioButtonTurboFlash->isChecked()); + + } void MRPerfusionView::OnModellSet(int index) { m_selectedModelFactory = nullptr; if (index > 0) { if (static_cast(index) <= m_FactoryStack.size() ) { m_selectedModelFactory = m_FactoryStack[index - 1]; } else { MITK_WARN << "Invalid model index. Index outside of the factory stack. Factory stack size: "<< m_FactoryStack.size() << "; invalid index: "<< index; } } if (m_selectedModelFactory) { this->m_modelConstraints = dynamic_cast (m_selectedModelFactory->CreateDefaultConstraints().GetPointer()); m_Controls.initialValuesManager->setInitialValues(m_selectedModelFactory->GetParameterNames(), m_selectedModelFactory->GetDefaultInitialParameterization()); if (this->m_modelConstraints.IsNull()) { this->m_modelConstraints = mitk::SimpleBarrierConstraintChecker::New(); } m_Controls.constraintManager->setChecker(this->m_modelConstraints, this->m_selectedModelFactory->GetParameterNames()); } UpdateGUIControls(); } std::string MRPerfusionView::GetFitName() const { std::string fitName = m_Controls.lineFitName->text().toStdString(); if (fitName.empty()) { fitName = m_Controls.lineFitName->placeholderText().toStdString(); } return fitName; } std::string MRPerfusionView::GetDefaultFitName() const { std::string defaultName = "undefined model"; if (this->m_selectedModelFactory.IsNotNull()) { defaultName = this->m_selectedModelFactory->GetClassID(); } if (this->m_Controls.radioPixelBased->isChecked()) { defaultName += "_pixel"; } else { defaultName += "_roi"; } return defaultName; } void MRPerfusionView::OnModellingButtonClicked() { //check if all static parameters set if (m_selectedModelFactory.IsNotNull() && CheckModelSettings()) { m_HasGeneratedNewInput = false; m_HasGeneratedNewInputAIF = false; mitk::ParameterFitImageGeneratorBase::Pointer generator = nullptr; mitk::modelFit::ModelFitInfo::Pointer fitSession = nullptr; bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isExtToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isStanToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateDescriptiveBrixModel_PixelBased(fitSession, generator); } else { GenerateDescriptiveBrixModel_ROIBased(fitSession, generator); } } else if (is3LinearFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { Generate3StepLinearModelFit_PixelBased(fitSession, generator); } else { Generate3StepLinearModelFit_ROIBased(fitSession, generator); } } else if (isStanToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isExtToftsFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (is2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } else if (isNum2CXMFactory) { if (this->m_Controls.radioPixelBased->isChecked()) { GenerateAIFbasedModelFit_PixelBased(fitSession, generator); } else { GenerateAIFbasedModelFit_ROIBased(fitSession, generator); } } //add other models with else if if (generator.IsNotNull() && fitSession.IsNotNull()) { m_FittingInProgress = true; UpdateGUIControls(); DoFit(fitSession, generator); } else { QMessageBox box; box.setText("Fitting error!"); box.setInformativeText("Could not establish fitting job. Error when setting ab generator, model parameterizer or session info."); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } else { QMessageBox box; box.setText("Static parameters for model are not set!"); box.setInformativeText("Some static parameters, that are needed for calculation are not set and equal to zero. Modeling not possible"); box.setStandardButtons(QMessageBox::Ok); box.setDefaultButton(QMessageBox::Ok); box.setIcon(QMessageBox::Warning); box.exec(); } } void MRPerfusionView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*source*/, const QList& selectedNodes) { m_selectedMaskNode = nullptr; m_selectedMask = nullptr; m_Controls.errorMessageLabel->setText(""); m_Controls.masklabel->setText("No (valid) mask selected."); m_Controls.timeserieslabel->setText("No (valid) series selected."); QList nodes = selectedNodes; if (nodes.size() > 0 && this->m_IsNoMaskImagePredicate->CheckNode(nodes.front())) { this->m_selectedNode = nodes.front(); auto selectedImage = dynamic_cast(this->m_selectedNode->GetData()); m_Controls.timeserieslabel->setText((this->m_selectedNode->GetName()).c_str()); if (selectedImage != this->m_selectedImage) { if (selectedImage) { this->m_Controls.initialValuesManager->setReferenceImageGeometry(selectedImage->GetGeometry()); } else { this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } } this->m_selectedImage = selectedImage; nodes.pop_front(); } else { this->m_selectedNode = nullptr; this->m_selectedImage = nullptr; this->m_Controls.initialValuesManager->setReferenceImageGeometry(nullptr); } if (nodes.size() > 0 && this->m_IsMaskPredicate->CheckNode(nodes.front())) { this->m_selectedMaskNode = nodes.front(); this->m_selectedMask = dynamic_cast(this->m_selectedMaskNode->GetData()); if (this->m_selectedMask->GetTimeSteps() > 1) { MITK_INFO << "Selected mask has multiple timesteps. Only use first timestep to mask model fit. Mask name: " << m_selectedMaskNode->GetName(); mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedMask = maskedImageTimeSelector->GetOutput(); } m_Controls.masklabel->setText((this->m_selectedMaskNode->GetName()).c_str()); } if (m_selectedMask.IsNull()) { this->m_Controls.radioPixelBased->setChecked(true); } m_Controls.errorMessageLabel->show(); + if (this->m_selectedImage.IsNotNull()) + { + m_Controls.spinBox_baselineStartTimeStep->setMaximum((this->m_selectedImage->GetDimension(3))-1); + m_Controls.spinBox_baselineEndTimeStep->setMaximum((this->m_selectedImage->GetDimension(3)) - 1); + } + UpdateGUIControls(); } bool MRPerfusionView::CheckModelSettings() const { bool ok = true; //check wether any model is set at all. Otherwise exit with false if (m_selectedModelFactory.IsNotNull()) { bool isDescBrixFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is3LinearFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isToftsFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr|| dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool is2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; bool isNum2CXMFactory = dynamic_cast (m_selectedModelFactory.GetPointer()) != nullptr; if (isDescBrixFactory) { //if all static parameters for this model are set, exit with true, Otherwise exit with false ok = m_Controls.injectiontime->value() > 0; } else if (is3LinearFactory) { - if (this->m_Controls.radioButtonTurboFlash->isChecked()) + if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); + ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() - || this->m_Controls.radioButton_relativeEnchancement->isChecked()) + || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); + ok = ok && CheckBaselineSelectionSettings(); } - else if (this->m_Controls.radioButtonUsingT1->isChecked()) + else if (this->m_Controls.radioButtonUsingT1->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.ComboT1Map->GetSelectedNode().IsNotNull()); - + ok = ok && CheckBaselineSelectionSettings(); } else { ok = false; } } else if (isToftsFactory || is2CXMFactory || isNum2CXMFactory) { if (this->m_Controls.radioAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFMask->GetSelectedNode().IsNotNull(); if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { ok = ok && m_Controls.comboAIFImage->GetSelectedNode().IsNotNull(); } } else if (this->m_Controls.radioAIFFile->isChecked()) { ok = ok && (this->AIFinputGrid.size() != 0) && (this->AIFinputFunction.size() != 0); } else { ok = false; } - if (this->m_Controls.radioButtonTurboFlash->isChecked()) + if (this->m_Controls.radioButtonTurboFlash->isChecked() ) { ok = ok && (m_Controls.recoverytime->value() > 0); ok = ok && (m_Controls.relaxationtime->value() > 0); ok = ok && (m_Controls.relaxivity->value() > 0); ok = ok && (m_Controls.AifRecoverytime->value() > 0); + ok = ok && CheckBaselineSelectionSettings(); } else if (this->m_Controls.radioButton_absoluteEnhancement->isChecked() - || this->m_Controls.radioButton_relativeEnchancement->isChecked()) + || this->m_Controls.radioButton_relativeEnchancement->isChecked() ) { ok = ok && (m_Controls.factorSpinBox->value() > 0); + ok = ok && CheckBaselineSelectionSettings(); } - else if (this->m_Controls.radioButtonUsingT1->isChecked()) + else if (this->m_Controls.radioButtonUsingT1->isChecked() ) { ok = ok && (m_Controls.FlipangleSpinBox->value() > 0); ok = ok && (m_Controls.TRSpinBox->value() > 0); ok = ok && (m_Controls.RelaxivitySpinBox->value() > 0); ok = ok && (m_Controls.ComboT1Map->GetSelectedNode().IsNotNull()); - + ok = ok && CheckBaselineSelectionSettings(); } else { ok = false; } if (isNum2CXMFactory) { ok = ok && (this->m_Controls.odeStepSize->value() > 0); } } //add other models as else if and check wether all needed static parameters are set else { ok = false; } if (this->m_Controls.radioButton_StartParameters->isChecked() && !this->m_Controls.initialValuesManager->hasValidInitialValues()) { std::string warning = "Warning. Invalid start parameters. At least one parameter as an invalid image setting as source."; MITK_ERROR << warning; m_Controls.infoBox->append(QString("") + QString::fromStdString(warning) + QString("")); ok = false; }; } else { ok = false; } return ok; } +bool MRPerfusionView::CheckBaselineSelectionSettings() const +{ + return m_Controls.spinBox_baselineStartTimeStep->value() <= m_Controls.spinBox_baselineEndTimeStep->value(); +} + void MRPerfusionView::ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const { if (m_Controls.radioButton_StartParameters->isChecked()) { //use user defined initial parameters mitk::InitialParameterizationDelegateBase::Pointer paramDelegate = m_Controls.initialValuesManager->getInitialParametrizationDelegate(); parameterizer->SetInitialParameterizationDelegate(paramDelegate); } } void MRPerfusionView::GenerateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelParameterizer::New(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); mitk::ImageTimeSelector::Pointer imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(this->m_selectedImage); imageTimeSelector->SetTimeNr(0); imageTimeSelector->UpdateLargestPossibleRegion(); mitk::DescriptivePharmacokineticBrixModelParameterizer::BaseImageType::Pointer baseImage; mitk::CastToItkImage(imageTimeSelector->GetOutput(), baseImage); modelParameterizer->SetBaseImage(baseImage); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } void MRPerfusionView::GenerateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::Pointer modelParameterizer = mitk::DescriptivePharmacokineticBrixModelValueBasedParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now modelParameterizer->SetTau(m_Controls.injectiontime->value()); modelParameterizer->SetBaseValue(roiSignal[0]); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } void MRPerfusionView::Generate3StepLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); mitk::ThreeStepLinearModelParameterizer::Pointer modelParameterizer = mitk::ThreeStepLinearModelParameterizer::New(); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); } fitGenerator->SetDynamicImage(m_selectedImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); } void MRPerfusionView::Generate3StepLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); mitk::ThreeStepLinearModelParameterizer::Pointer modelParameterizer = mitk::ThreeStepLinearModelParameterizer::New(); //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(m_selectedImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Model configuration (static parameters) can be done now this->ConfigureInitialParametersOfParameterizer(modelParameterizer); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(m_selectedImage)); generator = fitGenerator.GetPointer(); std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, m_selectedNode->GetData(), mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { mitk::PixelBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::PixelBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); std::string roiUID = ""; if (m_selectedMask.IsNotNull()) { fitGenerator->SetMask(m_selectedMask); roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); } fitGenerator->SetDynamicImage(this->m_inputImage); fitGenerator->SetFitFunctor(fitFunctor); generator = fitGenerator.GetPointer(); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_PIXELBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } template void MRPerfusionView::GenerateAIFbasedModelFit_ROIBased( mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator) { if (m_selectedMask.IsNull()) { return; } mitk::ROIBasedParameterFitImageGenerator::Pointer fitGenerator = mitk::ROIBasedParameterFitImageGenerator::New(); typename TParameterizer::Pointer modelParameterizer = TParameterizer::New(); PrepareConcentrationImage(); mitk::AIFBasedModelBase::AterialInputFunctionType aif; mitk::AIFBasedModelBase::AterialInputFunctionType aifTimeGrid; GetAIF(aif, aifTimeGrid); modelParameterizer->SetAIF(aif); modelParameterizer->SetAIFTimeGrid(aifTimeGrid); this->ConfigureInitialParametersOfParameterizer(modelParameterizer); mitk::NumericTwoCompartmentExchangeModelParameterizer* numTCXParametrizer = dynamic_cast (modelParameterizer.GetPointer()); if (numTCXParametrizer) { numTCXParametrizer->SetODEINTStepSize(this->m_Controls.odeStepSize->value()); } //Compute ROI signal mitk::MaskedDynamicImageStatisticsGenerator::Pointer signalGenerator = mitk::MaskedDynamicImageStatisticsGenerator::New(); signalGenerator->SetMask(m_selectedMask); signalGenerator->SetDynamicImage(this->m_inputImage); signalGenerator->Generate(); mitk::MaskedDynamicImageStatisticsGenerator::ResultType roiSignal = signalGenerator->GetMean(); //Specify fitting strategy and criterion parameters mitk::ModelFitFunctorBase::Pointer fitFunctor = CreateDefaultFitFunctor(modelParameterizer); //Parametrize fit generator fitGenerator->SetModelParameterizer(modelParameterizer); fitGenerator->SetMask(m_selectedMask); fitGenerator->SetFitFunctor(fitFunctor); fitGenerator->SetSignal(roiSignal); fitGenerator->SetTimeGrid(mitk::ExtractTimeGrid(this->m_inputImage)); generator = fitGenerator.GetPointer(); std::string roiUID = mitk::EnsureModelFitUID(this->m_selectedMaskNode); //Create model info modelFitInfo = mitk::modelFit::CreateFitInfoFromModelParameterizer(modelParameterizer, this->m_inputImage, mitk::ModelFitConstants::FIT_TYPE_VALUE_ROIBASED(), this->GetFitName(), roiUID); mitk::ScalarListLookupTable::ValueType infoSignal; for (mitk::MaskedDynamicImageStatisticsGenerator::ResultType::const_iterator pos = roiSignal.begin(); pos != roiSignal.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("ROI", infoSignal); infoSignal.clear(); for (mitk::AIFBasedModelBase::AterialInputFunctionType::const_iterator pos = aif.begin(); pos != aif.end(); ++pos) { infoSignal.push_back(*pos); } modelFitInfo->inputData.SetTableValue("AIF", infoSignal); } void MRPerfusionView::DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator) { std::stringstream message; message << "" << "Fitting Data Set . . ." << ""; m_Controls.errorMessageLabel->setText(message.str().c_str()); m_Controls.errorMessageLabel->show(); ///////////////////////// //create job and put it into the thread pool mitk::modelFit::ModelFitResultNodeVectorType additionalNodes; if (m_HasGeneratedNewInput) { additionalNodes.push_back(m_inputNode); } if (m_HasGeneratedNewInputAIF) { additionalNodes.push_back(m_inputAIFNode); } ParameterFitBackgroundJob* pJob = new ParameterFitBackgroundJob(generator, fitSession, this->m_selectedNode, additionalNodes); pJob->setAutoDelete(true); connect(pJob, SIGNAL(Error(QString)), this, SLOT(OnJobError(QString))); connect(pJob, SIGNAL(Finished()), this, SLOT(OnJobFinished())); connect(pJob, SIGNAL(ResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), this, SLOT(OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType, const ParameterFitBackgroundJob*)), Qt::BlockingQueuedConnection); connect(pJob, SIGNAL(JobProgress(double)), this, SLOT(OnJobProgress(double))); connect(pJob, SIGNAL(JobStatusChanged(QString)), this, SLOT(OnJobStatusChanged(QString))); QThreadPool* threadPool = QThreadPool::globalInstance(); threadPool->start(pJob); } MRPerfusionView::MRPerfusionView() : m_FittingInProgress(false), m_HasGeneratedNewInput(false), m_HasGeneratedNewInputAIF(false) { m_selectedImage = nullptr; m_selectedMask = nullptr; mitk::ModelFactoryBase::Pointer factory = mitk::DescriptivePharmacokineticBrixModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ThreeStepLinearModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::StandardToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::ExtendedToftsModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::TwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); factory = mitk::NumericTwoCompartmentExchangeModelFactory::New().GetPointer(); m_FactoryStack.push_back(factory); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isLegacyMask = mitk::NodePredicateAnd::New(isImage, isBinary); mitk::NodePredicateOr::Pointer isMask = mitk::NodePredicateOr::New(isLegacyMask, isLabelSet); mitk::NodePredicateAnd::Pointer isNoMask = mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isMask)); this->m_IsMaskPredicate = mitk::NodePredicateAnd::New(isMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); this->m_IsNoMaskImagePredicate = mitk::NodePredicateAnd::New(isNoMask, mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))).GetPointer(); } void MRPerfusionView::OnJobFinished() { this->m_Controls.infoBox->append(QString("Fitting finished.")); this->m_FittingInProgress = false; this->UpdateGUIControls(); }; void MRPerfusionView::OnJobError(QString err) { MITK_ERROR << err.toStdString().c_str(); m_Controls.infoBox->append(QString("") + err + QString("")); }; void MRPerfusionView::OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob) { //Store the resulting parameter fit image via convenience helper function in data storage //(handles the correct generation of the nodes and their properties) mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), results, pJob->GetParentNode()); //this stores the concentration image and AIF concentration image, if generated for this fit in the storage. //if not generated for this fit, relevant nodes are empty. mitk::modelFit::StoreResultsInDataStorage(this->GetDataStorage(), pJob->GetAdditionalRelevantNodes(), pJob->GetParentNode()); }; void MRPerfusionView::OnJobProgress(double progress) { QString report = QString("Progress. ") + QString::number(progress); this->m_Controls.infoBox->append(report); }; void MRPerfusionView::OnJobStatusChanged(QString info) { this->m_Controls.infoBox->append(info); } void MRPerfusionView::InitModelComboBox() const { this->m_Controls.comboModel->clear(); this->m_Controls.comboModel->addItem(tr("No model selected")); for (ModelFactoryStackType::const_iterator pos = m_FactoryStack.begin(); pos != m_FactoryStack.end(); ++pos) { this->m_Controls.comboModel->addItem(QString::fromStdString((*pos)->GetClassID())); } this->m_Controls.comboModel->setCurrentIndex(0); }; mitk::DataNode::Pointer MRPerfusionView::GenerateConcentrationNode(mitk::Image* image, const std::string& nodeName) const { if (!image) { mitkThrow() << "Cannot generate concentration node. Passed image is null. parameter name: "; } mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetData(image); result->SetName(nodeName); result->SetVisibility(true); mitk::EnsureModelFitUID(result); return result; }; mitk::Image::Pointer MRPerfusionView::ConvertConcentrationImage(bool AIFMode) { //Compute Concentration image mitk::ConcentrationCurveGenerator::Pointer concentrationGen = mitk::ConcentrationCurveGenerator::New(); if (m_Controls.checkDedicatedAIFImage->isChecked() && AIFMode) { concentrationGen->SetDynamicImage(this->m_selectedAIFImage); } else { concentrationGen->SetDynamicImage(this->m_selectedImage); } concentrationGen->SetisTurboFlashSequence(IsTurboFlashSequenceFlag()); concentrationGen->SetAbsoluteSignalEnhancement(m_Controls.radioButton_absoluteEnhancement->isChecked()); concentrationGen->SetRelativeSignalEnhancement(m_Controls.radioButton_relativeEnchancement->isChecked()); concentrationGen->SetUsingT1Map(m_Controls.radioButtonUsingT1->isChecked()); if (IsTurboFlashSequenceFlag()) { if (AIFMode) { concentrationGen->SetRecoveryTime(m_Controls.AifRecoverytime->value()); } else { concentrationGen->SetRecoveryTime(m_Controls.recoverytime->value()); } concentrationGen->SetRelaxationTime(m_Controls.relaxationtime->value()); concentrationGen->SetRelaxivity(m_Controls.relaxivity->value()); + concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); + concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); + } else if (this->m_Controls.radioButtonUsingT1->isChecked()) { concentrationGen->SetRecoveryTime(m_Controls.TRSpinBox->value()); concentrationGen->SetRelaxivity(m_Controls.RelaxivitySpinBox->value()); concentrationGen->SetT10Image(dynamic_cast(m_Controls.ComboT1Map->GetSelectedNode()->GetData())); - + concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); + concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); //Convert Flipangle from degree to radiant double alpha = m_Controls.FlipangleSpinBox->value()/360*2* boost::math::constants::pi(); concentrationGen->SetFlipAngle(alpha); } else { concentrationGen->SetFactor(m_Controls.factorSpinBox->value()); + concentrationGen->SetBaselineStartTimeStep(m_Controls.spinBox_baselineStartTimeStep->value()); + concentrationGen->SetBaselineEndTimeStep(m_Controls.spinBox_baselineEndTimeStep->value()); } + mitk::Image::Pointer concentrationImage = concentrationGen->GetConvertedImage(); return concentrationImage; } void MRPerfusionView::GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid) { if (this->m_Controls.radioAIFFile->isChecked()) { aif.clear(); aifTimeGrid.clear(); aif.SetSize(AIFinputFunction.size()); aifTimeGrid.SetSize(AIFinputGrid.size()); aif.fill(0.0); aifTimeGrid.fill(0.0); itk::Array::iterator aifPos = aif.begin(); for (std::vector::const_iterator pos = AIFinputFunction.begin(); pos != AIFinputFunction.end(); ++pos, ++aifPos) { *aifPos = *pos; } itk::Array::iterator gridPos = aifTimeGrid.begin(); for (std::vector::const_iterator pos = AIFinputGrid.begin(); pos != AIFinputGrid.end(); ++pos, ++gridPos) { *gridPos = *pos; } } else if (this->m_Controls.radioAIFImage->isChecked()) { aif.clear(); aifTimeGrid.clear(); mitk::AterialInputFunctionGenerator::Pointer aifGenerator = mitk::AterialInputFunctionGenerator::New(); //Hematocrit level aifGenerator->SetHCL(this->m_Controls.HCLSpinBox->value()); //mask settings this->m_selectedAIFMaskNode = m_Controls.comboAIFMask->GetSelectedNode(); this->m_selectedAIFMask = dynamic_cast(this->m_selectedAIFMaskNode->GetData()); if (this->m_selectedAIFMask->GetTimeSteps() > 1) { MITK_INFO << "Selected AIF mask has multiple timesteps. Only use first timestep to mask model fit. AIF Mask name: " << m_selectedAIFMaskNode->GetName() ; mitk::ImageTimeSelector::Pointer maskedImageTimeSelector = mitk::ImageTimeSelector::New(); maskedImageTimeSelector->SetInput(this->m_selectedAIFMask); maskedImageTimeSelector->SetTimeNr(0); maskedImageTimeSelector->UpdateLargestPossibleRegion(); this->m_selectedAIFMask = maskedImageTimeSelector->GetOutput(); } if (this->m_selectedAIFMask.IsNotNull()) { aifGenerator->SetMask(this->m_selectedAIFMask); } //image settings if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { this->m_selectedAIFImageNode = m_Controls.comboAIFImage->GetSelectedNode(); this->m_selectedAIFImage = dynamic_cast(this->m_selectedAIFImageNode->GetData()); } else { this->m_selectedAIFImageNode = m_selectedNode; this->m_selectedAIFImage = m_selectedImage; } this->PrepareAIFConcentrationImage(); aifGenerator->SetDynamicImage(this->m_inputAIFImage); aif = aifGenerator->GetAterialInputFunction(); aifTimeGrid = aifGenerator->GetAterialInputFunctionTimeGrid(); } else { mitkThrow() << "Cannot generate AIF. View is in a invalide state. No AIF mode selected."; } } void MRPerfusionView::LoadAIFfromFile() { QFileDialog dialog; dialog.setNameFilter(tr("Images (*.csv")); QString fileName = dialog.getOpenFileName(); m_Controls.aifFilePath->setText(fileName); std::string m_aifFilePath = fileName.toStdString(); //Read Input typedef boost::tokenizer< boost::escaped_list_separator > Tokenizer; ///////////////////////////////////////////////////////////////////////////////////////////////// //AIF Data std::ifstream in1(m_aifFilePath.c_str()); if (!in1.is_open()) { m_Controls.errorMessageLabel->setText("Could not open AIF File!"); } std::vector< std::string > vec1; std::string line1; while (getline(in1, line1)) { Tokenizer tok(line1); vec1.assign(tok.begin(), tok.end()); this->AIFinputGrid.push_back(convertToDouble(vec1[0])); this->AIFinputFunction.push_back(convertToDouble(vec1[1])); } } void MRPerfusionView::PrepareConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInput = false; if (!this->m_Controls.radioButtonNoConversion->isChecked()) { concentrationImage = this->ConvertConcentrationImage(false); concentrationNode = GenerateConcentrationNode(concentrationImage, "Concentration"); m_HasGeneratedNewInput = true; } m_inputImage = concentrationImage; m_inputNode = concentrationNode; mitk::EnsureModelFitUID(concentrationNode); } void MRPerfusionView::PrepareAIFConcentrationImage() { mitk::Image::Pointer concentrationImage = this->m_selectedImage; mitk::DataNode::Pointer concentrationNode = this->m_selectedNode; m_HasGeneratedNewInputAIF = false; if (this->m_Controls.checkDedicatedAIFImage->isChecked()) { concentrationImage = this->m_selectedAIFImage; concentrationNode = this->m_selectedAIFImageNode; } if (!this->m_Controls.radioButtonNoConversion->isChecked()) { if (!IsTurboFlashSequenceFlag() && !this->m_Controls.checkDedicatedAIFImage->isChecked()) { if (m_inputImage.IsNull()) { mitkThrow() << "Cannot get AIF concentration image. Invalid view state. Input image is not defined yet, but should be."; } //we can directly use the concentration input image/node (generated by GetConcentrationImage) also for the AIF concentrationImage = this->m_inputImage; concentrationNode = this->m_inputNode; } else { concentrationImage = this->ConvertConcentrationImage(true); concentrationNode = GenerateConcentrationNode(concentrationImage, "AIF Concentration"); m_HasGeneratedNewInputAIF = true; } } m_inputAIFImage = concentrationImage; m_inputAIFNode = concentrationNode; mitk::EnsureModelFitUID(concentrationNode); } mitk::ModelFitFunctorBase::Pointer MRPerfusionView::CreateDefaultFitFunctor( const mitk::ModelParameterizerBase* parameterizer) const { mitk::LevenbergMarquardtModelFitFunctor::Pointer fitFunctor = mitk::LevenbergMarquardtModelFitFunctor::New(); mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::Pointer chi2 = mitk::NormalizedSumOfSquaredDifferencesFitCostFunction::New(); fitFunctor->RegisterEvaluationParameter("Chi^2", chi2); if (m_Controls.checkBox_Constraints->isChecked()) { fitFunctor->SetConstraintChecker(m_modelConstraints); } mitk::ModelBase::Pointer refModel = parameterizer->GenerateParameterizedModel(); ::itk::LevenbergMarquardtOptimizer::ScalesType scales; scales.SetSize(refModel->GetNumberOfParameters()); scales.Fill(1.0); fitFunctor->SetScales(scales); fitFunctor->SetDebugParameterMaps(m_Controls.checkDebug->isChecked()); return fitFunctor.GetPointer(); } diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h index 3801493c0d..a5410d2e49 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionView.h @@ -1,208 +1,213 @@ /*============================================================================ 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 MRPerfusionView_h #define MRPerfusionView_h #include #include "QmitkAbstractView.h" #include "itkCommand.h" #include "ui_MRPerfusionViewControls.h" #include "mitkModelBase.h" #include "QmitkParameterFitBackgroundJob.h" #include "mitkModelFitResultHelper.h" #include "mitkModelFactoryBase.h" #include "mitkLevenbergMarquardtModelFitFunctor.h" #include "mitkSimpleBarrierConstraintChecker.h" #include "mitkAIFBasedModelBase.h" /*! * @brief Test Plugin for SUV calculations of PET images */ class MRPerfusionView : public QmitkAbstractView { Q_OBJECT public: /*! @brief The view's unique ID - required by MITK */ static const std::string VIEW_ID; MRPerfusionView(); protected slots: void OnModellingButtonClicked(); void OnJobFinished(); void OnJobError(QString err); void OnJobResultsAreAvailable(mitk::modelFit::ModelFitResultNodeVectorType results, const ParameterFitBackgroundJob* pJob); void OnJobProgress(double progress); void OnJobStatusChanged(QString info); void OnModellSet(int); void LoadAIFfromFile(); /**Sets visibility and enabled state of the GUI depending on the settings and workflow state.*/ void UpdateGUIControls(); protected: typedef QList SelectedDataNodeVectorType; // Overridden base class functions /*! * @brief Sets up the UI controls and connects the slots and signals. Gets * called by the framework to create the GUI at the right time. * @param[in,out] parent The parent QWidget, as this class itself is not a QWidget * subclass. */ void CreateQtPartControl(QWidget* parent) override; /*! * @brief Sets the focus to the plot curve button. Gets called by the framework to set the * focus on the right widget. */ void SetFocus() override; /*! @brief Generates a configured fit generator and the corresponding modelinfo for a descriptive brix model with pixel based strategy. * @remark add GenerateFunction for each model in the Combo box*/ void GenerateDescriptiveBrixModel_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void GenerateDescriptiveBrixModel_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void Generate3StepLinearModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); void Generate3StepLinearModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateAIFbasedModelFit_ROIBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); template void GenerateAIFbasedModelFit_PixelBased(mitk::modelFit::ModelFitInfo::Pointer& modelFitInfo, mitk::ParameterFitImageGeneratorBase::Pointer& generator); /** Helper function that configures the initial parameter strategy of a parameterizer according to the settings of the GUI.*/ void ConfigureInitialParametersOfParameterizer(mitk::ModelParameterizerBase* parameterizer) const; /*! Starts the fitting job with the passed generator and session info*/ void DoFit(const mitk::modelFit::ModelFitInfo* fitSession, mitk::ParameterFitImageGeneratorBase* generator); /**Checks if the settings in the GUI are valid for the chosen model.*/ bool CheckModelSettings() const; + bool CheckBaselineSelectionSettings() const; + void InitModelComboBox() const; + + + /*! Helper method that generates a node for the passed concentration image.*/ mitk::DataNode::Pointer GenerateConcentrationNode(mitk::Image* image, const std::string& nodeName) const; /*! \brief called by QmitkFunctionality when DataManager's selection has changed */ void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& selectedNodes) override; // Variables /*! @brief The view's UI controls */ Ui::MRPerfusionViewControls m_Controls; /* Nodes selected by user/ui for the fit */ mitk::DataNode::Pointer m_selectedNode; mitk::DataNode::Pointer m_selectedMaskNode; mitk::DataNode::Pointer m_selectedAIFMaskNode; mitk::DataNode::Pointer m_selectedAIFImageNode; /* Images selected by user/ui for the fit */ mitk::Image::Pointer m_selectedImage; mitk::Image::Pointer m_selectedMask; mitk::Image::Pointer m_selectedAIFMask; mitk::Image::Pointer m_selectedAIFImage; mitk::ModelFactoryBase::Pointer m_selectedModelFactory; mitk::SimpleBarrierConstraintChecker::Pointer m_modelConstraints; private: bool IsTurboFlashSequenceFlag() const; bool m_FittingInProgress; typedef std::vector ModelFactoryStackType; ModelFactoryStackType m_FactoryStack; /**Converts the selected image to a concentration image based on the given gui settings. AIFMode controls if the concentration image for the fit input or the AIF will be converted.*/ mitk::Image::Pointer ConvertConcentrationImage(bool AIFMode); /**Helper function that (depending on the gui settings) prepares m_inputNode and m_inputImage. Either by directly pass back the selected image/node or the newly generated concentration image/node. After calling this method m_inputImage are always what should be used as input image for the fitting.*/ void PrepareConcentrationImage(); /**Helper function that (depending on the gui settings) prepares m_inputAIFNode and m_inputAIFImage. Either by directly pass back the selected image/node or the newly generated concentration image/node. After calling this method m_inputAIFImage are always what should be used as AIF image for the fitting.*/ void PrepareAIFConcentrationImage(); /**Helper function that (depending on the gui settings) generates and passes back the AIF and its time grid that should be used for fitting. @remark the parameters aif and aifTimeGrid will be initialized accordingly if the method returns.*/ void GetAIF(mitk::AIFBasedModelBase::AterialInputFunctionType& aif, mitk::AIFBasedModelBase::AterialInputFunctionType& aifTimeGrid); /**Helper function that generates a default fitting functor * default is a levenberg marquart based optimizer with all scales set to 1.0. * Constraint setter will be set based on the gui setting and a evaluation parameter * "sum of squared differences" will always be set.*/ mitk::ModelFitFunctorBase::Pointer CreateDefaultFitFunctor(const mitk::ModelParameterizerBase* parameterizer) const; /**Returns the default fit name, derived from the current GUI settings.*/ std::string GetDefaultFitName() const; /**Returns the current set name of the fit (either default name or use defined name).*/ std::string GetFitName() const; std::vector AIFinputGrid; std::vector AIFinputFunction; mitk::NodePredicateBase::Pointer m_IsNoMaskImagePredicate; mitk::NodePredicateBase::Pointer m_IsMaskPredicate; /* Node used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::DataNode::Pointer m_inputNode; mitk::DataNode::Pointer m_inputAIFNode; bool m_HasGeneratedNewInput; bool m_HasGeneratedNewInputAIF; /* Image used for the fit (my be the selected image or converted ones (depending on the ui settings */ mitk::Image::Pointer m_inputImage; mitk::Image::Pointer m_inputAIFImage; }; #endif diff --git a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionViewControls.ui b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionViewControls.ui index 7202a701b1..63dfa422d3 100644 --- a/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.pharmacokinetics.mri/src/internal/MRPerfusionViewControls.ui @@ -1,680 +1,726 @@ MRPerfusionViewControls 0 0 556 1124 0 0 QmitkTemplate Selected Time Series: No series selected. Selected Mask: No mask selected. Fitting strategy 5 - + + 5 + + + 5 + + + 5 + + 5 Pixel based true ROI based Message - Select pharmacokinetic modell... AIF Mask: Select AIF from Image: 20 0 0 AIF Mask: false Dedicated AIF Image: false 0 0 0 Select AIF from File: false Browse 5 Hematocrit Level [ ]: 1.000000000000000 0.010000000000000 Descriptive Brix-Model Parameters: QFormLayout::AllNonFixedFieldsGrow Injection Time [min]: Numeric Two Compartment Exchange Model Parameters: ODE Int Step Size [s]: 3 0.001000000000000 0.050000000000000 0 0 Model Fit Configuration 0 0 0 0 - 512 - 73 + 526 + 132 Start parameter Enter Fit Starting Parameters 0 0 0 0 - 303 - 246 + 158 + 232 Constraints Enter Constraints for Fit Parameters 0 0 0 200 0 - -34 - 499 - 516 + -108 + 516 + 452 Conversion: Signal to Concentration 9 No Signal Conversion true 10 Using T1 Map 10 Parameters: Flip Angle [ ° ] : Repetition Time TR [ms] : T1 Map [ms] : 10000.000000000000000 Relaxivity [mM⁻¹ s⁻¹] : 6 - + + + + + + + Conversion Factor k: + + + + + + + + + Start Time Frame + + + + + + + + + + End Time Frame + + + + + + + + + Relative Signal Enhancement - + Absolute Signal Enhancement - - + + - - + + - Conversion Factor k: + Baseline Range Selection: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 2 TurboFLASH Sequence 5 20 true Turbo FLASH Parameters: Recovery Time [s]: + + + + + + + AIF Recovery Time [s]: + + + + + + Relaxation Time [s]: Relaxivity [ ]: - - - - - - - AIF Recovery Time [s]: - - - - - - 5 Fitting name: <html><head/><body><p>Name/prefix that should be used for the fitting results.</p><p>May be explicitly defined by the user.</p></body></html> default fit name Start Modelling Generate debug parameter images 0 0 true Qt::Vertical 20 40 QmitkSimpleBarrierManagerWidget QWidget
QmitkSimpleBarrierManagerWidget.h
QmitkInitialValuesManagerWidget QWidget
QmitkInitialValuesManagerWidget.h
QmitkDataStorageComboBox QWidget
QmitkDataStorageComboBox.h
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp index 02cbeede6e..b0ade03e2a 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.cpp @@ -1,181 +1,228 @@ /*============================================================================ 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 "QmitkDataSelectionWidget.h" #include "../mitkPluginActivator.h" #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include static mitk::NodePredicateBase::Pointer CreatePredicate(QmitkDataSelectionWidget::Predicate predicate) { auto imageType = mitk::TNodePredicateDataType::New(); auto labelSetImageType = mitk::TNodePredicateDataType::New(); auto surfaceType = mitk::TNodePredicateDataType::New(); auto contourModelType = mitk::TNodePredicateDataType::New(); auto contourModelSetType = mitk::TNodePredicateDataType::New(); auto nonLabelSetImageType = mitk::NodePredicateAnd::New(imageType, mitk::NodePredicateNot::New(labelSetImageType)); auto nonHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")); auto isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); auto isSegmentation = mitk::NodePredicateProperty::New("segmentation", mitk::BoolProperty::New(true)); auto isBinaryOrSegmentation = mitk::NodePredicateOr::New(isBinary, isSegmentation); mitk::NodePredicateBase::Pointer returnValue; switch(predicate) { case QmitkDataSelectionWidget::ImagePredicate: returnValue = mitk::NodePredicateAnd::New( mitk::NodePredicateNot::New(isBinaryOrSegmentation), nonLabelSetImageType).GetPointer(); break; case QmitkDataSelectionWidget::SegmentationPredicate: returnValue = mitk::NodePredicateOr::New( mitk::NodePredicateAnd::New(imageType, isBinaryOrSegmentation), labelSetImageType).GetPointer(); break; case QmitkDataSelectionWidget::SurfacePredicate: returnValue = surfaceType.GetPointer(); break; case QmitkDataSelectionWidget::ImageAndSegmentationPredicate: returnValue = imageType.GetPointer(); break; case QmitkDataSelectionWidget::ContourModelPredicate: returnValue = mitk::NodePredicateOr::New( contourModelSetType, contourModelSetType).GetPointer(); break; default: assert(false && "Unknown predefined predicate!"); return nullptr; } return mitk::NodePredicateAnd::New(returnValue, nonHelperObject).GetPointer(); } QmitkDataSelectionWidget::QmitkDataSelectionWidget(QWidget* parent) : QWidget(parent) { m_Controls.setupUi(this); m_Controls.helpLabel->hide(); } QmitkDataSelectionWidget::~QmitkDataSelectionWidget() { } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(QmitkDataSelectionWidget::Predicate predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(QmitkDataSelectionWidget::Predicate predicate) { - return this->AddDataStorageComboBox("", predicate); + QString hint = "Select node"; + QString popupTitel = "Select node"; + + switch (predicate) + { + case QmitkDataSelectionWidget::ImagePredicate: + hint = "Select an image"; + popupTitel = "Select an image"; + break; + + case QmitkDataSelectionWidget::SegmentationPredicate: + hint = "Select a segmentation"; + popupTitel = "Select a segmentation"; + break; + + case QmitkDataSelectionWidget::SurfacePredicate: + hint = "Select a surface"; + popupTitel = "Select a surface"; + break; + + case QmitkDataSelectionWidget::ImageAndSegmentationPredicate: + hint = "Select an image or segmentation"; + popupTitel = "Select an image or segmentation"; + break; + + case QmitkDataSelectionWidget::ContourModelPredicate: + hint = "Select a contour model"; + popupTitel = "Select a contour model"; + break; + } + + return this->AddDataSelection("", hint, popupTitel, "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(mitk::NodePredicateBase* predicate) { - return this->AddDataStorageComboBox("", predicate); + return this->AddDataSelection("", "Select a node", "Select a node", "", predicate); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, QmitkDataSelectionWidget::Predicate predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, QmitkDataSelectionWidget::Predicate predicate) { - return this->AddDataStorageComboBox(labelText, CreatePredicate(predicate)); + return this->AddDataSelection(labelText, info, popupHint, popupTitel, CreatePredicate(predicate)); } -unsigned int QmitkDataSelectionWidget::AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate) +unsigned int QmitkDataSelectionWidget::AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate) { int row = m_Controls.gridLayout->rowCount(); if (!labelText.isEmpty()) { QLabel* label = new QLabel(labelText, m_Controls.dataSelectionWidget); - label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); m_Controls.gridLayout->addWidget(label, row, 0); } - QmitkDataStorageComboBox* comboBox = new QmitkDataStorageComboBox(this->GetDataStorage(), predicate, m_Controls.dataSelectionWidget); - connect(comboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSelectionChanged(const mitk::DataNode *))); - m_Controls.gridLayout->addWidget(comboBox, row, 1); - - m_DataStorageComboBoxes.push_back(comboBox); - return static_cast(m_DataStorageComboBoxes.size() - 1); + QmitkSingleNodeSelectionWidget* nodeSelection = new QmitkSingleNodeSelectionWidget(m_Controls.dataSelectionWidget); + + nodeSelection->SetSelectionIsOptional(false); + nodeSelection->SetAutoSelectNewNodes(false); + nodeSelection->SetInvalidInfo(info); + nodeSelection->SetPopUpTitel(popupTitel); + nodeSelection->SetPopUpHint(popupHint); + nodeSelection->SetDataStorage(this->GetDataStorage()); + nodeSelection->SetNodePredicate(predicate); + nodeSelection->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); + nodeSelection->setMinimumSize(0, 40); + + connect(nodeSelection, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSelectionChanged(QList))); + m_Controls.gridLayout->addWidget(nodeSelection, row, 1); + + m_NodeSelectionWidgets.push_back(nodeSelection); + return static_cast(m_NodeSelectionWidgets.size() - 1); } mitk::DataStorage::Pointer QmitkDataSelectionWidget::GetDataStorage() const { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); assert(ref == true); mitk::IDataStorageService* service = mitk::PluginActivator::getContext()->getService(ref); assert(service); return service->GetDefaultDataStorage()->GetDataStorage(); } mitk::DataNode::Pointer QmitkDataSelectionWidget::GetSelection(unsigned int index) { - assert(index < m_DataStorageComboBoxes.size()); - return m_DataStorageComboBoxes[index]->GetSelectedNode(); + assert(index < m_NodeSelectionWidgets.size()); + return m_NodeSelectionWidgets[index]->GetSelectedNode(); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, Predicate predicate) { this->SetPredicate(index, CreatePredicate(predicate)); } void QmitkDataSelectionWidget::SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate) { - assert(index < m_DataStorageComboBoxes.size()); - m_DataStorageComboBoxes[index]->SetPredicate(predicate); + assert(index < m_NodeSelectionWidgets.size()); + m_NodeSelectionWidgets[index]->SetNodePredicate(predicate); } void QmitkDataSelectionWidget::SetHelpText(const QString& text) { if (!text.isEmpty()) { m_Controls.helpLabel->setText(text); if (!m_Controls.helpLabel->isVisible()) m_Controls.helpLabel->show(); } else { m_Controls.helpLabel->hide(); } } -void QmitkDataSelectionWidget::OnSelectionChanged(const mitk::DataNode* selection) +void QmitkDataSelectionWidget::OnSelectionChanged(QList selection) { - std::vector::iterator it = std::find(m_DataStorageComboBoxes.begin(), m_DataStorageComboBoxes.end(), sender()); - assert(it != m_DataStorageComboBoxes.end()); + std::vector::iterator it = std::find(m_NodeSelectionWidgets.begin(), m_NodeSelectionWidgets.end(), sender()); + assert(it != m_NodeSelectionWidgets.end()); - emit SelectionChanged(std::distance(m_DataStorageComboBoxes.begin(), it), selection); + const mitk::DataNode* result = nullptr; + if (!selection.empty()) + { + result = selection.front(); + } + emit SelectionChanged(std::distance(m_NodeSelectionWidgets.begin(), it), result); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h index 21592bfb24..48cbcdeab7 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidget.h @@ -1,67 +1,67 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkDataSelectionWidget_h #define QmitkDataSelectionWidget_h #include #include #include #include namespace mitk { class NodePredicateBase; } -class QmitkDataStorageComboBox; +class QmitkSingleNodeSelectionWidget; class QmitkDataSelectionWidget : public QWidget { Q_OBJECT public: enum Predicate { ImagePredicate, SegmentationPredicate, SurfacePredicate, ImageAndSegmentationPredicate, ContourModelPredicate }; explicit QmitkDataSelectionWidget(QWidget* parent = nullptr); ~QmitkDataSelectionWidget() override; - unsigned int AddDataStorageComboBox(Predicate predicate); - unsigned int AddDataStorageComboBox(mitk::NodePredicateBase* predicate = nullptr); - unsigned int AddDataStorageComboBox(const QString &labelText, Predicate predicate); - unsigned int AddDataStorageComboBox(const QString &labelText, mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataSelection(Predicate predicate); + unsigned int AddDataSelection(mitk::NodePredicateBase* predicate = nullptr); + unsigned int AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, Predicate predicate); + unsigned int AddDataSelection(const QString &labelText, const QString &info, const QString &popupTitel, const QString &popupHint, mitk::NodePredicateBase* predicate = nullptr); mitk::DataStorage::Pointer GetDataStorage() const; mitk::DataNode::Pointer GetSelection(unsigned int index); void SetPredicate(unsigned int index, Predicate predicate); void SetPredicate(unsigned int index, mitk::NodePredicateBase* predicate); void SetHelpText(const QString& text); signals: void SelectionChanged(unsigned int index, const mitk::DataNode* selection); private slots: - void OnSelectionChanged(const mitk::DataNode* selection); + void OnSelectionChanged(QList selection); private: Ui::QmitkDataSelectionWidgetControls m_Controls; - std::vector m_DataStorageComboBoxes; + std::vector m_NodeSelectionWidgets; }; #endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui index 1849a496d9..6d6fcf1369 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/Common/QmitkDataSelectionWidgetControls.ui @@ -1,64 +1,94 @@ QmitkDataSelectionWidgetControls 0 0 333 191 - + + 0 + + + 0 + + + 0 + + 0 + + + 0 + 0 + + Data Selection + + + 0 + 0 + + - + + 0 + + + 0 + + + 0 + + 0 - + 0 0 color: red true diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui index 13c10e8817..2757115a88 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationControls.ui @@ -1,496 +1,497 @@ QmitkSegmentationControls 0 0 237 591 0 0 0 0 MS Shell Dlg 2 8 50 false false false false QmitkSegmentation QLayout::SetMinimumSize 6 6 6 6 0 0 Data Selection 6 6 6 6 QLayout::SetMinimumSize 4 0 0 Patient Image 0 0 Segmentation 0 0 Create a new segmentation &New... :/segmentation/btnNew.png:/segmentation/btnNew.png Qt::ToolButtonTextOnly - - - - 0 - 0 - - - + + + + 0 + 40 + + + - - - - 0 - 0 - - - + + + + 0 + 40 + + + 0 0 200 0 0 200 0 0 200 0 0 200 0 0 200 0 0 200 0 0 84 82 78 84 82 78 84 82 78 50 false Please load an image! true 0 0 Qt::LeftToRight QTabWidget::tab-bar { alignment: middle; } QTabWidget::North QTabWidget::Triangular 0 0 0 Qt::LeftToRight false 2D Tools 6 6 6 6 0 0 50 false 0 0 50 false 0 0 50 false Qt::Vertical 20 40 0 0 3D Tools 6 6 6 6 0 0 50 false 0 0 50 false Qt::Vertical 20 40 - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
- + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ QmitkToolSelectionBox QWidget
QmitkToolSelectionBox.h
QmitkSlicesInterpolator QWidget
QmitkSlicesInterpolator.h
QmitkToolGUIArea QWidget
QmitkToolGUIArea.h
QmitkToolReferenceDataSelectionBox.h QmitkToolGUIArea.h QmitkToolSelectionBox.h QmitkSlicesInterpolator.h
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp index 29c2fb6189..415d586d47 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1168 +1,941 @@ /*============================================================================ 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 "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkStatusBar.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include "QmitkSegmentationView.h" #include #include "mitkVtkResliceInterpolationProperty.h" #include "mitkApplicationCursor.h" #include "mitkSegmentationObjectFactory.h" #include "mitkPluginActivator.h" #include "mitkCameraController.h" #include "mitkLabelSetImage.h" #include "mitkImageTimeSelector.h" +#include "mitkNodePredicateFunction.h" #include #include "usModuleResource.h" #include "usModuleResourceStream.h" //micro service to get the ToolManager instance #include "mitkToolManagerProvider.h" #include #include const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; QmitkSegmentationView::QmitkSegmentationView() : m_Parent(nullptr) , m_Controls(nullptr) , m_RenderWindowPart(nullptr) , m_MouseCursorSet(false) , m_DataSelectionChanged(false) - , m_AutoSelectionEnabled(false) { mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_IsNotAHelperObject = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(true))); m_IsOfTypeImagePredicate = mitk::NodePredicateAnd::New(validImages, m_IsNotAHelperObject); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New(isBinaryPredicate); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isBinaryPredicate); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New(m_IsOfTypeImagePredicate, isNotBinaryPredicate); m_IsASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, mitk::TNodePredicateDataType::New()); m_IsAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New())); } QmitkSegmentationView::~QmitkSegmentationView() { if (m_Controls) { SetToolSelectionBoxesEnabled(false); // deactivate all tools mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); // removing all observers for (NodeTagMapType::iterator dataIter = m_WorkingDataObserverTags.begin(); dataIter != m_WorkingDataObserverTags.end(); ++dataIter) { (*dataIter).first->GetProperty("visible")->RemoveObserver((*dataIter).second); } m_WorkingDataObserverTags.clear(); - for (NodeTagMapType::iterator dataIter = m_BinaryPropertyObserverTags.begin(); dataIter != m_BinaryPropertyObserverTags.end(); ++dataIter) - { - (*dataIter).first->GetProperty("binary")->RemoveObserver((*dataIter).second); - } - m_BinaryPropertyObserverTags.clear(); - mitk::RenderingManager::GetInstance()->RemoveObserver(m_RenderingManagerObserverTag); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); SetToolManagerSelection(nullptr, nullptr); } delete m_Controls; } -void QmitkSegmentationView::NewNodesGenerated() -{ - MITK_WARN << "Use of deprecated function: NewNodesGenerated!! This function is empty and will be removed in the next time!"; -} - void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); if (!toolManager) return; for (mitk::ToolManager::DataVectorType::iterator iter = nodes->begin(); iter != nodes->end(); ++iter) { this->FireNodeSelected( *iter ); // only last iteration meaningful, multiple generated objects are not taken into account here } } void QmitkSegmentationView::Visible() { } void QmitkSegmentationView::Hidden() { } void QmitkSegmentationView::Activated() { } void QmitkSegmentationView::Deactivated() { } void QmitkSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_RenderWindowPart != renderWindowPart) { m_RenderWindowPart = renderWindowPart; } if (m_Parent) { m_Parent->setEnabled(true); } // tell the interpolation about tool manager, data storage and render window part if (m_Controls) { mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage(this->GetDataStorage()); QList controllers; controllers.push_back(renderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(renderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls->m_SlicesInterpolator->Initialize(toolManager, controllers); } } void QmitkSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_RenderWindowPart = nullptr; if (m_Parent) { m_Parent->setEnabled(false); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Controls != nullptr) { bool slimView = prefs->GetBool("slim view", false); m_Controls->m_ManualToolSelectionBox2D->SetShowNames(!slimView); m_Controls->m_ManualToolSelectionBox3D->SetShowNames(!slimView); m_Controls->btnNewSegmentation->setToolButtonStyle(slimView ? Qt::ToolButtonIconOnly : Qt::ToolButtonTextOnly); } - m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); + auto autoSelectionEnabled = prefs->GetBool("auto selection", true); + m_Controls->patImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); + m_Controls->segImageSelector->SetAutoSelectNewNodes(autoSelectionEnabled); this->ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::ConstPointer image = dynamic_cast(node->GetData()); if (image.IsNotNull()) { if (image->GetDimension() > 1) { // ask about the name and organ type of the new segmentation QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); // needs a QWidget as parent, "this" is not QWidget QStringList organColors = mitk::OrganNamesHandling::GetDefaultOrganColorString();; dialog->SetSuggestionList(organColors); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { // user clicked cancel or pressed Esc or something similar return; } if (image->GetDimension() > 3) { auto result = QMessageBox::question(m_Parent, tr("Generate a static mask?"),tr("The selected image has multiple time steps. You can either generate a simple/static masks resembling the geometry of the first timestep of the image. Or you can generate a dynamic mask that equals the selected image in geometry and number of timesteps; thus a dynamic mask can change over time (e.g. according to the image)."), tr("Yes, generate a static mask"), tr("No, generate a dynamic mask"), QString(), 0,0); if (result == 0) { auto selector = mitk::ImageTimeSelector::New(); selector->SetInput(image); selector->SetTimeNr(0); selector->Update(); const auto refTimeGeometry = image->GetTimeGeometry(); auto newTimeGeometry = mitk::ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(refTimeGeometry->GetMinimumTimePoint()); newTimeGeometry->SetStepDuration(refTimeGeometry->GetMaximumTimePoint() - refTimeGeometry->GetMinimumTimePoint()); mitk::Image::Pointer newImage = selector->GetOutput(); newTimeGeometry->SetTimeStepGeometry(image->GetGeometry(), 0); newImage->SetTimeGeometry(newTimeGeometry); image = newImage; } } // ask the user about an organ type and name, add this information to the image's (!) propertylist // create a new image of the same dimensions and smallest possible pixel type mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { std::string newNodeName = dialog->GetSegmentationName().toStdString(); if (newNodeName.empty()) { newNodeName = "no_name"; } mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode(image, newNodeName, dialog->GetColor()); // initialize showVolume to false to prevent recalculating the volume while working on the segmentation emptySegmentation->SetProperty("showVolume", mitk::BoolProperty::New(false)); if (!emptySegmentation) { return; // could be aborted by user } mitk::OrganNamesHandling::UpdateOrganList(organColors, dialog->GetSegmentationName(), dialog->GetColor()); // escape ';' here (replace by '\;'), see longer comment above QString stringForStorage = organColors.replaceInStrings(";", "\\;").join(";"); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->Put("Organ-Color-List", stringForStorage); this->GetPreferences()->Flush(); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)) { mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDataStorage()->Add(emptySegmentation, node); // add as a child, because the segmentation "derives" from the original - this->FireNodeSelected(emptySegmentation); - this->OnSelectionChanged(emptySegmentation); - - m_Controls->segImageSelector->SetSelectedNode(emptySegmentation); + m_Controls->segImageSelector->SetCurrentSelectedNode(emptySegmentation); mitk::RenderingManager::GetInstance()->InitializeViews(emptySegmentation->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } catch (const std::bad_alloc&) { QMessageBox::warning(nullptr, tr("Create new segmentation"), tr("Could not allocate memory for new segmentation")); } } } else { QMessageBox::information(nullptr, tr("Segmentation"), tr("Segmentation is currently not supported for 2D images")); } } } else { MITK_ERROR << "'Create new segmentation' button should never be clickable unless a patient image is selected..."; } } void QmitkSegmentationView::OnVisiblePropertyChanged() { - mitk::DataNode* selectedNode = m_Controls->segImageSelector->GetSelectedNode(); - if ( !selectedNode ) - { - this->SetToolSelectionBoxesEnabled(false); - return; - } - - mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); - bool selectedNodeIsVisible = renderWindowPart && selectedNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); - - if (!selectedNodeIsVisible) - { - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); - } - else - { - this->SetToolSelectionBoxesEnabled(true); - this->UpdateWarningLabel(""); - } -} - -void QmitkSegmentationView::OnBinaryPropertyChanged() -{ - mitk::DataStorage::SetOfObjects::ConstPointer patImages = m_Controls->patImageSelector->GetNodes(); - - for (mitk::DataStorage::SetOfObjects::ConstIterator it = patImages->Begin(); it != patImages->End(); ++it) - { - const mitk::DataNode* node = it->Value(); - if(m_IsASegmentationImagePredicate->CheckNode(node)) - { - m_Controls->patImageSelector->RemoveNode(node); - m_Controls->segImageSelector->AddNode(node); - this->SetToolManagerSelection(nullptr,nullptr); - return; - } - } - - mitk::DataStorage::SetOfObjects::ConstPointer segImages = m_Controls->segImageSelector->GetNodes(); - - for (mitk::DataStorage::SetOfObjects::ConstIterator it = segImages->Begin(); it != segImages->End(); ++it) - { - const mitk::DataNode* node = it->Value(); - if(!m_IsASegmentationImagePredicate->CheckNode(node)) - { - m_Controls->segImageSelector->RemoveNode(node); - m_Controls->patImageSelector->AddNode(node); - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) - { - mitk::ToolManagerProvider::GetInstance()->GetToolManager()->SetWorkingData(nullptr); - } - return; - } - } + this->CheckRenderingState(); } void QmitkSegmentationView::NodeAdded(const mitk::DataNode *node) { - if (!m_IsOfTypeImagePredicate->CheckNode(node)) + if (!m_IsASegmentationImagePredicate->CheckNode(node)) { return; } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(const_cast(node), node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); - itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); - command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); - m_BinaryPropertyObserverTags.insert(std::pair(const_cast(node), node->GetProperty("binary")->AddObserver(itk::ModifiedEvent(), command2))); - ApplyDisplayOptions(const_cast(node)); } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { if (m_IsASegmentationImagePredicate->CheckNode(node)) { //First of all remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; if ((mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) && m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { this->SetToolManagerSelection(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0), nullptr); this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::Image* image = dynamic_cast(node->GetData()); mitk::SurfaceInterpolationController::GetInstance()->RemoveInterpolationSession(image); } + mitk::DataNode* tempNode = const_cast(node); - //Since the binary property could be changed during runtime by the user - if (m_IsOfTypeImagePredicate->CheckNode(node)) + //Remove observer if one was registered + auto finding = m_WorkingDataObserverTags.find(tempNode); + if (finding != m_WorkingDataObserverTags.end()) { node->GetProperty("visible")->RemoveObserver(m_WorkingDataObserverTags[tempNode]); m_WorkingDataObserverTags.erase(tempNode); - node->GetProperty("binary")->RemoveObserver(m_BinaryPropertyObserverTags[tempNode]); - m_BinaryPropertyObserverTags.erase(tempNode); - } - - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) == node) - { - //as we don't know which node was actually removed e.g. our reference node, disable 'New Segmentation' button. - //consider the case that there is no more image in the datastorage - this->SetToolManagerSelection(nullptr, nullptr); - this->SetToolSelectionBoxesEnabled(false); } } -void QmitkSegmentationView::OnPatientComboBoxSelectionChanged( const mitk::DataNode* node ) +void QmitkSegmentationView::OnPatientSelectionChanged(QList nodes) { - //mitk::DataNode* selectedNode = const_cast(node); - if( node != nullptr ) + if(! nodes.empty()) { this->UpdateWarningLabel(""); - mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); - if (segNode) + auto node = nodes.first(); + + auto geometryCheck = [node](const mitk::DataNode * segNode) { - mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDataStorage()->GetSources(segNode, m_IsAPatientImagePredicate); - bool isSourceNode(false); + return QmitkSegmentationView::CheckForSameGeometry(segNode, node); + }; + mitk::NodePredicateFunction::Pointer hasCorrectGeo = mitk::NodePredicateFunction::New(geometryCheck); + auto segPredicate = mitk::NodePredicateAnd::New(m_IsASegmentationImagePredicate.GetPointer(), hasCorrectGeo.GetPointer()); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = possibleParents->Begin(); it != possibleParents->End(); it++) - { - if (it.Value() == node) - isSourceNode = true; - } + m_Controls->segImageSelector->SetNodePredicate(segPredicate); - if ( !isSourceNode && (!this->CheckForSameGeometry(segNode, node) || possibleParents->Size() > 0 )) - { - this->SetToolManagerSelection(node, nullptr); - this->SetToolSelectionBoxesEnabled( false ); - this->UpdateWarningLabel(tr("The selected patient image does not match with the selected segmentation!")); - } - else if ((!isSourceNode && this->CheckForSameGeometry(segNode, node)) || isSourceNode ) - { - this->SetToolManagerSelection(node, segNode); - //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are - //loaded separately - int layer(10); - node->GetIntProperty("layer", layer); - layer++; - segNode->SetProperty("layer", mitk::IntProperty::New(layer)); - //this->UpdateWarningLabel(""); - RenderingManagerReinitialized(); - } + mitk::DataNode* segNode = m_Controls->segImageSelector->GetSelectedNode(); + this->SetToolManagerSelection(node, segNode); + if (segNode) + { + //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are + //loaded separately + int layer(10); + node->GetIntProperty("layer", layer); + layer++; + segNode->SetProperty("layer", mitk::IntProperty::New(layer)); + this->CheckRenderingState(); } else { - this->SetToolManagerSelection(node, nullptr); this->SetToolSelectionBoxesEnabled( false ); this->UpdateWarningLabel(tr("Select or create a segmentation")); } } else { - this->UpdateWarningLabel(tr("Please select an image!")); - this->SetToolSelectionBoxesEnabled( false ); + m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); + this->UpdateWarningLabel(tr("Please select an image!")); + this->SetToolSelectionBoxesEnabled( false ); } } -void QmitkSegmentationView::OnSegmentationComboBoxSelectionChanged(const mitk::DataNode *node) +void QmitkSegmentationView::OnSegmentationSelectionChanged(QList nodes) { - if (node == nullptr) + if (nodes.empty()) { this->UpdateWarningLabel(tr("Select or create a segmentation")); this->SetToolSelectionBoxesEnabled( false ); return; } - mitk::DataNode* refNode = m_Controls->patImageSelector->GetSelectedNode(); + auto refNode = m_Controls->patImageSelector->GetSelectedNode(); + auto segNode = nodes.front(); - RenderingManagerReinitialized(); - if ( m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further + if (!refNode) + { + this->UpdateWarningLabel(tr("Please select the matching patient image!")); + this->SetToolSelectionBoxesEnabled(false); + this->SetToolManagerSelection(nullptr, segNode); + return; + } + + this->CheckRenderingState(); + if ( m_Controls->lblSegmentationWarnings->isVisible()) // "this->CheckRenderingState()" caused a warning. we do not need to go any further return; - if (m_AutoSelectionEnabled) + this->SetToolManagerSelection(refNode, segNode); + + if (segNode) { - this->OnSelectionChanged(const_cast(node)); + //Doing this we can assure that the segmenation is always visible if the segmentation and the patient image are + //loaded separately + int layer(10); + refNode->GetIntProperty("layer", layer); + layer++; + segNode->SetProperty("layer", mitk::IntProperty::New(layer)); } else { - mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDataStorage()->GetSources(node, m_IsAPatientImagePredicate); - - if ( possibleParents->Size() == 1 ) - { - mitk::DataNode* parentNode = possibleParents->ElementAt(0); - - if (parentNode != refNode) - { - this->UpdateWarningLabel(tr("The selected segmentation does not match with the selected patient image!")); - this->SetToolSelectionBoxesEnabled( false ); - this->SetToolManagerSelection(nullptr, node); - } - else - { - this->UpdateWarningLabel(""); - this->SetToolManagerSelection(refNode, node); - } - } - else if (refNode && this->CheckForSameGeometry(node, refNode)) - { - this->UpdateWarningLabel(""); - this->SetToolManagerSelection(refNode, node); - } - else if (!refNode || !this->CheckForSameGeometry(node, refNode)) - { - this->UpdateWarningLabel(tr("Please select the matching patient image!")); - } + this->SetToolSelectionBoxesEnabled(false); + this->UpdateWarningLabel(tr("Select or create a segmentation")); } mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); - if (!renderWindowPart || !node->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) + if (!renderWindowPart || !segNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) { this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); this->SetToolSelectionBoxesEnabled( false ); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } -void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) -{ - berry::IWorkbenchPart::Pointer nullPart; - QList nodes; - nodes.push_back(node); - this->OnSelectionChanged(nullPart, nodes); -} - -void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) -{ - if (nodes.size() != 0) - { - std::string markerName = "Position"; - unsigned int numberOfNodes = nodes.size(); - std::string nodeName = nodes.at(0)->GetName(); - if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) - { - OnContourMarkerSelected(nodes.at(0)); - return; - } - } - - if (m_AutoSelectionEnabled) - { - if (nodes.size() == 0 && m_Controls->patImageSelector->GetSelectedNode().IsNull()) - { - SetToolManagerSelection(nullptr, nullptr); - } - else if (nodes.size() == 1) - { - mitk::DataNode::Pointer selectedNode = nodes.at(0); - if (selectedNode.IsNull()) - { - return; - } - - mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); - if (selectedImage.IsNull()) - { - SetToolManagerSelection(nullptr, nullptr); - return; - } - - if (m_IsASegmentationImagePredicate->CheckNode(selectedNode)) - { - // set all nodes to invisible - mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsNotAHelperObject); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) - { - (*iter)->SetVisibility(false); - } - - // if a segmentation is selected find a possible patient image (a parent node) - mitk::DataStorage::SetOfObjects::ConstPointer sources = GetDataStorage()->GetSources(selectedNode, m_IsAPatientImagePredicate); - mitk::DataNode::Pointer sourceNode; - if (sources->Size() != 0) - { - // found one or more sources - use the first one - sourceNode = sources->ElementAt(0); - sourceNode->SetVisibility(true); - selectedNode->SetVisibility(true); - SetToolManagerSelection(sourceNode, selectedNode); - - // set all child nodes of the segmentation to visible - mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(selectedNode, m_IsNotAHelperObject, false); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = derivations->begin(); iter != derivations->end(); ++iter) - { - (*iter)->SetVisibility(true); - } - } - else - { - // did not find a source / patient image, check all images and compare geometry - mitk::DataStorage::SetOfObjects::ConstPointer possiblePatientImages = GetDataStorage()->GetSubset(m_IsAPatientImagePredicate); - for (mitk::DataStorage::SetOfObjects::ConstIterator iter = possiblePatientImages->Begin(); iter != possiblePatientImages->End(); ++iter) - { - sourceNode = iter->Value(); - if (CheckForSameGeometry(selectedNode, iter->Value())) - { - sourceNode->SetVisibility(true); - selectedNode->SetVisibility(true); - SetToolManagerSelection(sourceNode, selectedNode); - - // set all child nodes of the segmentation to visible - mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(selectedNode, m_IsNotAHelperObject, false); - for (mitk::DataStorage::SetOfObjects::const_iterator iter = derivations->begin(); iter != derivations->end(); ++iter) - { - (*iter)->SetVisibility(true); - } - - // doing this we can assure that the segmentation is always visible if the segmentation and the patient image are at the - // same level in the data manager - int layer(10); - sourceNode->GetIntProperty("layer", layer); - layer++; - selectedNode->SetProperty("layer", mitk::IntProperty::New(layer)); - return; - } - } - // did not find a source / patient image with the same geometry - SetToolManagerSelection(nullptr, selectedNode); - } - mitk::RenderingManager::GetInstance()->InitializeViews(selectedNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); - } - else - { - if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetReferenceData(0) != selectedNode) - { - SetToolManagerSelection(selectedNode, nullptr); - // may be a bug in the selection services. A node which is deselected will be passed as selected node to the OnSelectionChanged function - mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); - if (renderWindowPart && !selectedNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer())) - { - selectedNode->SetVisibility(true); - } - UpdateWarningLabel(tr("The selected patient image does not match with the selected segmentation!")); - SetToolSelectionBoxesEnabled(false); - } - } - } - - if (m_Controls->lblSegmentationWarnings->isVisible()) // "RenderingManagerReinitialized()" caused a warning. we do not need to go any further - { - return; - } - RenderingManagerReinitialized(); - } -} - void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { QmitkRenderWindow* selectedRenderWindow = nullptr; QmitkRenderWindow* axialRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("axial"); QmitkRenderWindow* sagittalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("sagittal"); QmitkRenderWindow* coronalRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("coronal"); QmitkRenderWindow* _3DRenderWindow = GetRenderWindowPart(mitk::WorkbenchUtil::OPEN)->GetQmitkRenderWindow("3d"); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, _3DRenderWindow->GetRenderer())) { selectedRenderWindow = _3DRenderWindow; } // make node visible if (selectedRenderWindow) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t+1).c_str())-1; { ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); context->ungetService(ppmRef); } selectedRenderWindow->GetRenderer()->GetCameraController()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } +void QmitkSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes) +{ + if (nodes.size() != 0) + { + std::string markerName = "Position"; + unsigned int numberOfNodes = nodes.size(); + std::string nodeName = nodes.at(0)->GetName(); + if ((numberOfNodes == 1) && (nodeName.find(markerName) == 0)) + { + this->OnContourMarkerSelected(nodes.at(0)); + return; + } + } +} + void QmitkSegmentationView::OnTabWidgetChanged(int id) { //always disable tools on tab changed mitk::ToolManagerProvider::GetInstance()->GetToolManager()->ActivateTool(-1); //2D Tab ID = 0 //3D Tab ID = 1 if (id == 0) { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); //Deactivate possible active tool //TODO Remove possible visible interpolations -> Maybe changes in SlicesInterpolator } else { //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox2D->hide(); m_Controls->m_ManualToolSelectionBox3D->show(); //Deactivate possible active tool } } -void QmitkSegmentationView::InitToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) -{ - // initial tool manager selection, called from 'CreateQtPartControl' - mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); - toolManager->SetReferenceData(const_cast(referenceData)); - toolManager->SetWorkingData(const_cast(workingData)); - - // check original image - m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); - if (referenceData) - { - UpdateWarningLabel(""); - } -} - -void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData) +void QmitkSegmentationView::SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData) { // called as a result of new BlueBerry selections // tells the ToolManager for manual segmentation about new selections // updates GUI information about what the user should select mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData(const_cast(workingData)); - // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != nullptr); - if (referenceData) - { - UpdateWarningLabel(""); - disconnect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - m_Controls->patImageSelector->setCurrentIndex(m_Controls->patImageSelector->Find(referenceData)); - connect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - - // check segmentation - if (workingData) - { - //FireNodeSelected(const_cast(workingData)); - - disconnect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); - m_Controls->segImageSelector->setCurrentIndex(m_Controls->segImageSelector->Find(workingData)); - connect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); - } - } } void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent) { return; } // check all images and segmentations in DataStorage: // (items in brackets are implicitly done by previous steps) // 1. // if a reference image is selected, // show the reference image // and hide all other images (orignal and segmentation), // (and hide all segmentations of the other original images) // and show all the reference's segmentations // if no reference image is selected, do do nothing // // 2. // if a segmentation is selected, // show it // (and hide all all its siblings (childs of the same parent, incl, nullptr parent)) // if no segmentation is selected, do nothing if (!m_Controls) { return; // might happen on initialization (preferences loaded) } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); mitk::DataNode::Pointer referenceData = toolManager->GetReferenceData(0); mitk::DataNode::Pointer workingData = toolManager->GetWorkingData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDataStorage()->GetSubset(m_IsASegmentationImagePredicate); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility node->SetVisibility(node == referenceData); } } // 2. if (workingData.IsNotNull()) workingData->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) { return; } mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(GetPreferences()->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(GetPreferences()->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage = dynamic_cast(node->GetData()); if (nullptr != labelSetImage) { // node is actually a multi label segmentation, // but its outline property can be set in the 'single label' segmentation preference page as well node->SetProperty("labelset.contour.active", drawOutline); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } else { // node is a 'single label' segmentation bool isBinary = false; node->GetBoolProperty("binary", isBinary); if (isBinary) { node->SetProperty("outline binary", drawOutline); node->SetProperty("outline width", mitk::FloatProperty::New(2.0)); //node->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); node->SetProperty("volumerendering", volumeRendering); // force render window update to show outline node->GetData()->Modified(); } } } -void QmitkSegmentationView::RenderingManagerReinitialized() +void QmitkSegmentationView::CheckRenderingState() { - if (!this->GetRenderWindowPart()) - { - return; - } + mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); + mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); + + if (!workingNode) + { + this->SetToolSelectionBoxesEnabled(false); + this->UpdateWarningLabel(tr("Select or create a segmentation")); + return; + } + + bool selectedNodeIsVisible = renderWindowPart && workingNode->IsVisible(renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()); + + if (!selectedNodeIsVisible) + { + this->SetToolSelectionBoxesEnabled(false); + this->UpdateWarningLabel(tr("The selected segmentation is currently not visible!")); + return; + } /* * Here we check whether the geometry of the selected segmentation image if aligned with the worldgeometry * At the moment it is not supported to use a geometry different from the selected image for reslicing. * For further information see Bug 16063 */ - mitk::DataNode* workingNode = m_Controls->segImageSelector->GetSelectedNode(); + const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (workingNode && worldGeo) { const mitk::BaseGeometry* workingNodeGeo = workingNode->GetData()->GetGeometry(); const mitk::BaseGeometry* worldGeo = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetSliceNavigationController()->GetCurrentGeometry3D(); if (mitk::Equal(*workingNodeGeo->GetBoundingBox(), *worldGeo->GetBoundingBox(), mitk::eps, true)) { this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), workingNode); this->SetToolSelectionBoxesEnabled(true); this->UpdateWarningLabel(""); - } - else - { - this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); - this->SetToolSelectionBoxesEnabled(false); - this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); + return; } } + + this->SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), nullptr); + this->SetToolSelectionBoxesEnabled(false); + this->UpdateWarningLabel(tr("Please perform a reinit on the segmentation image!")); } -bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) const +bool QmitkSegmentationView::CheckForSameGeometry(const mitk::DataNode *node1, const mitk::DataNode *node2) { bool isSameGeometry(true); mitk::Image* image1 = dynamic_cast(node1->GetData()); mitk::Image* image2 = dynamic_cast(node2->GetData()); if (image1 && image2) { mitk::BaseGeometry* geo1 = image1->GetGeometry(); mitk::BaseGeometry* geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } void QmitkSegmentationView::UpdateWarningLabel(QString text) { if (text.size() == 0) m_Controls->lblSegmentationWarnings->hide(); else m_Controls->lblSegmentationWarnings->show(); m_Controls->lblSegmentationWarnings->setText("" + text + ""); } void QmitkSegmentationView::CreateQtPartControl(QWidget* parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls = new Ui::QmitkSegmentationControls; m_Controls->setupUi(parent); m_Controls->patImageSelector->SetDataStorage(GetDataStorage()); - m_Controls->patImageSelector->SetPredicate(m_IsAPatientImagePredicate); + m_Controls->patImageSelector->SetNodePredicate(m_IsAPatientImagePredicate); + m_Controls->patImageSelector->SetSelectionIsOptional(false); + m_Controls->patImageSelector->SetInvalidInfo("Select an image."); + m_Controls->patImageSelector->SetPopUpTitel("Select an image."); + m_Controls->patImageSelector->SetPopUpHint("Select an image that should be used to define the geometry and bounds of the segmentation."); UpdateWarningLabel(tr("Please select an image")); if (m_Controls->patImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(tr("Select or create a new segmentation")); } m_Controls->segImageSelector->SetDataStorage(GetDataStorage()); - m_Controls->segImageSelector->SetPredicate(m_IsASegmentationImagePredicate); + m_Controls->segImageSelector->SetNodePredicate(m_IsASegmentationImagePredicate); + m_Controls->segImageSelector->SetSelectionIsOptional(false); + m_Controls->segImageSelector->SetInvalidInfo("Select a segmentation."); + m_Controls->segImageSelector->SetPopUpTitel("Select a segmentation."); + m_Controls->segImageSelector->SetPopUpHint("Select a segmentation that should be modified. Only segmentation with the same geometry and within the bounds of the reference image are selected."); + if (m_Controls->segImageSelector->GetSelectedNode().IsNotNull()) { UpdateWarningLabel(""); } mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(toolManager); toolManager->SetDataStorage(*(GetDataStorage())); toolManager->InitializeTools(); QString segTools2D = tr("Add Subtract Correction Paint Wipe 'Region Growing' Fill Erase 'Live Wire' '2D Fast Marching'"); QString segTools3D = tr("Threshold 'UL Threshold' Otsu 'Fast Marching 3D' 'Region Growing 3D' Watershed Picking"); std::regex extSegTool2DRegEx("SegTool2D$"); std::regex extSegTool3DRegEx("SegTool3D$"); auto tools = toolManager->GetTools(); for (const auto &tool : tools) { if (std::regex_search(tool->GetNameOfClass(), extSegTool2DRegEx)) { segTools2D.append(QString(" '%1'").arg(tool->GetName())); } else if (std::regex_search(tool->GetNameOfClass(), extSegTool3DRegEx)) { segTools3D.append(QString(" '%1'").arg(tool->GetName())); } } // all part of open source MITK m_Controls->m_ManualToolSelectionBox2D->setEnabled(true); m_Controls->m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox2D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer2D ); m_Controls->m_ManualToolSelectionBox2D->SetDisplayedToolGroups(segTools2D.toStdString()); m_Controls->m_ManualToolSelectionBox2D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); connect( m_Controls->m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int)) ); //setup 3D Tools m_Controls->m_ManualToolSelectionBox3D->setEnabled(true); m_Controls->m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox3D->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer3D ); //specify tools to be added to 3D Tool area m_Controls->m_ManualToolSelectionBox3D->SetDisplayedToolGroups(segTools3D.toStdString()); m_Controls->m_ManualToolSelectionBox3D->SetLayoutColumns(3); m_Controls->m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible ); //Hide 3D selection box, show 2D selection box m_Controls->m_ManualToolSelectionBox3D->hide(); m_Controls->m_ManualToolSelectionBox2D->show(); - // update the list of segmentations - toolManager->NewNodesGenerated += mitk::MessageDelegate(this, &QmitkSegmentationView::NewNodesGenerated); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1(this, &QmitkSegmentationView::NewNodeObjectsGenerated); // create signal/slot connections - connect(m_Controls->patImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnPatientComboBoxSelectionChanged(const mitk::DataNode*))); - connect(m_Controls->segImageSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSegmentationComboBoxSelectionChanged(const mitk::DataNode*))); + connect(m_Controls->patImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnPatientSelectionChanged(QList))); + connect(m_Controls->segImageSelector, SIGNAL(CurrentSelectionChanged(QList)), this, SLOT(OnSegmentationSelectionChanged(QList))); + connect(m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation())); connect(m_Controls->tabWidgetSegmentationTools, SIGNAL(currentChanged(int)), this, SLOT(OnTabWidgetChanged(int))); connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); - mitk::DataStorage::SetOfObjects::ConstPointer patientImages = GetDataStorage()->GetSubset(m_IsAPatientImagePredicate); - if (!patientImages->empty()) - { - OnSelectionChanged(*patientImages->begin()); - } - // set callback function for already existing nodes (images & segmentations) mitk::DataStorage::SetOfObjects::ConstPointer allImages = GetDataStorage()->GetSubset(m_IsOfTypeImagePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnVisiblePropertyChanged); m_WorkingDataObserverTags.insert(std::pair(node, node->GetProperty("visible")->AddObserver(itk::ModifiedEvent(), command))); - - itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); - command2->SetCallbackFunction(this, &QmitkSegmentationView::OnBinaryPropertyChanged); - m_BinaryPropertyObserverTags.insert(std::pair(node, node->GetProperty("binary")->AddObserver(itk::ModifiedEvent(), command2))); } itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); - command->SetCallbackFunction(this, &QmitkSegmentationView::RenderingManagerReinitialized); + command->SetCallbackFunction(this, &QmitkSegmentationView::CheckRenderingState); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver(mitk::RenderingManagerViewsInitializedEvent(), command); - InitToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); + SetToolManagerSelection(m_Controls->patImageSelector->GetSelectedNode(), m_Controls->segImageSelector->GetSelectedNode()); m_RenderWindowPart = GetRenderWindowPart(); if (m_RenderWindowPart) { RenderWindowPartActivated(m_RenderWindowPart); } + + //Should be done last, if everything else is configured because it triggers the autoselection of data. + m_Controls->patImageSelector->SetAutoSelectNewNodes(true); + m_Controls->segImageSelector->SetAutoSelectNewNodes(true); } void QmitkSegmentationView::SetFocus() { m_Controls->btnNewSegmentation->setFocus(); } void QmitkSegmentationView::OnManualTool2DSelected(int id) { if (id >= 0) { std::string text = "Active Tool: \""; mitk::ToolManager* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); text += toolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = toolManager->GetToolById(id)->GetCursorIconResource(); this->SetMouseCursor(resource, 0, 0); } else { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); } } void QmitkSegmentationView::ResetMouseCursor() { if ( m_MouseCursorSet ) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkSegmentationView::SetMouseCursor( const us::ModuleResource& resource, int hotspotX, int hotspotY ) { // Remove previously set mouse cursor if (m_MouseCursorSet) this->ResetMouseCursor(); if (resource) { us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } } void QmitkSegmentationView::SetToolSelectionBoxesEnabled(bool status) { if (status) { m_Controls->m_ManualToolSelectionBox2D->RecreateButtons(); m_Controls->m_ManualToolSelectionBox3D->RecreateButtons(); } m_Controls->m_ManualToolSelectionBox2D->setEnabled(status); m_Controls->m_ManualToolSelectionBox3D->setEnabled(status); m_Controls->m_SlicesInterpolator->setEnabled(status); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h index 32e1ccd3e4..b1e7ee3a0f 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.h @@ -1,169 +1,143 @@ /*============================================================================ 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 QMITKSEGMENTATIONVIEW_H #define QMITKSEGMENTATIONVIEW_H #include #include #include #include #include "ui_QmitkSegmentationControls.h" class QmitkRenderWindow; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_segmentation_internal * \warning Implementation of this class is split up into two .cpp files to make things more compact. Check both this file and QmitkSegmentationOrganNamesHandling.cpp */ class QmitkSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart, public mitk::IRenderWindowPartListener { Q_OBJECT public: QmitkSegmentationView(); ~QmitkSegmentationView() override; typedef std::map NodeTagMapType; - /*! - \brief Invoked when the DataManager selection changed - */ - virtual void OnSelectionChanged(mitk::DataNode* node); - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - - // reaction to new segmentations being created by segmentation tools - void NewNodesGenerated(); void NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType*); void Activated() override; void Deactivated() override; void Visible() override; void Hidden() override; /// /// Sets the focus to an internal widget. /// void SetFocus() override; void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; // BlueBerry's notification about preference changes (e.g. from a dialog) void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; // observer to mitk::RenderingManager's RenderingManagerViewsInitializedEvent event - void RenderingManagerReinitialized(); - - // observer to mitk::SliceController's SliceRotation event - void SliceRotation(const itk::EventObject&); + void CheckRenderingState(); static const std::string VIEW_ID; protected slots: - void OnPatientComboBoxSelectionChanged(const mitk::DataNode* node); - void OnSegmentationComboBoxSelectionChanged(const mitk::DataNode* node); + void OnPatientSelectionChanged(QList nodes); + void OnSegmentationSelectionChanged(QList nodes); // reaction to the button "New segmentation" void CreateNewSegmentation(); void OnManualTool2DSelected(int id); void OnVisiblePropertyChanged(); - void OnBinaryPropertyChanged(); - void OnShowMarkerNodes(bool); void OnTabWidgetChanged(int); protected: // a type for handling lists of DataNodes typedef std::vector NodeList; // GUI setup void CreateQtPartControl(QWidget* parent) override; - // reactions to selection events from data manager (and potential other senders) - //void BlueBerrySelectionChanged(berry::IWorkbenchPart::Pointer sourcepart, berry::ISelection::ConstPointer selection); - mitk::DataNode::Pointer FindFirstRegularImage(std::vector nodes); - mitk::DataNode::Pointer FindFirstSegmentation(std::vector nodes); - - // initially set the tool manager selection from the combo boxes - void InitToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); - // propagate BlueBerry selection to ToolManager for manual segmentation - void SetToolManagerSelection(const mitk::DataNode* referenceData, const mitk::DataNode* workingData); - - // checks if given render window aligns with the slices of given image - bool IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image); + void SetToolManagerSelection(mitk::DataNode* referenceData, mitk::DataNode* workingData); // make sure all images/segmentations look as selected by the users in this view's preferences void ForceDisplayPreferencesUponAllImages(); // decorates a DataNode according to the user preference settings void ApplyDisplayOptions(mitk::DataNode* node); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource&, int hotspotX, int hotspotY); void SetToolSelectionBoxesEnabled(bool); // If a contourmarker is selected, the plane in the related widget will be reoriented according to the marker`s geometry void OnContourMarkerSelected(const mitk::DataNode* node); + void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; + void NodeRemoved(const mitk::DataNode* node) override; void NodeAdded(const mitk::DataNode *node) override; - bool CheckForSameGeometry(const mitk::DataNode*, const mitk::DataNode*) const; + static bool CheckForSameGeometry(const mitk::DataNode*, const mitk::DataNode*); void UpdateWarningLabel(QString text/*, bool overwriteExistingText = true*/); // the Qt parent of our GUI (NOT of this object) QWidget* m_Parent; // our GUI Ui::QmitkSegmentationControls* m_Controls; mitk::IRenderWindowPart* m_RenderWindowPart; unsigned long m_VisibilityChangedObserverTag; bool m_MouseCursorSet; bool m_DataSelectionChanged; NodeTagMapType m_WorkingDataObserverTags; - NodeTagMapType m_BinaryPropertyObserverTags; - unsigned int m_RenderingManagerObserverTag; - bool m_AutoSelectionEnabled; - mitk::NodePredicateNot::Pointer m_IsNotAHelperObject; mitk::NodePredicateAnd::Pointer m_IsOfTypeImagePredicate; mitk::NodePredicateOr::Pointer m_IsASegmentationImagePredicate; mitk::NodePredicateAnd::Pointer m_IsAPatientImagePredicate; }; #endif // QMITKSEGMENTATIONVIEW_H diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp index 6888f48345..d66b78dc14 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp @@ -1,141 +1,141 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkBooleanOperationsWidget.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include static const char* const HelpText = "Select two different segmentations above"; static std::string GetPrefix(mitk::BooleanOperation::Type type) { switch (type) { case mitk::BooleanOperation::Difference: return "DifferenceFrom_"; case mitk::BooleanOperation::Intersection: return "IntersectionWith_"; case mitk::BooleanOperation::Union: return "UnionWith_"; default: assert(false && "Unknown boolean operation type"); return "UNKNOWN_BOOLEAN_OPERATION_WITH_"; } } static void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr) { auto dataNode = mitk::DataNode::New(); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); } QmitkBooleanOperationsWidget::QmitkBooleanOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox("", QmitkDataSelectionWidget::SegmentationPredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox("", QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection("", "Select 1st segmentation", "Select 1st segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection("", "Select 2nd segmentation", "Select 2nd segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect(m_Controls.differenceButton, SIGNAL(clicked()), this, SLOT(OnDifferenceButtonClicked())); connect(m_Controls.intersectionButton, SIGNAL(clicked()), this, SLOT(OnIntersectionButtonClicked())); connect(m_Controls.unionButton, SIGNAL(clicked()), this, SLOT(OnUnionButtonClicked())); } QmitkBooleanOperationsWidget::~QmitkBooleanOperationsWidget() { } void QmitkBooleanOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { auto dataSelectionWidget = m_Controls.dataSelectionWidget; auto nodeA = dataSelectionWidget->GetSelection(0); auto nodeB = dataSelectionWidget->GetSelection(1); if (nodeA.IsNotNull() && nodeB.IsNotNull() && nodeA != nodeB) { dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } else { dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } } void QmitkBooleanOperationsWidget::EnableButtons(bool enable) { m_Controls.differenceButton->setEnabled(enable); m_Controls.intersectionButton->setEnabled(enable); m_Controls.unionButton->setEnabled(enable); } void QmitkBooleanOperationsWidget::OnDifferenceButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Difference); } void QmitkBooleanOperationsWidget::OnIntersectionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Intersection); } void QmitkBooleanOperationsWidget::OnUnionButtonClicked() { this->DoBooleanOperation(mitk::BooleanOperation::Union); } void QmitkBooleanOperationsWidget::DoBooleanOperation(mitk::BooleanOperation::Type type) { auto timeNavigationController = this->GetTimeNavigationController(); assert(timeNavigationController != nullptr); mitk::Image::Pointer segmentationA = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(0)->GetData()); mitk::Image::Pointer segmentationB = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(1)->GetData()); mitk::Image::Pointer result; try { mitk::BooleanOperation booleanOperation(type, segmentationA, segmentationB, timeNavigationController->GetTime()->GetPos()); result = booleanOperation.GetResult(); assert(result.IsNotNull()); auto dataSelectionWidget = m_Controls.dataSelectionWidget; AddToDataStorage( dataSelectionWidget->GetDataStorage(), result, GetPrefix(type) + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); } catch (const mitk::Exception& exception) { MITK_ERROR << "Boolean operation failed: " << exception.GetDescription(); QMessageBox::information(nullptr, "Boolean operation failed", exception.GetDescription()); } } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp index 5211d000ac..eb5efa0705 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ContourModelToImage/QmitkContourModelToImageWidget.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. ============================================================================*/ #include "QmitkContourModelToImageWidget.h" #include "mitkImage.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include #include #include static const char* const HelpText = "Select a image and a contour(set)"; class QmitkContourModelToImageWidgetPrivate { public: QmitkContourModelToImageWidgetPrivate(); ~QmitkContourModelToImageWidgetPrivate(); /** @brief Check if selections is valid. */ void SelectionControl( unsigned int index, const mitk::DataNode* selection); /** @brief Enable buttons if data selction is valid. */ void EnableButtons(bool enable = true); /** @brief Does the actual contour filling */ mitk::Image::Pointer FillContourModelSetIntoImage(mitk::Image *image, mitk::ContourModelSet *contourSet, unsigned int timeStep); Ui::QmitkContourModelToImageWidgetControls m_Controls; QFutureWatcher m_Watcher; }; QmitkContourModelToImageWidgetPrivate::QmitkContourModelToImageWidgetPrivate() { } QmitkContourModelToImageWidgetPrivate::~QmitkContourModelToImageWidgetPrivate() { } void QmitkContourModelToImageWidgetPrivate::EnableButtons(bool enable) { m_Controls.btnProcess->setEnabled(enable); } void QmitkContourModelToImageWidgetPrivate::SelectionControl(unsigned int index, const mitk::DataNode* /*selection*/) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } mitk::Image::Pointer QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage(mitk::Image* image, mitk::ContourModelSet* contourSet, unsigned int timeStep) { // Use mitk::ContourModelSetToImageFilter to fill the ContourModelSet into the image mitk::ContourModelSetToImageFilter::Pointer contourFiller = mitk::ContourModelSetToImageFilter::New(); contourFiller->SetTimeStep(timeStep); contourFiller->SetImage(image); contourFiller->SetInput(contourSet); contourFiller->MakeOutputBinaryOn(); contourFiller->Update(); mitk::Image::Pointer result = contourFiller->GetOutput(); if (result.IsNull()) { MITK_ERROR<<"Could not write the selected contours into the image!"; } result->DisconnectPipeline(); return result; } void QmitkContourModelToImageWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { Q_D(QmitkContourModelToImageWidget); QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { d->EnableButtons(false); dataSelectionWidget->SetHelpText(HelpText); } else { d->SelectionControl(index, selection); } } void QmitkContourModelToImageWidget::OnProcessingFinished() { // Called when processing finished // Adding the result to the data storage Q_D(QmitkContourModelToImageWidget); // Adding the result to the data storage mitk::Image::Pointer result = d->m_Watcher.result(); if (result.IsNotNull()) { QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); mitk::DataNode::Pointer filled = mitk::DataNode::New(); std::stringstream stream; stream << imageNode->GetName(); stream << "_"; stream << contourNode->GetName(); filled->SetName(stream.str()); filled->SetData(result); dataSelectionWidget->GetDataStorage()->Add(filled, imageNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { MITK_ERROR<<"Error filling contours into an image!"; } d->EnableButtons(); } void QmitkContourModelToImageWidget::OnProcessPressed() { Q_D(QmitkContourModelToImageWidget); QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); // Check if data nodes are valid if(imageNode.IsNull() || contourNode.IsNull() ) { MITK_ERROR << "Selection does not contain valid data"; QMessageBox::information( this, "Contour To Image", "Selection does not contain valid data, please select a binary image and a contour(set)", QMessageBox::Ok ); d->m_Controls.btnProcess->setEnabled(false); return; } mitk::Image::Pointer image = static_cast(imageNode->GetData()); // Check if the image is valid if (image.IsNull()) { MITK_ERROR<<"Error writing contours into image! Invalid image data selected!"; return; } unsigned int timeStep = this->GetTimeNavigationController()->GetTime()->GetPos(); // Check if the selected contours are valid mitk::ContourModelSet::Pointer contourSet; mitk::ContourModel::Pointer contour = dynamic_cast(contourNode->GetData()); if (contour.IsNotNull()) { contourSet = mitk::ContourModelSet::New(); contourSet->AddContourModel(contour); } else { contourSet = static_cast(contourNode->GetData()); if (contourSet.IsNull()) { MITK_ERROR<<"Error writing contours into binary image! Invalid contour data selected!"; return; } } //Disable Buttons during calculation and initialize Progressbar d->EnableButtons(false); // Start the computation in a background thread QFuture< mitk::Image::Pointer > future = QtConcurrent::run(d, &QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage, image, contourSet, timeStep); d->m_Watcher.setFuture(future); } QmitkContourModelToImageWidget::QmitkContourModelToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent), d_ptr(new QmitkContourModelToImageWidgetPrivate()) { Q_D(QmitkContourModelToImageWidget); // Set up UI d->m_Controls.setupUi(this); - d->m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); - d->m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ContourModelPredicate); + d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); + d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ContourModelPredicate); d->m_Controls.dataSelectionWidget->SetHelpText(HelpText); d->EnableButtons(false); // Create connections connect (d->m_Controls.btnProcess, SIGNAL(pressed()), this, SLOT(OnProcessPressed())); connect(d->m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); connect(&d->m_Watcher, SIGNAL(finished()), this, SLOT(OnProcessingFinished())); if( d->m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && d->m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { OnSelectionChanged(0, d->m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkContourModelToImageWidget::~QmitkContourModelToImageWidget() { } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp index 4b0c55f6d1..033d760819 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/ImageMasking/QmitkImageMaskingWidget.cpp @@ -1,298 +1,298 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkImageMaskingWidget.h" #include "mitkImage.h" #include "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include #include #include #include #include static const char* const HelpText = "Select a regular image and a binary image"; QmitkImageMaskingWidget::QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImagePredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SegmentationPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); connect (m_Controls.rbMaskImage, SIGNAL(toggled(bool)), this, SLOT(OnImageMaskingToggled(bool))); connect (m_Controls.rbMaskSurface, SIGNAL(toggled(bool)), this, SLOT(OnSurfaceMaskingToggled(bool))); connect (m_Controls.btnMaskImage, SIGNAL(clicked()), this, SLOT(OnMaskImagePressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkImageMaskingWidget::~QmitkImageMaskingWidget() { } void QmitkImageMaskingWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNull() || node1.IsNull() ) { if( m_Controls.rbMaskImage->isChecked() ) { dataSelectionWidget->SetHelpText(HelpText); } else { dataSelectionWidget->SetHelpText("Select a regular image and a surface"); } this->EnableButtons(false); } else { this->SelectionControl(index, selection); } } void QmitkImageMaskingWidget::SelectionControl(unsigned int index, const mitk::DataNode* selection) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); //if Image-Masking is enabled, check if image-dimension of reference and binary image is identical if( m_Controls.rbMaskImage->isChecked() ) { if( dataSelectionWidget->GetSelection(0) == dataSelectionWidget->GetSelection(1) ) { dataSelectionWidget->SetHelpText("Select two different images above"); this->EnableButtons(false); return; } else if( node.IsNotNull() && selection ) { mitk::Image::Pointer referenceImage = dynamic_cast ( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Image::Pointer maskImage = dynamic_cast ( dataSelectionWidget->GetSelection(1)->GetData() ); if( maskImage.IsNull() || referenceImage->GetLargestPossibleRegion().GetSize() != maskImage->GetLargestPossibleRegion().GetSize() ) { dataSelectionWidget->SetHelpText("Different image sizes cannot be masked"); this->EnableButtons(false); return; } } else { dataSelectionWidget->SetHelpText(HelpText); return; } } dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } void QmitkImageMaskingWidget::EnableButtons(bool enable) { m_Controls.btnMaskImage->setEnabled(enable); } void QmitkImageMaskingWidget::OnImageMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a regular image and a binary image"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::SegmentationPredicate); } } void QmitkImageMaskingWidget::OnSurfaceMaskingToggled(bool status) { if (status) { m_Controls.dataSelectionWidget->SetHelpText("Select a regular image and a surface"); m_Controls.dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::SurfacePredicate); } } void QmitkImageMaskingWidget::OnMaskImagePressed() { //Disable Buttons during calculation and initialize Progressbar this->EnableButtons(false); mitk::ProgressBar::GetInstance()->AddStepsToDo(4); mitk::ProgressBar::GetInstance()->Progress(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; //create result image, get mask node and reference image mitk::Image::Pointer resultImage(nullptr); mitk::DataNode::Pointer maskingNode = dataSelectionWidget->GetSelection(1); mitk::Image::Pointer referenceImage = static_cast(dataSelectionWidget->GetSelection(0)->GetData()); if(referenceImage.IsNull() || maskingNode.IsNull() ) { MITK_ERROR << "Selection does not contain an image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain an image", QMessageBox::Ok ); m_Controls.btnMaskImage->setEnabled(true); return; } //Do Image-Masking if (m_Controls.rbMaskImage->isChecked()) { mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer maskImage = dynamic_cast ( maskingNode->GetData() ); if(maskImage.IsNull() ) { MITK_ERROR << "Selection does not contain a binary image"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a binary image", QMessageBox::Ok ); this->EnableButtons(); return; } if( referenceImage->GetLargestPossibleRegion().GetSize() == maskImage->GetLargestPossibleRegion().GetSize() ) { resultImage = this->MaskImage( referenceImage, maskImage ); } } //Do Surface-Masking else { mitk::ProgressBar::GetInstance()->Progress(); //1. convert surface to image mitk::Surface::Pointer surface = dynamic_cast ( maskingNode->GetData() ); //TODO Get 3D Surface of current time step if(surface.IsNull()) { MITK_ERROR << "Selection does not contain a surface"; QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer maskImage = this->ConvertSurfaceToImage( referenceImage, surface ); //2. mask reference image with mask image if(maskImage.IsNotNull() && referenceImage->GetLargestPossibleRegion().GetSize() == maskImage->GetLargestPossibleRegion().GetSize() ) { resultImage = this->MaskImage( referenceImage, maskImage ); } } mitk::ProgressBar::GetInstance()->Progress(); if( resultImage.IsNull() ) { MITK_ERROR << "Masking failed"; QMessageBox::information( this, "Image and Surface Masking", "Masking failed. For more information please see logging window.", QMessageBox::Ok ); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(4); return; } //Add result to data storage this->AddToDataStorage( dataSelectionWidget->GetDataStorage(), resultImage, dataSelectionWidget->GetSelection(0)->GetName() + "_" + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); this->EnableButtons(); mitk::ProgressBar::GetInstance()->Progress(); } mitk::Image::Pointer QmitkImageMaskingWidget::MaskImage(mitk::Image::Pointer referenceImage, mitk::Image::Pointer maskImage ) { mitk::Image::Pointer resultImage(nullptr); mitk::MaskImageFilter::Pointer maskFilter = mitk::MaskImageFilter::New(); maskFilter->SetInput( referenceImage ); maskFilter->SetMask( maskImage ); maskFilter->OverrideOutsideValueOn(); maskFilter->SetOutsideValue( referenceImage->GetStatistics()->GetScalarValueMin() ); try { maskFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } resultImage = maskFilter->GetOutput(); return resultImage; } mitk::Image::Pointer QmitkImageMaskingWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::ProgressBar::GetInstance()->Progress(); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(image); try { surfaceToImageFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer resultImage = mitk::Image::New(); resultImage = surfaceToImageFilter->GetOutput(); return resultImage; } void QmitkImageMaskingWidget::AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent ) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetName(name); dataNode->SetData(segmentation); dataStorage->Add(dataNode, parent); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp index 1807185302..d67b951f87 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/MorphologicalOperations/QmitkMorphologicalOperationsWidget.cpp @@ -1,251 +1,251 @@ /*============================================================================ 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 "QmitkMorphologicalOperationsWidget.h" #include #include #include static const char* const HelpText = "Select a segmentation above"; QmitkMorphologicalOperationsWidget::QmitkMorphologicalOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SegmentationPredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); connect(m_Controls.btnClosing, SIGNAL(clicked()), this, SLOT(OnClosingButtonClicked())); connect(m_Controls.btnOpening, SIGNAL(clicked()), this, SLOT(OnOpeningButtonClicked())); connect(m_Controls.btnDilatation, SIGNAL(clicked()), this, SLOT(OnDilatationButtonClicked())); connect(m_Controls.btnErosion, SIGNAL(clicked()), this, SLOT(OnErosionButtonClicked())); connect(m_Controls.btnFillHoles, SIGNAL(clicked()), this, SLOT(OnFillHolesButtonClicked())); connect(m_Controls.radioButtonMorphoCross, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); connect(m_Controls.radioButtonMorphoBall, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if (m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull()) this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); } QmitkMorphologicalOperationsWidget::~QmitkMorphologicalOperationsWidget() { } void QmitkMorphologicalOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); if (node.IsNotNull()) { m_Controls.dataSelectionWidget->SetHelpText(""); this->EnableButtons(true); } else { m_Controls.dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } } void QmitkMorphologicalOperationsWidget::EnableButtons(bool enable) { m_Controls.btnClosing->setEnabled(enable); m_Controls.btnDilatation->setEnabled(enable); m_Controls.btnErosion->setEnabled(enable); m_Controls.btnFillHoles->setEnabled(enable); m_Controls.btnOpening->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnRadioButtonsClicked() { bool enable = m_Controls.radioButtonMorphoBall->isChecked(); m_Controls.sliderMorphFactor->setEnabled(enable); m_Controls.spinBoxMorphFactor->setEnabled(enable); } void QmitkMorphologicalOperationsWidget::OnClosingButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); try { int factor = m_Controls.spinBoxMorphFactor->isEnabled() ? m_Controls.spinBoxMorphFactor->value() : 1; mitk::MorphologicalOperations::Closing(image, factor, structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnOpeningButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); try { int factor = m_Controls.spinBoxMorphFactor->isEnabled() ? m_Controls.spinBoxMorphFactor->value() : 1; mitk::MorphologicalOperations::Opening(image, factor, structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnDilatationButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); mitk::MorphologicalOperations::StructuralElementType structuralElement = this->CreateStructerElement_UI(); try { int factor = m_Controls.spinBoxMorphFactor->isEnabled() ? m_Controls.spinBoxMorphFactor->value() : 1; mitk::MorphologicalOperations::Dilate(image, factor, structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnErosionButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); try { int factor = m_Controls.spinBoxMorphFactor->isEnabled() ? m_Controls.spinBoxMorphFactor->value() : 1; mitk::MorphologicalOperations::Erode(image, factor, structuralElement); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } void QmitkMorphologicalOperationsWidget::OnFillHolesButtonClicked() { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); mitk::Image::Pointer image = static_cast(node->GetData()); try { mitk::MorphologicalOperations::FillHoles(image); } catch (const itk::ExceptionObject& exception) { MITK_WARN << "Exception caught: " << exception.GetDescription(); QApplication::restoreOverrideCursor(); return; } node->SetData(image); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); QApplication::restoreOverrideCursor(); } mitk::MorphologicalOperations::StructuralElementType QmitkMorphologicalOperationsWidget::CreateStructerElement_UI() { bool ball = m_Controls.radioButtonMorphoBall->isChecked(); int accum_flag = 0; if(ball){ if(m_Controls.planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Ball; // 3D Operation if(m_Controls.planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Ball_Axial; // 2D Operation - Axial plane if(m_Controls.planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Ball_Sagital; // 2D Operation - Sagital plane if(m_Controls.planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Ball_Coronal; // 2D Operation - Coronal plane }else{ if(m_Controls.planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Cross; if(m_Controls.planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Cross_Axial; if(m_Controls.planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Cross_Sagital; if(m_Controls.planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Cross_Coronal; } return (mitk::MorphologicalOperations::StructuralElementType)accum_flag; } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp index 31ebc70831..d358c17492 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp @@ -1,157 +1,157 @@ /*============================================================================ 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 "QmitkSurfaceToImageWidget.h" #include #include #include #include #include #include #include #include #include static const char* const HelpText = "Select an image and a surface above"; QmitkSurfaceToImageWidget::QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); - m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SurfacePredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SurfacePredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); connect (m_Controls.btnSurface2Image, SIGNAL(pressed()), this, SLOT(OnSurface2ImagePressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkSurfaceToImageWidget::~QmitkSurfaceToImageWidget() { } void QmitkSurfaceToImageWidget::EnableButtons(bool enable) { m_Controls.btnSurface2Image->setEnabled(enable); } void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer surfaceNode = dataSelectionWidget->GetSelection(1); if (imageNode.IsNull() || surfaceNode.IsNull() ) { dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } else { mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); if( image->GetTimeSteps() != surface->GetTimeSteps() ) { dataSelectionWidget->SetHelpText("Image and surface are of different size"); this->EnableButtons(false); } else { dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } } } void QmitkSurfaceToImageWidget::OnSurface2ImagePressed() { this->EnableButtons(false); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); if( image.IsNull() || surface.IsNull()) { MITK_ERROR << "Selection does not contain an image and/or a surface"; QMessageBox::information( this, "Surface To Image", "Selection does not contain an image and/or a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer resultImage(nullptr); resultImage = this->ConvertSurfaceToImage( image, surface ); if( resultImage.IsNull() ) { MITK_ERROR << "Convert Surface to binary image failed"; QMessageBox::information( this, "Surface To Image", "Convert Surface to binary image failed", QMessageBox::Ok ); this->EnableButtons(); return; } //create name for result node std::string nameOfResultImage = dataSelectionWidget->GetSelection(0)->GetName(); nameOfResultImage.append("_"); nameOfResultImage.append(dataSelectionWidget->GetSelection(1)->GetName()); //create data node and add to data storage mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); resultNode->SetData( resultImage ); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); // resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); dataSelectionWidget->GetDataStorage()->Add(resultNode, dataSelectionWidget->GetSelection(0)); this->EnableButtons(); } mitk::LabelSetImage::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::ProgressBar::GetInstance()->Progress(); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(image); try { surfaceToImageFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer resultImage = surfaceToImageFilter->GetOutput(); mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); multilabelImage->InitializeByLabeledImage(resultImage); return multilabelImage; }