diff --git a/CMake/FindGit.cmake b/CMake/FindGit.cmake index e2fa61db14..5bc9acf228 100644 --- a/CMake/FindGit.cmake +++ b/CMake/FindGit.cmake @@ -1,80 +1,81 @@ # # FindGit # set(git_candidates git eg) if(WIN32) list(APPEND git_candidates eg.cmd) if(NOT MSYS) # We don't append git.cmd, since it does not correctly return # exit codes, see http://code.google.com/p/msysgit/issues/detail?id=428 list(APPEND git_candidates git.cmd) endif() endif() find_program(GIT_EXECUTABLE ${git_candidates} PATHS "C:/Program Files/Git/bin" "C:/Program Files (x86)/Git/bin" DOC "git command line client") mark_as_advanced(GIT_EXECUTABLE) if(GIT_EXECUTABLE) macro(GIT_IS_REPO dir result_var) - execute_process(COMMAND ${GIT_EXECUTABLE} status + # check if ${dir} is a proper Git repository + execute_process(COMMAND ${GIT_EXECUTABLE} rev-list -n 1 HEAD WORKING_DIRECTORY ${dir} RESULT_VARIABLE GIT_error OUTPUT_QUIET ERROR_QUIET) if(GIT_error EQUAL 0) set(${result_var} 1) else() set(${result_var} 0) endif() endmacro() macro(GIT_WC_INFO dir prefix) execute_process(COMMAND ${GIT_EXECUTABLE} rev-list -n 1 HEAD WORKING_DIRECTORY ${dir} ERROR_VARIABLE GIT_error OUTPUT_VARIABLE ${prefix}_WC_REVISION_HASH OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT ${GIT_error} EQUAL 0) message(SEND_ERROR "Command \"${GIT_EXECUTBALE} rev-list -n 1 HEAD\" in directory ${dir} failed with output:\n${GIT_error}") else() execute_process(COMMAND ${GIT_EXECUTABLE} name-rev ${${prefix}_WC_REVISION_HASH} WORKING_DIRECTORY ${dir} OUTPUT_VARIABLE ${prefix}_WC_REVISION_NAME OUTPUT_STRIP_TRAILING_WHITESPACE) endif() set(${prefix}_WC_GITSVN 0) # In case, git-svn is used, attempt to extract svn info execute_process(COMMAND ${GIT_EXECUTABLE} svn info WORKING_DIRECTORY ${dir} ERROR_VARIABLE git_svn_info_error OUTPUT_VARIABLE ${prefix}_WC_INFO RESULT_VARIABLE git_svn_info_result OUTPUT_STRIP_TRAILING_WHITESPACE) if(${git_svn_info_result} EQUAL 0) set(${prefix}_WC_GITSVN 1) string(REGEX REPLACE "^(.*\n)?URL: ([^\n]+).*" "\\2" ${prefix}_WC_URL "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Revision: ([^\n]+).*" "\\2" ${prefix}_WC_REVISION "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Author: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_AUTHOR "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Rev: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_REV "${${prefix}_WC_INFO}") string(REGEX REPLACE "^(.*\n)?Last Changed Date: ([^\n]+).*" "\\2" ${prefix}_WC_LAST_CHANGED_DATE "${${prefix}_WC_INFO}") endif() endmacro() endif() include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Git DEFAULT_MSG GIT_EXECUTABLE) diff --git a/CMake/mitkSetupVariables.cmake b/CMake/mitkSetupVariables.cmake index 84555e5e77..9177d2560f 100644 --- a/CMake/mitkSetupVariables.cmake +++ b/CMake/mitkSetupVariables.cmake @@ -1,169 +1,169 @@ if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() set(LIBPOSTFIX "") # MITK_VERSION set(MITK_VERSION_MAJOR "2013") set(MITK_VERSION_MINOR "03") -set(MITK_VERSION_PATCH "00") +set(MITK_VERSION_PATCH "99") set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() # Needed early on for redirecting the BlueBerry documentation output dir set(MITK_DOXYGEN_OUTPUT_DIR ${PROJECT_BINARY_DIR}/Documentation/Doxygen CACHE PATH "Output directory for doxygen generated documentation." ) #----------------------------------- # Configuration of module system #----------------------------------- set(MODULES_CONF_DIRNAME modulesConf) set(MODULES_CONF_DIRS ${MITK_BINARY_DIR}/${MODULES_CONF_DIRNAME}) if(NOT UNIX AND NOT MINGW) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() # build the MITK_INCLUDE_DIRS variable set(MITK_INCLUDE_DIRS ${ITK_INCLUDE_DIRS} ${VTK_INCLUDE_DIRS} ${PROJECT_BINARY_DIR} # contains mitkConfig.h and similar files ${MODULES_CONF_DIRS} # contains module *Exports.h files ) set(CORE_DIRECTORIES Common DataManagement Algorithms IO Rendering Interactions Controllers Service) foreach(d ${CORE_DIRECTORIES}) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/Core/Code/${d}) endforeach() #list(APPEND MITK_INCLUDE_DIRS #${ITK_INCLUDE_DIRS} #${VTK_INCLUDE_DIRS} # ) foreach(d Utilities Utilities/ipPic Utilities/pic2vtk Utilities/tinyxml Utilities/mbilog) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/${d}) endforeach() list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/Utilities/mbilog) if(WIN32) list(APPEND MITK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipPic/win32) endif() # additional include dirs variables set(ANN_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ann/include) set(IPSEGMENTATION_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipSegmentation) # variables containing librariy names set(MITK_CORE_LIBRARIES Mitk) set(VTK_FOR_MITK_LIBRARIES vtkGraphics vtkCommon vtkFiltering vtkGraphics vtkHybrid vtkImaging vtkIO vtkParallel vtkRendering vtkVolumeRendering vtkWidgets ${VTK_JPEG_LIBRARIES} ${VTK_PNG_LIBRARIES} ${VTK_ZLIB_LIBRARIES} ${VTK_EXPAT_LIBRARIES} ${VTK_FREETYPE_LIBRARIES} ) # TODO: maybe solve this with lib depends mechanism of CMake set(UTIL_FOR_MITK_LIBRARIES mitkIpPic mitkIpFunc mbilog) set(LIBRARIES_FOR_MITK_CORE ${UTIL_FOR_MITK_LIBRARIES} ${VTK_FOR_MITK_LIBRARIES} ${ITK_LIBRARIES} ) set(MITK_LIBRARIES ${MITK_CORE_LIBRARIES} ${LIBRARIES_FOR_MITK_CORE} pic2vtk ipSegmentation ann ) # variables used in CMake macros which are called from external projects set(MITK_VTK_LIBRARY_DIRS ${VTK_LIBRARY_DIRS}) set(MITK_ITK_LIBRARY_DIRS ${ITK_LIBRARY_DIRS}) # variables containing link directories set(MITK_LIBRARY_DIRS ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) set(MITK_LINK_DIRECTORIES ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${ITK_LIBRARY_DIRS} ${VTK_LIBRARY_DIRS} ${GDCM_LIBRARY_DIRS}) # Qt support if(MITK_USE_QT) find_package(Qt4 REQUIRED) set(QMITK_INCLUDE_DIRS ${MITK_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/Modules/Qmitk ${PROJECT_BINARY_DIR}/Modules/Qmitk ) set(QMITK_LIBRARIES Qmitk ${MITK_LIBRARIES}) set(QMITK_LINK_DIRECTORIES ${MITK_LINK_DIRECTORIES}) endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # create a list of types for template instantiations of itk image access functions function(_create_type_seq TYPES seq_var seqdim_var) set(_seq ) set(_seq_dim ) string(REPLACE "," ";" _pixeltypes "${TYPES}") foreach(_pixeltype ${_pixeltypes}) set(_seq "${_seq}(${_pixeltype})") set(_seq_dim "${_seq_dim}((${_pixeltype},dim))") endforeach() set(${seq_var} "${_seq}" PARENT_SCOPE) set(${seqdim_var} "${_seq_dim}" PARENT_SCOPE) endfunction() set(MITK_ACCESSBYITK_PIXEL_TYPES ) set(MITK_ACCESSBYITK_PIXEL_TYPES_SEQ ) set(MITK_ACCESSBYITK_TYPES_DIMN_SEQ ) # concatenate only the simple pixel types to the MITK_ACCESSBYITK_PIXEL_TYPE_SEQ list # see Bug 12682 for detailed information foreach(_type INTEGRAL FLOATING) set(_typelist "${MITK_ACCESSBYITK_${_type}_PIXEL_TYPES}") if(_typelist) if(MITK_ACCESSBYITK_PIXEL_TYPES) set(MITK_ACCESSBYITK_PIXEL_TYPES "${MITK_ACCESSBYITK_PIXEL_TYPES},${_typelist}") else() set(MITK_ACCESSBYITK_PIXEL_TYPES "${_typelist}") endif() endif() _create_type_seq("${_typelist}" MITK_ACCESSBYITK_${_type}_PIXEL_TYPES_SEQ MITK_ACCESSBYITK_${_type}_TYPES_DIMN_SEQ) set(MITK_ACCESSBYITK_PIXEL_TYPES_SEQ "${MITK_ACCESSBYITK_PIXEL_TYPES_SEQ}${MITK_ACCESSBYITK_${_type}_PIXEL_TYPES_SEQ}") set(MITK_ACCESSBYITK_TYPES_DIMN_SEQ "${MITK_ACCESSBYITK_TYPES_DIMN_SEQ}${MITK_ACCESSBYITK_${_type}_TYPES_DIMN_SEQ}") endforeach() # separate processing of the COMPOSITE list to avoid its concatenation to to global list _create_type_seq(${MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES} MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES_SEQ MITK_ACCESSBYITK_COMPOSITE_TYPES_DIMN_SEQ) set(MITK_ACCESSBYITK_DIMENSIONS_SEQ ) string(REPLACE "," ";" _dimensions "${MITK_ACCESSBYITK_DIMENSIONS}") foreach(_dimension ${_dimensions}) set(MITK_ACCESSBYITK_DIMENSIONS_SEQ "${MITK_ACCESSBYITK_DIMENSIONS_SEQ}(${_dimension})") endforeach() diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 1fcc8ff026..ba86519fb5 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,35 +1,35 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag 062612b5) + set(revision_tag 452cf3a4) ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${ep_source_dir}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeExternals/MITKData.cmake.BACKUP.9452.cmake b/CMakeExternals/MITKData.cmake.BACKUP.9452.cmake deleted file mode 100644 index c2dd0c371b..0000000000 --- a/CMakeExternals/MITKData.cmake.BACKUP.9452.cmake +++ /dev/null @@ -1,43 +0,0 @@ -#----------------------------------------------------------------------------- -# MITK Data -#----------------------------------------------------------------------------- - -# Sanity checks -if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) - message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") -endif() - -set(proj MITK-Data) -set(proj_DEPENDENCIES) -set(MITK-Data_DEPENDS ${proj}) - -if(BUILD_TESTING) - -<<<<<<< HEAD - set(revision_tag 16d96097) -======= - set(revision_tag 66dc8282) ->>>>>>> bug-14224-DefaultCalibrationFiles - - #if(${proj}_REVISION_TAG) - # set(revision_tag ${${proj}_REVISION_TAG}) - #endif() - - ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - DEPENDS ${proj_DEPENDENCIES} - ) - - set(MITK_DATA_DIR ${ep_source_dir}/${proj}) - -else() - - mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") - -endif(BUILD_TESTING) - - diff --git a/CMakeExternals/MITKData.cmake.BASE.9452.cmake b/CMakeExternals/MITKData.cmake.BASE.9452.cmake deleted file mode 100644 index a01699470f..0000000000 --- a/CMakeExternals/MITKData.cmake.BASE.9452.cmake +++ /dev/null @@ -1,39 +0,0 @@ -#----------------------------------------------------------------------------- -# MITK Data -#----------------------------------------------------------------------------- - -# Sanity checks -if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) - message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") -endif() - -set(proj MITK-Data) -set(proj_DEPENDENCIES) -set(MITK-Data_DEPENDS ${proj}) - -if(BUILD_TESTING) - - set(revision_tag 55445f45) - - #if(${proj}_REVISION_TAG) - # set(revision_tag ${${proj}_REVISION_TAG}) - #endif() - - ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - DEPENDS ${proj_DEPENDENCIES} - ) - - set(MITK_DATA_DIR ${ep_source_dir}/${proj}) - -else() - - mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") - -endif(BUILD_TESTING) - - diff --git a/CMakeExternals/MITKData.cmake.LOCAL.9452.cmake b/CMakeExternals/MITKData.cmake.LOCAL.9452.cmake deleted file mode 100644 index 70ab82637a..0000000000 --- a/CMakeExternals/MITKData.cmake.LOCAL.9452.cmake +++ /dev/null @@ -1,39 +0,0 @@ -#----------------------------------------------------------------------------- -# MITK Data -#----------------------------------------------------------------------------- - -# Sanity checks -if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) - message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") -endif() - -set(proj MITK-Data) -set(proj_DEPENDENCIES) -set(MITK-Data_DEPENDS ${proj}) - -if(BUILD_TESTING) - - set(revision_tag 16d96097) - - #if(${proj}_REVISION_TAG) - # set(revision_tag ${${proj}_REVISION_TAG}) - #endif() - - ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - DEPENDS ${proj_DEPENDENCIES} - ) - - set(MITK_DATA_DIR ${ep_source_dir}/${proj}) - -else() - - mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") - -endif(BUILD_TESTING) - - diff --git a/CMakeExternals/MITKData.cmake.REMOTE.9452.cmake b/CMakeExternals/MITKData.cmake.REMOTE.9452.cmake deleted file mode 100644 index a1de5f6636..0000000000 --- a/CMakeExternals/MITKData.cmake.REMOTE.9452.cmake +++ /dev/null @@ -1,39 +0,0 @@ -#----------------------------------------------------------------------------- -# MITK Data -#----------------------------------------------------------------------------- - -# Sanity checks -if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) - message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") -endif() - -set(proj MITK-Data) -set(proj_DEPENDENCIES) -set(MITK-Data_DEPENDS ${proj}) - -if(BUILD_TESTING) - - set(revision_tag 66dc8282) - - #if(${proj}_REVISION_TAG) - # set(revision_tag ${${proj}_REVISION_TAG}) - #endif() - - ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/MITK-Data_${revision_tag}.tar.gz - UPDATE_COMMAND "" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - DEPENDS ${proj_DEPENDENCIES} - ) - - set(MITK_DATA_DIR ${ep_source_dir}/${proj}) - -else() - - mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") - -endif(BUILD_TESTING) - - diff --git a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake index c34601206a..c559177c5e 100644 --- a/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake +++ b/Core/Code/CppMicroServices/CMake/usFunctionEmbedResources.cmake @@ -1,145 +1,147 @@ #! Embed resources into a shared library or executable. #! #! This CMake function uses an external command line program to generate a source #! file containing data from external resources such as text files or images. The path #! to the generated source file is appended to the \c src_var variable. #! #! Each module can call this function (at most once) to embed resources and make them #! available at runtime through the Module class. Resources can also be embedded into #! executables, using the EXECUTABLE_NAME argument instead of LIBRARY_NAME. #! #! Example usage: #! \verbatim #! set(module_srcs ) #! usFunctionEmbedResources(module_srcs #! LIBRARY_NAME "mylib" #! ROOT_DIR resources #! FILES config.properties logo.png #! ) #! \endverbatim #! #! \param LIBRARY_NAME (required if EXECUTABLE_NAME is empty) The library name of the module #! which will include the generated source file, without extension. #! \param EXECUTABLE_NAME (required if LIBRARY_NAME is empty) The name of the executable #! which will include the generated source file. #! \param COMPRESSION_LEVEL (optional) The zip compression level. Defaults to the default zip #! level. Level 0 disables compression. #! \param COMPRESSION_THRESHOLD (optional) The compression threshold ranging from 0 to 100 for #! actually compressing the resource data. The default threshold is 30, meaning a size #! reduction of 30 percent or better results in the resource data being compressed. #! \param ROOT_DIR (optional) The root path for all resources listed after the FILES argument. #! If no or a relative path is given, it is considered relativ to the current CMake source directory. #! \param FILES (optional) A list of resources (paths to external files in the file system) relative #! to the ROOT_DIR argument or the current CMake source directory if ROOT_DIR is empty. #! #! The ROOT_DIR and FILES arguments may be repeated any number of times to merge files from #! different root directories into the embedded resource tree (hence the relative file paths #! after the FILES argument must be unique). #! function(usFunctionEmbedResources src_var) set(prefix US_RESOURCE) set(arg_names LIBRARY_NAME EXECUTABLE_NAME COMPRESSION_LEVEL COMPRESSION_THRESHOLD ROOT_DIR FILES) foreach(arg_name ${arg_names}) set(${prefix}_${arg_name}) endforeach(arg_name) set(cmd_line_args ) set(absolute_res_files ) set(current_arg_name DEFAULT_ARGS) set(current_arg_list) set(current_root_dir ${CMAKE_CURRENT_SOURCE_DIR}) foreach(arg ${ARGN}) list(FIND arg_names "${arg}" is_arg_name) if(is_arg_name GREATER -1) set(${prefix}_${current_arg_name} ${current_arg_list}) set(current_arg_name "${arg}") set(current_arg_list) else() set(current_arg_list ${current_arg_list} "${arg}") if(current_arg_name STREQUAL "ROOT_DIR") set(current_root_dir "${arg}") if(NOT IS_ABSOLUTE ${current_root_dir}) set(current_root_dir "${CMAKE_CURRENT_SOURCE_DIR}/${current_root_dir}") endif() if(NOT IS_DIRECTORY ${current_root_dir}) message(SEND_ERROR "The ROOT_DIR argument is not a directory: ${current_root_dir}") endif() get_filename_component(current_root_dir "${current_root_dir}" REALPATH) file(TO_NATIVE_PATH "${current_root_dir}" current_root_dir_native) list(APPEND cmd_line_args -d "${current_root_dir_native}") elseif(current_arg_name STREQUAL "FILES") set(res_file "${current_root_dir}/${arg}") file(TO_NATIVE_PATH "${res_file}" res_file_native) if(IS_DIRECTORY ${res_file}) message(SEND_ERROR "A resource cannot be a directory: ${res_file_native}") endif() if(NOT EXISTS ${res_file}) message(SEND_ERROR "Resource does not exists: ${res_file_native}") endif() list(APPEND absolute_res_files ${res_file}) file(TO_NATIVE_PATH "${arg}" res_filename_native) list(APPEND cmd_line_args "${res_filename_native}") endif() endif(is_arg_name GREATER -1) endforeach(arg ${ARGN}) set(${prefix}_${current_arg_name} ${current_arg_list}) if(NOT src_var) message(SEND_ERROR "Output variable name not specified.") endif() if(US_RESOURCE_EXECUTABLE_NAME AND US_RESOURCE_LIBRARY_NAME) message(SEND_ERROR "Only one of LIBRARY_NAME or EXECUTABLE_NAME can be specified.") endif() if(NOT US_RESOURCE_LIBRARY_NAME AND NOT US_RESOURCE_EXECUTABLE_NAME) message(SEND_ERROR "LIBRARY_NAME or EXECUTABLE_NAME argument not specified.") endif() if(NOT US_RESOURCE_FILES) message(WARNING "No FILES argument given. Skipping resource processing.") return() endif() list(GET cmd_line_args 0 first_arg) if(NOT first_arg STREQUAL "-d") set(cmd_line_args -d "${CMAKE_CURRENT_SOURCE_DIR}" ${cmd_line_args}) endif() if(US_RESOURCE_COMPRESSION_LEVEL) set(cmd_line_args -c ${US_RESOURCE_COMPRESSION_LEVEL} ${cmd_line_args}) endif() if(US_RESOURCE_COMPRESSION_THRESHOLD) set(cmd_line_args -t ${US_RESOURCE_COMPRESSION_THRESHOLD} ${cmd_line_args}) endif() if(US_RESOURCE_LIBRARY_NAME) set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_LIBRARY_NAME}_resources.cpp") set(us_lib_name ${US_RESOURCE_LIBRARY_NAME}) else() set(us_cpp_resource_file "${CMAKE_CURRENT_BINARY_DIR}/${US_RESOURCE_EXECUTABLE_NAME}_resources.cpp") set(us_lib_name "\"\"") endif() set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE}) if(TARGET ${CppMicroServices_RCC_EXECUTABLE_NAME}) set(resource_compiler ${CppMicroServices_RCC_EXECUTABLE_NAME}) + elseif(NOT resource_compiler) + message(FATAL_ERROR "The CppMicroServices resource compiler was not found. Check the CppMicroServices_RCC_EXECUTABLE CMake variable.") endif() add_custom_command( OUTPUT ${us_cpp_resource_file} COMMAND ${resource_compiler} "${us_lib_name}" ${us_cpp_resource_file} ${cmd_line_args} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${absolute_res_files} ${resource_compiler} COMMENT "Generating embedded resource file ${us_cpp_resource_name}" ) set(${src_var} "${${src_var}};${us_cpp_resource_file}" PARENT_SCOPE) endfunction() diff --git a/Core/Code/CppMicroServices/CMakeLists.txt b/Core/Code/CppMicroServices/CMakeLists.txt index 534a6a3b65..bed7726a9c 100644 --- a/Core/Code/CppMicroServices/CMakeLists.txt +++ b/Core/Code/CppMicroServices/CMakeLists.txt @@ -1,359 +1,357 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 0) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(MacroParseArguments) include(CheckCXXSourceCompiles) include(usFunctionCheckCompilerFlags) include(usFunctionEmbedResources) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) set(CppMicroServices_EXPORTS 1) endif() endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_SERVICE_FACTORY_SUPPORT ON BOOL "Enable Service Factory support" ADVANCED) us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_ENABLE_RESOURCE_COMPRESSION ON BOOL "Enable resource compression" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") if(MSVC10 OR MSVC11) # Visual Studio 2010 and newer have support for C++11 enabled by default set(US_USE_C++11 1) else() us_cache_var(US_USE_C++11 OFF BOOL "Enable the use of C++11 features" ADVANCED) endif() us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ micro services entities") us_cache_var(US_HEADER_PREFIX "" STRING "The file name prefix for the public C++ micro services header files") us_cache_var(US_BASECLASS_NAME "" STRING "The fully-qualified name of the base class") if(US_ENABLE_SERVICE_FACTORY_SUPPORT) us_cache_var(US_BASECLASS_PACKAGE "" STRING "The name of the package providing the base class definition" ADVANCED) set(bc_inc_d_doc "A list of include directories containing the header files for the base class") us_cache_var(US_BASECLASS_INCLUDE_DIRS "" STRING "${bc_inc_d_doc}" ADVANCED) set(bc_lib_d_doc "A list of library directories for the base class") us_cache_var(US_BASECLASS_LIBRARY_DIRS "" STRING "${bc_lib_d_doc}" ADVANCED) set(bc_lib_doc "A list of libraries needed for the base class") us_cache_var(US_BASECLASS_LIBRARIES "" STRING "${bc_lib_doc}" ADVANCED) us_cache_var(US_BASECLASS_HEADER "" STRING "The name of the header file containing the base class declaration" ADVANCED) endif() set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) # Sanity checks if(US_ENABLE_SERVICE_FACTORY_SUPPORT OR US_BUILD_TESTING) if(US_BASECLASS_PACKAGE) find_package(${US_BASECLASS_PACKAGE} REQUIRED) # Try to get the include dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix} AND NOT US_BASECLASS_INCLUDE_DIRS) us_cache_var(US_BASECLASS_INCLUDE_DIRS "${${US_BASECLASS_PACKAGE}_INCLUDE_${_suffix}}" STRING "${bc_inc_d_doc}" FORCE) break() endif() endforeach() # Try to get the library dirs foreach(_suffix DIRECTORIES DIRS DIRECTORY DIR) if(${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix} AND NOT US_BASECLASS_LIBRARY_DIRS) us_cache_var(US_BASECLASS_LIBRARY_DIRS "${${US_BASECLASS_PACKAGE}_LIBRARY_${_suffix}}" STRING "${bc_lib_d_doc}" FORCE) break() endif() endforeach() # Try to get the libraries foreach(_suffix LIBRARIES LIBS LIBRARY LIB) if(${US_BASECLASS_PACKAGE}_${_suffix} AND NOT US_BASECLASS_LIBRARIES) us_cache_var(US_BASECLASS_LIBRARIES "${${US_BASECLASS_PACKAGE}_${_suffix}}" STRING "${bc_lib_doc}" FORCE) break() endif() endforeach() if(NOT US_BASECLASS_NAME) message(FATAL_ERROR "US_BASECLASS_NAME not set") elseif(NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BASECLASS_HEADER not set") endif() endif() if(US_ENABLE_SERVICE_FACTORY_SUPPORT AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_ENABLE_SERVICE_FACTORY_SUPPORT requires a US_BASECLASS_HEADER value") endif() endif() set(_us_baseclass_default 0) if(NOT US_BASECLASS_NAME) message(WARNING "Using build in base class \"::${US_NAMESPACE}::Base\"") set(_us_baseclass_default 1) set(US_BASECLASS_NAME "${US_NAMESPACE}::Base") set(US_BASECLASS_HEADER "usBase.h") endif() if(US_BUILD_TESTING AND US_BASECLASS_NAME AND NOT US_BASECLASS_HEADER) message(FATAL_ERROR "US_BUILD_TESTING requires a US_BASECLASS_HEADER value") endif() set(US_BASECLASS_INCLUDE "#include <${US_BASECLASS_HEADER}>") string(REPLACE "::" ";" _bc_token "${US_BASECLASS_NAME}") list(GET _bc_token -1 _bc_name) list(REMOVE_AT _bc_token -1) set(US_BASECLASS_FORWARD_DECLARATION "") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}namespace ${_namespace_tok} { ") endif() endforeach() set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}class ${_bc_name}; ") foreach(_namespace_tok ${_bc_token}) if(_namespace_tok) set(US_BASECLASS_FORWARD_DECLARATION "${US_BASECLASS_FORWARD_DECLARATION}}") endif() endforeach() #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- set(US_C_FLAGS "${COVERAGE_C_FLAGS} ${ADDITIONAL_C_FLAGS}") set(US_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${ADDITIONAL_CXX_FLAGS}") # This is used as a preprocessor define set(US_USE_CXX11 ${US_USE_C++11}) # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option -D_FORTIFY_SOURCE=2) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() if(US_USE_C++11) usFunctionCheckCompilerFlags("-std=c++0x" US_CXX_FLAGS) endif() endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() if(MINGW) # suppress warnings about auto imported symbols set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") # we need to define a Windows version set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") else() # Enable visibility support if(NOT ${GCC_VERSION} VERSION_LESS "4.5") usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" US_CXX_FLAGS) endif() endif() elseif(MSVC) set(US_CXX_FLAGS "/MP /wd4996 ${US_CXX_FLAGS}") endif() if(NOT US_IS_EMBEDDED) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") endif() #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(NOT MSVC) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFile) CHECK_INCLUDE_FILE(stdint.h HAVE_STDINT) #----------------------------------------------------------------------------- # US include dirs and libraries #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ) set(US_INTERNAL_INCLUDE_DIRS ${PROJECT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src/util ${CMAKE_CURRENT_SOURCE_DIR}/src/service ${CMAKE_CURRENT_SOURCE_DIR}/src/module ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_INTERNAL_INCLUDE_DIRS ${US_BASECLASS_INCLUDE_DIRS}) endif() # link libraries for third party libs if(US_IS_EMBEDDED) set(US_LINK_LIBRARIES ${US_EMBEDDING_LIBRARY}) else() set(US_LINK_LIBRARIES ${PROJECT_NAME}) endif() # link libraries for the CppMicroServices lib set(_link_libraries ) if(UNIX) list(APPEND _link_libraries dl) endif() list(APPEND US_LINK_LIBRARIES ${_link_libraries}) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_LIBRARIES ${US_BASECLASS_LIBRARIES}) endif() set(US_LINK_DIRS ) if(US_ENABLE_SERVICE_FACTORY_SUPPORT) list(APPEND US_LINK_DIRS ${US_BASECLASS_LIBRARY_DIRS}) endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(us_config_h_file "${PROJECT_BINARY_DIR}/include/usConfig.h") configure_file(usConfig.h.in ${us_config_h_file}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler) set(CppMicroServices_RCC_EXECUTABLE_NAME ${US_RCC_EXECUTABLE_NAME}) -set(US_RCC_EXECUTABLE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${US_RCC_EXECUTABLE_NAME}") -set(CppMicroServices_RCC_EXECUTABLE ${US_RCC_EXECUTABLE}) add_subdirectory(tools) add_subdirectory(src) #----------------------------------------------------------------------------- # US testing #----------------------------------------------------------------------------- if(US_BUILD_TESTING) enable_testing() add_subdirectory(test) endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(documentation) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- configure_file(${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY) diff --git a/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake.in b/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake.in index 027a0a7555..293031cb43 100644 --- a/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake.in +++ b/Core/Code/CppMicroServices/CppMicroServicesConfig.cmake.in @@ -1,16 +1,19 @@ set(@PROJECT_NAME@_INCLUDE_DIRS @US_INCLUDE_DIRS@) set(@PROJECT_NAME@_INTERNAL_INCLUDE_DIRS @US_INTERNAL_INCLUDE_DIRS@) set(@PROJECT_NAME@_LIBRARIES @US_LINK_LIBRARIES@) set(@PROJECT_NAME@_LIBRARY_DIRS @CMAKE_LIBRARY_OUTPUT_DIRECTORY@) set(@PROJECT_NAME@_SOURCES @US_SOURCES@) set(@PROJECT_NAME@_PUBLIC_HEADERS @US_PUBLIC_HEADERS@) set(@PROJECT_NAME@_PRIVATE_HEADERS @US_PRIVATE_HEADERS@) set(@PROJECT_NAME@_SOURCE_DIR @CMAKE_CURRENT_SOURCE_DIR@) -set(CppMicroServices_RCC_EXECUTABLE @US_RCC_EXECUTABLE@) -set(CppMicroServices_RCC_EXECUTABLE_NAME @US_RCC_EXECUTABLE_NAME@) +set(CppMicroServices_RCC_EXECUTABLE_NAME @CppMicroServices_RCC_EXECUTABLE_NAME@) + +find_program(CppMicroServices_RCC_EXECUTABLE ${CppMicroServices_RCC_EXECUTABLE_NAME} + PATHS "@CMAKE_RUNTIME_OUTPUT_DIRECTORY@" + PATH_SUFFIXES Release Debug RelWithDebInfo MinSizeRel) include(@CMAKE_CURRENT_SOURCE_DIR@/CMake/usFunctionGenerateModuleInit.cmake) include(@CMAKE_CURRENT_SOURCE_DIR@/CMake/usFunctionEmbedResources.cmake) diff --git a/Core/Code/Interactions/mitkDisplayInteractor.h b/Core/Code/Interactions/mitkDisplayInteractor.h index 4658a9127e..2e3dfbf169 100644 --- a/Core/Code/Interactions/mitkDisplayInteractor.h +++ b/Core/Code/Interactions/mitkDisplayInteractor.h @@ -1,163 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDisplayInteractor_h #define mitkDisplayInteractor_h #include #include "mitkInteractionEventObserver.h" namespace mitk { /** *\class DisplayInteractor *@brief Observer that manages the interaction with the display. * * This includes the interaction of Zooming, Panning, Scrolling and adjusting the LevelWindow. * * @ingroup Interaction **/ /** * Inherits from mitk::InteractionEventObserver since it doesn't alter any data (only their representation), * and its actions cannot be associated with a DataNode. Also inherits from EventStateMachine */ class MITK_CORE_EXPORT DisplayInteractor: public EventStateMachine, public InteractionEventObserver { public: mitkClassMacro(DisplayInteractor, EventStateMachine) itkNewMacro(Self) /** - * By this function the Observer gets notifier about new events. + * By this function the Observer gets notified about new events. * Here it is adapted to pass the events to the state machine in order to use * its infrastructure. - * It also checks if event is to be accepted when i already has been processed by a DataInteractor. + * It also checks if event is to be accepted when it already has been processed by a DataInteractor. */ virtual void Notify(InteractionEvent* interactionEvent, bool isHandled); protected: DisplayInteractor(); virtual ~DisplayInteractor(); /** * Derived function. * Connects the action names used in the state machine pattern with functions implemented within * this InteractionEventObserver. This is only necessary here because the events are processed by the state machine. */ void ConnectActionsAndFunctions(); /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ virtual void ConfigurationChanged(); /** * Derived function. * Is executed when config object is set / changed. * Here it is used to read out the parameters set in the configuration file, * and set the member variables accordingly. */ virtual bool FilterEvents(InteractionEvent* interactionEvent, DataNode* dataNode); /** * \brief Initializes an interaction, saves the pointers start position for further reference. */ virtual bool Init(StateMachineAction*, InteractionEvent*); /** * \brief Performs panning of the data set in the render window. */ virtual bool Move(StateMachineAction*, InteractionEvent*); /** * \brief Performs zooming relative to mouse/pointer movement. * * Behavior is determined by \see m_ZoomDirection and \see m_ZoomFactor. * */ virtual bool Zoom(StateMachineAction*, InteractionEvent*); /** * \brief Performs scrolling relative to mouse/pointer movement. * * Behavior is determined by \see m_ScrollDirection and \see m_AutoRepeat. * */ virtual bool Scroll(StateMachineAction*, InteractionEvent*); /** * \brief Scrolls one layer up */ virtual bool ScrollOneDown(StateMachineAction*, InteractionEvent*); /** * \brief Scrolls one layer down */ virtual bool ScrollOneUp(StateMachineAction*, InteractionEvent*); /** * \brief Adjusts the level windows relative to mouse/pointer movement. */ virtual bool AdjustLevelWindow(StateMachineAction*, InteractionEvent*); private: /** * \brief Coordinate of the pointer at begin of an interaction */ mitk::Point2D m_StartDisplayCoordinate; /** * \brief Coordinate of the pointer at begin of an interaction translated to mm unit */ mitk::Point2D m_StartCoordinateInMM; /** * \brief Coordinate of the pointer in the last step within an interaction. */ mitk::Point2D m_LastDisplayCoordinate; /** * \brief Current coordinates of the pointer. */ mitk::Point2D m_CurrentDisplayCoordinate; /** * \brief Modifier that defines how many slices are scrolled per pixel that the mouse has moved * * This modifier defines how many slices the scene is scrolled per pixel that the mouse cursor has moved. * By default the modifier is 4. This means that when the user moves the cursor by 4 pixels in Y-direction * the scene is scrolled by one slice. If the user has moved the the cursor by 20 pixels, the scene is * scrolled by 5 slices. * * If the cursor has moved less than m_IndexToSliceModifier pixels the scene is scrolled by one slice. */ int m_IndexToSliceModifier; /** Defines behavior at end of data set. * If set to true it will restart at end of data set from the beginning. */ bool m_AutoRepeat; /** * Defines scroll behavior. * Default is up/down movement of pointer performs scrolling */ std::string m_ScrollDirection; /** * Defines scroll behavior. * Default is up/down movement of pointer performs zooming */ std::string m_ZoomDirection; /** * Determines if the Observer reacts to events that already have been processed by a DataInteractor. * The default value is false. */ bool m_AlwaysReact; /** * Factor to adjust zooming speed. */ float m_ZoomFactor; }; } #endif diff --git a/Core/Code/Rendering/mitkRenderingTestHelper.cpp b/Core/Code/Rendering/mitkRenderingTestHelper.cpp index cf646c1de3..a6e86079e3 100644 --- a/Core/Code/Rendering/mitkRenderingTestHelper.cpp +++ b/Core/Code/Rendering/mitkRenderingTestHelper.cpp @@ -1,191 +1,237 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //VTK #include #include #include #include //MITK #include #include #include #include #include #include #include // include gl to read out properties #include #include +//VTK Testing to compare the rendered image pixel-wise against a reference screen shot +#include "vtkTesting.h" + +mitkRenderingTestHelper::mitkRenderingTestHelper(int width, int height) + : m_AutomaticallyCloseRenderWindow(true) +{ + this->Initialize(width, height); +} + mitkRenderingTestHelper::mitkRenderingTestHelper(int width, int height, int argc, char* argv[]) + : m_AutomaticallyCloseRenderWindow(true) { - // Global interaction must(!) be initialized - mitk::GlobalInteraction::GetInstance()->Initialize("global"); + this->Initialize(width, height); + this->SetInputFileNames(argc, argv); +} - m_DataStorage = mitk::StandaloneDataStorage::New(); +void mitkRenderingTestHelper::Initialize(int width, int height) +{ + // Global interaction must(!) be initialized + mitk::GlobalInteraction::GetInstance()->Initialize("global"); + + m_RenderWindow = mitk::RenderWindow::New(); + m_DataStorage = mitk::StandaloneDataStorage::New(); - m_RenderWindow = mitk::RenderWindow::New(); - m_RenderWindow->GetRenderer()->SetDataStorage(m_DataStorage); - m_RenderWindow->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); - this->GetVtkRenderWindow()->SetSize( width, height ); - m_RenderWindow->GetRenderer()->Resize( width, height); + m_RenderWindow->GetRenderer()->SetDataStorage(m_DataStorage); + this->SetMapperIDToRender2D(); + this->GetVtkRenderWindow()->SetSize( width, height ); + m_RenderWindow->GetRenderer()->Resize( width, height); - //this->GetVtkRenderWindow()->DoubleBufferOff( ); - this->SetInputFileNames(argc, argv); - // prints the glinfo after creation of the vtkrenderwindow - this->PrintGLInfo(); + //Prints the glinfo after creation of the vtkrenderwindow, we always want to do this for debugging. + this->PrintGLInfo(); } mitkRenderingTestHelper::~mitkRenderingTestHelper() { } void mitkRenderingTestHelper::PrintGLInfo() { - GLint maxTextureSize; + GLint maxTextureSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);; - MITK_INFO << "OpenGL Render Context Information: \n" - << "- GL_VENDOR: "<< glGetString(GL_VENDOR) << "\n" - << "- GL_RENDERER: "<< glGetString(GL_RENDERER) << "\n" - << "- GL_VERSION: "<< glGetString(GL_VERSION) << "\n" - << "- GL_MAX_TEXTURE_SIZE: "<< maxTextureSize << "\n" - << "- GL_EXTENSIONS: "<< glGetString(GL_EXTENSIONS); + MITK_INFO << "OpenGL Render Context Information: \n" + << "- GL_VENDOR: "<< glGetString(GL_VENDOR) << "\n" + << "- GL_RENDERER: "<< glGetString(GL_RENDERER) << "\n" + << "- GL_VERSION: "<< glGetString(GL_VERSION) << "\n" + << "- GL_MAX_TEXTURE_SIZE: "<< maxTextureSize << "\n" + << "- GL_EXTENSIONS: "<< glGetString(GL_EXTENSIONS); } void mitkRenderingTestHelper::SetMapperID( mitk::BaseRenderer::StandardMapperSlot id) { - m_RenderWindow->GetRenderer()->SetMapperID(id); + m_RenderWindow->GetRenderer()->SetMapperID(id); +} + +void mitkRenderingTestHelper::SetMapperIDToRender3D() +{ + this->SetMapperID(mitk::BaseRenderer::Standard3D); +} + +void mitkRenderingTestHelper::SetMapperIDToRender2D() +{ + this->SetMapperID(mitk::BaseRenderer::Standard2D); } void mitkRenderingTestHelper::Render() { - //if the datastorage is initialized and at least 1 image is loaded render it - if(m_DataStorage.IsNotNull() || m_DataStorage->GetAll()->Size() >= 1 ) - { - //perform global reinit: - m_RenderWindow->GetRenderer()->PrepareRender(); - // mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetVtkRenderWindow()); + //if the datastorage is initialized and at least 1 image is loaded render it + if(m_DataStorage.IsNotNull() || m_DataStorage->GetAll()->Size() >= 1 ) + { + //Prepare the VTK camera before rendering. + m_RenderWindow->GetRenderer()->PrepareRender(); - //use this to actually show the iamge in a renderwindow - this->GetVtkRenderWindow()->Render(); -// this->GetVtkRenderWindow()->GetInteractor()->Start(); - } - else + this->GetVtkRenderWindow()->Render(); + if(m_AutomaticallyCloseRenderWindow == false) { - MITK_ERROR << "No images loaded in data storage!"; + //Use interaction to stop the test + this->GetVtkRenderWindow()->GetInteractor()->Start(); } + } + else + { + MITK_ERROR << "No images loaded in data storage!"; + } } -void mitkRenderingTestHelper::PrepareRender() -{ - //perform global reinit: - m_RenderWindow->GetRenderer()->PrepareRender(); -} - mitk::DataStorage::Pointer mitkRenderingTestHelper::GetDataStorage() { - return m_DataStorage; + return m_DataStorage; } void mitkRenderingTestHelper::SetInputFileNames(int argc, char* argv[]) { - // parse parameters - for (int i = 1; i < argc; ++i) + //i is set 1, because 0 is the testname as string + //parse parameters + for (int i = 1; i < argc; ++i) + { + //add everything to a list but -T and -V + std::string tmp = argv[i]; + if((tmp.compare("-T")) && (tmp.compare("-V"))) { - //add everything to a list but -T and -V - std::string tmp = argv[i]; - if((tmp.compare("-T")) && (tmp.compare("-V"))) - { - this->AddToStorage(tmp); - } - else - { - break; - } + this->AddToStorage(tmp); } + else + { + break; + } + } } void mitkRenderingTestHelper::SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection) { - mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController()->SetDefaultViewDirection(viewDirection); - mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()) ); + mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController()->SetDefaultViewDirection(viewDirection); + mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()) ); } void mitkRenderingTestHelper::ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation) { - mitk::SliceNavigationController::Pointer sliceNavigationController = - mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController(); - sliceNavigationController->ReorientSlices(origin, rotation); + mitk::SliceNavigationController::Pointer sliceNavigationController = + mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController(); + sliceNavigationController->ReorientSlices(origin, rotation); } vtkRenderer* mitkRenderingTestHelper::GetVtkRenderer() { - return m_RenderWindow->GetRenderer()->GetVtkRenderer(); + return m_RenderWindow->GetRenderer()->GetVtkRenderer(); } void mitkRenderingTestHelper::SetImageProperty(const char *propertyKey, mitk::BaseProperty* property ) { - this->m_DataStorage->GetNode(mitk::NodePredicateDataType::New("Image"))->SetProperty(propertyKey, property); + this->m_DataStorage->GetNode(mitk::NodePredicateDataType::New("Image"))->SetProperty(propertyKey, property); } vtkRenderWindow* mitkRenderingTestHelper::GetVtkRenderWindow() { - return m_RenderWindow->GetVtkRenderWindow(); + return m_RenderWindow->GetVtkRenderWindow(); +} + +bool mitkRenderingTestHelper::CompareRenderWindowAgainstReference(int argc, char* argv[], double threshold) +{ + this->Render(); + + //retVal meanings: (see VTK/Rendering/vtkTesting.h) + //0 = test failed + //1 = test passed + //2 = test not run + //3 = something with vtkInteraction + if(vtkTesting::Test(argc, argv, this->GetVtkRenderWindow(), threshold) == 1) + return true; + else + return false; } //method to save a screenshot of the renderwindow (e.g. create a reference screenshot) void mitkRenderingTestHelper::SaveAsPNG(std::string fileName) { - vtkSmartPointer renderer = this->GetVtkRenderer(); - bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); - renderer->GetRenderWindow()->DoubleBufferOff(); + vtkSmartPointer renderer = this->GetVtkRenderer(); + bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); + renderer->GetRenderWindow()->DoubleBufferOff(); + + vtkSmartPointer magnifier = vtkSmartPointer::New(); + magnifier->SetInput(renderer); + magnifier->SetMagnification(1); - vtkSmartPointer magnifier = vtkSmartPointer::New(); - magnifier->SetInput(renderer); - magnifier->SetMagnification(1); + vtkSmartPointer fileWriter = vtkSmartPointer::New(); + fileWriter->SetInput(magnifier->GetOutput()); + fileWriter->SetFileName(fileName.c_str()); - vtkSmartPointer fileWriter = vtkSmartPointer::New(); - fileWriter->SetInput(magnifier->GetOutput()); - fileWriter->SetFileName(fileName.c_str()); + fileWriter->Write(); + renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); +} - fileWriter->Write(); - renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); +void mitkRenderingTestHelper::SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow) +{ + m_AutomaticallyCloseRenderWindow = automaticallyCloseRenderWindow; +} + +void mitkRenderingTestHelper::SaveReferenceScreenShot(std::string fileName) +{ + this->SaveAsPNG(fileName); } void mitkRenderingTestHelper::AddToStorage(const std::string &filename) { - try - { - mitk::DataNode::Pointer node = mitk::IOUtil::LoadDataNode(filename); - this->AddNodeToStorage(node); - } - catch ( itk::ExceptionObject & e ) - { - MITK_ERROR << "Failed loading test data '" << filename << "': " << e.what(); - } + try + { + mitk::DataNode::Pointer node = mitk::IOUtil::LoadDataNode(filename); + this->AddNodeToStorage(node); + } + catch ( itk::ExceptionObject & e ) + { + MITK_ERROR << "Failed loading test data '" << filename << "': " << e.what(); + } } void mitkRenderingTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { - this->m_DataStorage->Add(node); - mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()) ); + this->m_DataStorage->Add(node); + mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()) ); } diff --git a/Core/Code/Rendering/mitkRenderingTestHelper.h b/Core/Code/Rendering/mitkRenderingTestHelper.h index 4b0ae508e1..f01bde6241 100644 --- a/Core/Code/Rendering/mitkRenderingTestHelper.h +++ b/Core/Code/Rendering/mitkRenderingTestHelper.h @@ -1,114 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRenderingTestHelper_h #define mitkRenderingTestHelper_h #include #include #include #include #include class vtkRenderWindow; class vtkRenderer; class MITK_CORE_EXPORT mitkRenderingTestHelper { public: - /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel). - @param argc Number of parameters. (here: Images) "Usage: [filename1 filenam2 -V referenceScreenshot (optional -T /directory/to/save/differenceImage)] - @param argv Given parameters. + /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel). + @param argc Number of parameters. (here: Images) "Usage: [filename1 filenam2 -V referenceScreenshot + (optional -T /directory/to/save/differenceImage)] + @param argv Given parameters. If no data is inserted via commandline, you can add data + later via AddNodeToDataStorage(). **/ - mitkRenderingTestHelper(int width, int height, int argc, char *argv[]); + mitkRenderingTestHelper(int width, int height, int argc, char *argv[]); + + /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel).*/ + mitkRenderingTestHelper(int width, int height); - ~mitkRenderingTestHelper(); + /** Default destructor */ + ~mitkRenderingTestHelper(); - /** @brief Getter for the vtkRenderer. + /** @brief Getter for the vtkRenderer. **/ - vtkRenderer* GetVtkRenderer(); + vtkRenderer* GetVtkRenderer(); - /** @brief Getter for the vtkRenderWindow which should be used to call vtkRegressionTestImage. + /** @brief Getter for the vtkRenderWindow which should be used to call vtkRegressionTestImage. **/ - vtkRenderWindow* GetVtkRenderWindow(); + vtkRenderWindow* GetVtkRenderWindow(); - /** @brief Method can be used to save a screenshot (e.g. reference screenshot as a .png file. + /** @brief Method can be used to save a screenshot (e.g. reference screenshot as a .png file. @param fileName The filename of the new screenshot (including path). **/ - void SaveAsPNG(std::string fileName); - - /** @brief This method set the property of the member datastorage - @param property Set a property for each image in the datastorage m_DataStorage. + void SaveAsPNG(std::string fileName); + + /** + * @brief SetStopRenderWindow Convenience method to make the renderwindow hold after rendering. Usefull for debugging. + * @param flag Flag indicating whether the renderwindow should automatically close (false, default) or stay open (true). Usefull for debugging. + */ + void SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow); + + /** @brief This method set the property of the member datastorage + @param property Set a property for each image in the datastorage m_DataStorage. If you want + to set the property for a single data node, use GetDataStorage() and set the property + yourself for the destinct node. **/ - void SetImageProperty(const char *propertyKey, mitk::BaseProperty *property); + void SetImageProperty(const char *propertyKey, mitk::BaseProperty *property); - /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, axial) + /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, axial) **/ - void SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection); + void SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection); - /** @brief Reorient the slice (e.g. rotation and translation like the swivel mode). + /** @brief Reorient the slice (e.g. rotation and translation like the swivel mode). **/ - void ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation); + void ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation); - /** @brief Render everything into an mitkRenderWindow. Call SetViewDirection() and SetProperty() before this method. + /** @brief Render everything into an mitkRenderWindow. Call SetViewDirection() and SetProperty() before this method. **/ - void Render(); - /** @brief Calls PrepareRender function of mitkRenderWindow - **/ - void PrepareRender(); + void Render(); - /** @brief Returns the datastorage, in order to modify the data inside a rendering test. + /** @brief Returns the datastorage, in order to modify the data inside a rendering test. **/ - mitk::DataStorage::Pointer GetDataStorage(); + mitk::DataStorage::Pointer GetDataStorage(); - /** + /** * @brief SetMapperID Change between Standard2D and 3D mappers. * @param id Enum mitk::BaseRenderer::StandardMapperSlot which defines the mapper. */ - void SetMapperID(mitk::BaseRenderer::StandardMapperSlot id); + void SetMapperID(mitk::BaseRenderer::StandardMapperSlot id); - /** + /** * @brief AddNodeToStorage Add a node to the datastorage and perform a reinit which is necessary for rendering. * @param node The data you want to add. */ - void AddNodeToStorage(mitk::DataNode::Pointer node); + void AddNodeToStorage(mitk::DataNode::Pointer node); + + /** + * @brief SetMapperIDToRender3D Convenience method to render in a 3D renderwindow. + * @warning Does not add helper objects like the image planes to render images in 3D. + */ + void SetMapperIDToRender3D(); + + /** + * @brief SetMapperIDToRender2D Convenience method to render in a 2D renderwindow. + */ + void SetMapperIDToRender2D(); + + /** + * @brief SaveReferenceScreenShot Convenience method to save a reference screen shot. + * @param fileName Path/to/save/the/png/file. + */ + void SaveReferenceScreenShot(std::string fileName); + + /** + * @brief CompareRenderWindowAgainstReference Convenience method to compare the image rendered in the internal renderwindow against a reference screen shot. + * + Usage of vtkTesting::Test: + vtkTesting::Test( argc, argv, vtkRenderWindow, threshold ) + Set a vtkRenderWindow containing the desired scene. This is automatically rendered. + vtkTesting::Test() automatically searches in argc and argv[] + for a path a valid image with -V. If the test failed with the + first image (foo.png) it checks if there are images of the form + foo_N.png (where N=1,2,3...) and compare against them. This allows for multiple + valid images. + * @param argc Number of arguments. + * @param argv Arguments must(!) contain the term "-V Path/To/Valid/Image.png" + * @param threshold Allowed difference between two images. Default = 10.0 and was taken from VTK. + * @return True if the images are equal regarding the threshold. False in all other cases. + */ + bool CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold = 10.0); + protected: + /** + * @brief Initialize Internal method to initialize the renderwindow and set the datastorage. + * @param width Height of renderwindow. + * @param height Width of renderwindow. + */ + void Initialize(int width, int height); - /** @brief Prints the opengl information, e.g. version, vendor and extensions, + /** @brief Prints the opengl information, e.g. version, vendor and extensions, * This function can only be called after an opengl context is active. * It only prints the context after the vtkRenderwindow is fully initialized. **/ - void PrintGLInfo(); + void PrintGLInfo(); - /** @brief This method tries to load the given file into a member datastorage, in order to render it. + /** @brief This method tries to load the given file into a member datastorage, in order to render it. @param fileName The filename of the file to be loaded (including path). **/ - void AddToStorage(const std::string& filename); + void AddToStorage(const std::string& filename); - /** @brief This method tries to parse the given argv for files (e.g. images) and load them into a member datastorage, in order to render it. + /** @brief This method tries to parse the given argv for files (e.g. images) and load them into a member datastorage, in order to render it. @param argc Number of parameters. @param argv Given parameters. **/ - void SetInputFileNames(int argc, char *argv[]); + void SetInputFileNames(int argc, char *argv[]); - mitk::RenderWindow::Pointer m_RenderWindow; //<< Contains the mitkRenderWindow into which the test renders the data - mitk::DataStorage::Pointer m_DataStorage; //<< Contains the mitkDataStorage which contains the data to be rendered + mitk::RenderWindow::Pointer m_RenderWindow; //<< Contains the mitkRenderWindow into which the test renders the data + mitk::DataStorage::Pointer m_DataStorage; //<< Contains the mitkDataStorage which contains the data to be rendered + bool m_AutomaticallyCloseRenderWindow; //<< Flag indicating whether the renderwindow should automatically close (true, default) or stay open (false). Usefull for debugging. }; #endif diff --git a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml index 7ce0de4ab3..0cd6f2be12 100644 --- a/Core/Code/Resources/Interactions/Legacy/StateMachine.xml +++ b/Core/Code/Resources/Interactions/Legacy/StateMachine.xml @@ -1,4061 +1,4101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/Code/Testing/CMakeLists.txt b/Core/Code/Testing/CMakeLists.txt index 6c46455f78..cdebc1245e 100644 --- a/Core/Code/Testing/CMakeLists.txt +++ b/Core/Code/Testing/CMakeLists.txt @@ -1,113 +1,124 @@ # The core tests need relaxed compiler flags... # TODO fix core tests to compile without these additional no-error flags if(MSVC_VERSION) # disable deprecated warnings (they would lead to errors) mitkFunctionCheckCompilerFlags2("/wd4996" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) else() mitkFunctionCheckCompilerFlags2("-Wno-error=deprecated" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) mitkFunctionCheckCompilerFlags2("-Wno-error=deprecated-declarations" CMAKE_C_FLAGS CMAKE_CXX_FLAGS) endif() MITK_CREATE_MODULE_TESTS(LABELS MITK-Core) # MITK_INSTALL_TARGETS(EXECUTABLES MitkTestDriver) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_CT mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-ct.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_MR mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-mr.dcm) mitkAddCustomModuleTest(mitkDICOMLocaleTest_spacingOk_SC mitkDICOMLocaleTest ${MITK_DATA_DIR}/spacing-ok-sc.dcm) mitkAddCustomModuleTest(mitkVolumeCalculatorTest_Png2D-bw mitkVolumeCalculatorTest ${MITK_DATA_DIR}/Png2D-bw.png ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkEventMapperTest_Test1And2 mitkEventMapperTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) #mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.pic.gz ${MITK_DATA_DIR}/BallBinary30x30x30.pic.gz) mitkAddCustomModuleTest(mitkNodeDependentPointSetInteractorTest mitkNodeDependentPointSetInteractorTest ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/BallBinary30x30x30.nrrd) mitkAddCustomModuleTest(mitkDataStorageTest_US4DCyl mitkDataStorageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkStateMachineFactoryTest_TestStateMachine1_2 mitkStateMachineFactoryTest ${MITK_DATA_DIR}/TestStateMachine1.xml ${MITK_DATA_DIR}/TestStateMachine2.xml) mitkAddCustomModuleTest(mitkDicomSeriesReaderTest_CTImage mitkDicomSeriesReaderTest ${MITK_DATA_DIR}/TinyCTAbdomen) mitkAddCustomModuleTest(mitkPointSetReaderTest mitkPointSetReaderTest ${MITK_DATA_DIR}/PointSetReaderTestData.mps) mitkAddCustomModuleTest(mitkImageTest_4DImageData mitkImageTest ${MITK_DATA_DIR}/US4DCyl.nrrd) mitkAddCustomModuleTest(mitkImageTest_2D+tImageData mitkImageTest ${MITK_DATA_DIR}/Pic2DplusT.nrrd) mitkAddCustomModuleTest(mitkImageTest_3DImageData mitkImageTest ${MITK_DATA_DIR}/Pic3D.nrrd) mitkAddCustomModuleTest(mitkImageTest_brainImage mitkImageTest ${MITK_DATA_DIR}/brain.mhd) #mitkAddCustomModuleTest(mitkImageTest_color2DImage mitkImageTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) mitkAddCustomModuleTest(mitkIOUtilTest mitkIOUtilTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/pointSet.mps ${MITK_DATA_DIR}/binary.stl ) mitkAddCustomModuleTest(mitkLevelWindowManagerTest mitkLevelWindowManagerTest ${MITK_DATA_DIR}/Pic3D.nrrd ) if(WIN32 OR APPLE OR MITK_ENABLE_GUI_TESTING) ### since the rendering test's do not run in ubuntu, yet, we build them only for other systems or if the user explicitly sets the variable MITK_ENABLE_GUI_TESTING mitkAddCustomModuleTest(mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2DTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/rgbaImage640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3d640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2DColorTest #test for color property (=blue) Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dColorBlue640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2DLevelWindowTest #test for levelwindow property (=blood) #Pic3D sagittal slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dLevelWindowBlood640x480REF.png #corresponding reference #screenshot ) -#mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dOpacity640x480 mitkImageVtkMapper2DOpacityTest #test for opacity (=0.5) Pic3D coronal slice -# ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -# -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dOpacity640x480REF.png #corresponding reference screenshot -#) +mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dOpacity640x480 mitkImageVtkMapper2DOpacityTest #test for opacity (=0.5) Pic3D coronal slice + ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage + -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dOpacity640x480REF.png corresponding reference screenshot +) mitkAddCustomModuleTest(mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DSwivelTest #test for a randomly chosen Pic3D swivelled slice ${MITK_DATA_DIR}/Pic3D.nrrd #input image to load in data storage -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/pic3dSwivel640x480REF.png #corresponding reference screenshot ) +# Testing of the rendering of binary images +mitkAddCustomModuleTest(mitkImageVtkMapper2D_binaryTestImage640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice + ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage + -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImage640x480REF.png #corresponding reference screenshot +) +mitkAddCustomModuleTest(mitkImageVtkMapper2D_binaryTestImageWithRef640x480 mitkImageVtkMapper2DTest #test for standard Pic3D axial slice + ${MITK_DATA_DIR}/Pic3D.nrrd ${MITK_DATA_DIR}/RenderingTestData/binaryImage.nrrd #input image to load in data storage + -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/binaryImageWithRef640x480REF.png #corresponding reference screenshot +) +# End of binary image tests + mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTest_TextureProperty mitkSurfaceVtkMapper3DTest ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom.vtp ${MITK_DATA_DIR}/ToF-Data/Kinect_LiverPhantom_RGBImage.nrrd -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedLiver640x480REF.png #corresponding reference screenshot ) mitkAddCustomModuleTest(mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw mitkImageVtkMapper2DTransferFunctionTest ${MITK_DATA_DIR}/Png2D-bw.png -V ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/Png2D-bw-TransferFunctionRGBImage640x480REF.png #corresponding reference screenshot ) #mitkAddCustomModuleTest(mitkSurfaceVtkMapper3DTexturedSphereTest_Football mitkSurfaceVtkMapper3DTexturedSphereTest # ${MITK_DATA_DIR}/RenderingTestData/texture.jpg #input texture # -V # ${MITK_DATA_DIR}/RenderingTestData/ReferenceScreenshots/texturedSphere640x480REF.png corresponding reference screenshot #) -SET_PROPERTY(TEST mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw #mitkSurfaceVtkMapper3DTest_TextureProperty #mitkSurfaceVtkMapper3DTexturedSphereTest_Football #mitkImageVtkMapper2D_pic3dOpacity640x480 +SET_PROPERTY(TEST mitkImageVtkMapper2D_rgbaImage640x480 mitkImageVtkMapper2D_pic3d640x480 mitkImageVtkMapper2D_pic3dColorBlue640x480 mitkImageVtkMapper2D_pic3dLevelWindow640x480 mitkImageVtkMapper2D_pic3dSwivel640x480 mitkImageVtkMapper2DTransferFunctionTest_Png2D-bw mitkImageVtkMapper2D_pic3dOpacity640x480 #mitkSurfaceVtkMapper3DTest_TextureProperty #mitkSurfaceVtkMapper3DTexturedSphereTest_Football PROPERTY RUN_SERIAL TRUE) endif() add_test(mitkPointSetLocaleTest ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkPointSetLocaleTest ${MITK_DATA_DIR}/pointSet.mps) set_property(TEST mitkPointSetLocaleTest PROPERTY LABELS MITK-Core) add_test(mitkImageWriterTest_nrrdImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/NrrdWritingTestImage.jpg) add_test(mitkImageWriterTest_2DPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/Png2D-bw.png) add_test(mitkImageWriterTest_rgbPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbImage.png) add_test(mitkImageWriterTest_rgbaPNGImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TESTDRIVER} mitkImageWriterTest ${MITK_DATA_DIR}/RenderingTestData/rgbaImage.png) set_property(TEST mitkImageWriterTest_nrrdImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_2DPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbPNGImage PROPERTY LABELS MITK-Core) set_property(TEST mitkImageWriterTest_rgbaPNGImage PROPERTY LABELS MITK-Core) add_subdirectory(DICOMTesting) diff --git a/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp index 47cbb6e9e0..2ce87c0e70 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DColorTest.cpp @@ -1,74 +1,53 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DColorTest(int argc, char* argv[]) { - // load all arguments into a datastorage, take last argument as reference rendering - // setup a renderwindow of fixed size X*Y - // render the datastorage - // compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") - - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - //Set the opacity for all images - renderingHelper.SetImageProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 255.0f)); - //for now this test renders in sagittal view direction - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); - renderingHelper.Render(); - - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); - } - - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") + + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //Set the opacity for all images + renderingHelper.SetImageProperty("color", mitk::ColorProperty::New(0.0f, 0.0f, 255.0f)); + //for now this test renders in sagittal view direction + renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + + //#################### + //Use this to generate a reference screenshot or save the file. + //(Only in your local version of the test!) + if(false) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); + } + //#################### + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp index da113a3356..ee59981e32 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DLevelWindowTest.cpp @@ -1,81 +1,58 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include #include //VTK #include int mitkImageVtkMapper2DLevelWindowTest(int argc, char* argv[]) { - // load all arguments into a datastorage, take last argument as reference rendering - // setup a renderwindow of fixed size X*Y - // render the datastorage - // compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") - - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - //chose a level window: here we randomly chosen the blood preset. - mitk::LevelWindowPreset* levelWindowPreset = mitk::LevelWindowPreset::New(); - bool loadedPreset = levelWindowPreset->LoadPreset(); - MITK_TEST_CONDITION_REQUIRED(loadedPreset == true, "Testing if level window preset could be loaded"); - double level = levelWindowPreset->getLevel("Blood"); - double window = levelWindowPreset->getWindow("Blood"); - //apply level window to all images - renderingHelper.SetImageProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(level, window)) ); - //for now this test renders Sagittal - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); - renderingHelper.Render(); - - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); - } - - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") + + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //chose a level window: here we randomly chosen the blood preset. + mitk::LevelWindowPreset* levelWindowPreset = mitk::LevelWindowPreset::New(); + bool loadedPreset = levelWindowPreset->LoadPreset(); + MITK_TEST_CONDITION_REQUIRED(loadedPreset == true, "Testing if level window preset could be loaded"); + double level = levelWindowPreset->getLevel("Blood"); + double window = levelWindowPreset->getWindow("Blood"); + //apply level window to all images + renderingHelper.SetImageProperty("levelwindow", mitk::LevelWindowProperty::New(mitk::LevelWindow(level, window)) ); + //for now this test renders Sagittal + renderingHelper.SetViewDirection(mitk::SliceNavigationController::Sagittal); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp index 1cafc6de51..be59fe014a 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DOpacityTest.cpp @@ -1,74 +1,51 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DOpacityTest(int argc, char* argv[]) { - // load all arguments into a datastorage, take last argument as reference rendering - // setup a renderwindow of fixed size X*Y - // render the datastorage - // compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") - - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - //Set the opacity for all images - renderingHelper.SetImageProperty("opacity", mitk::FloatProperty::New(0.5f)); - //for now this test renders in coronal view direction - renderingHelper.SetViewDirection(mitk::SliceNavigationController::Frontal); - renderingHelper.Render(); - - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); - } - - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") + + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //Set the opacity for all images + renderingHelper.SetImageProperty("opacity", mitk::FloatProperty::New(0.5f)); + //for now this test renders in coronal view direction + renderingHelper.SetViewDirection(mitk::SliceNavigationController::Frontal); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp index 58b356a3f6..b17e39356b 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DSwivelTest.cpp @@ -1,89 +1,66 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include //VTK #include int mitkImageVtkMapper2DSwivelTest(int argc, char* argv[]) { - //load all arguments into a datastorage, take last argument as reference - //setup a renderwindow of fixed size X*Y - //render the datastorage - //compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DSwivelTest") - - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - //center point for rotation - mitk::Point3D centerPoint; - centerPoint.Fill(0.0f); - //vector for rotating the slice - mitk::Vector3D rotationVector; - rotationVector.SetElement(0, 0.2); - rotationVector.SetElement(1, 0.3); - rotationVector.SetElement(2, 0.5); - //sets a swivel direction for the image - - //new version of setting the center point: - mitk::Image::Pointer image = static_cast(renderingHelper.GetDataStorage()->GetNode(mitk::NodePredicateDataType::New("Image"))->GetData()); - - //get the center point of the image - centerPoint = image->GetGeometry()->GetCenter(); - - //rotate the image arround its own center - renderingHelper.ReorientSlices(centerPoint, rotationVector); - renderingHelper.Render(); - - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/media/hdd/thomasHdd/Pictures/RenderingTestData/pic3dSwivel640x480REF.png"); - } - - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + //load all arguments into a datastorage, take last argument as reference + //setup a renderwindow of fixed size X*Y + //render the datastorage + //compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DSwivelTest") + + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //center point for rotation + mitk::Point3D centerPoint; + centerPoint.Fill(0.0f); + //vector for rotating the slice + mitk::Vector3D rotationVector; + rotationVector.SetElement(0, 0.2); + rotationVector.SetElement(1, 0.3); + rotationVector.SetElement(2, 0.5); + //sets a swivel direction for the image + + //new version of setting the center point: + mitk::Image::Pointer image = static_cast(renderingHelper.GetDataStorage()->GetNode(mitk::NodePredicateDataType::New("Image"))->GetData()); + + //get the center point of the image + centerPoint = image->GetGeometry()->GetCenter(); + + //rotate the image arround its own center + renderingHelper.ReorientSlices(centerPoint, rotationVector); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/media/hdd/thomasHdd/Pictures/RenderingTestData/pic3dSwivel640x480REF.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp index 5d155c1d67..aacce7ef4a 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DTest.cpp @@ -1,70 +1,47 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include int mitkImageVtkMapper2DTest(int argc, char* argv[]) { - // load all arguments into a datastorage, take last argument as reference rendering - // setup a renderwindow of fixed size X*Y - // render the datastorage - // compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DTest") - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - renderingHelper.Render(); + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); + } - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); - } + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp b/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp index 6f5e720acb..dfa3f53280 100644 --- a/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp +++ b/Core/Code/Testing/mitkImageVtkMapper2DTransferFunctionTest.cpp @@ -1,89 +1,63 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" //VTK #include #include #include #include int mitkImageVtkMapper2DTransferFunctionTest(int argc, char* argv[]) { - // load all arguments into a datastorage, take last argument as reference rendering - // setup a renderwindow of fixed size X*Y - // render the datastorage - // compare rendering to reference image - MITK_TEST_BEGIN("mitkImageVtkMapper2DTransferFunctionTest") - - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); - - //define an arbitrary colortransferfunction - vtkSmartPointer colorTransferFunction = vtkSmartPointer::New(); - colorTransferFunction->SetColorSpaceToRGB(); - colorTransferFunction->AddRGBPoint(0.0, 1, 0, 0); //black = red - colorTransferFunction->AddRGBPoint(127.5, 0, 1, 0); //grey = green - colorTransferFunction->AddRGBPoint(255.0, 0, 0, 1); //white = blue - mitk::TransferFunction::Pointer transferFucntion = mitk::TransferFunction::New(); - transferFucntion->SetColorTransferFunction( colorTransferFunction ); - - //set the rendering mode to use the transfer function - renderingHelper.SetImageProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR)); - //set the property for the image - renderingHelper.SetImageProperty("Image Rendering.Transfer Function", mitk::TransferFunctionProperty::New(transferFucntion)); - - renderingHelper.Render(); - - //use this to generate a reference screenshot or save the file: - bool generateReferenceScreenshot = false; - if(generateReferenceScreenshot) - { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); - } - - renderingHelper.PrepareRender(); - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - //Default tolerance for rendering tests is 10 (set by VTK). - //For this case, small artifacts in Windows occur and boundaries of the fonts, - //thus we double the default tolerance threshold and set it to 20. - int retVal = vtkTesting::Test(argc, argv, renderingHelper.GetVtkRenderWindow(), 20 ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); - - MITK_TEST_END(); + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + MITK_TEST_BEGIN("mitkImageVtkMapper2DTransferFunctionTest") + + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + + //define an arbitrary colortransferfunction + vtkSmartPointer colorTransferFunction = vtkSmartPointer::New(); + colorTransferFunction->SetColorSpaceToRGB(); + colorTransferFunction->AddRGBPoint(0.0, 1, 0, 0); //black = red + colorTransferFunction->AddRGBPoint(127.5, 0, 1, 0); //grey = green + colorTransferFunction->AddRGBPoint(255.0, 0, 0, 1); //white = blue + mitk::TransferFunction::Pointer transferFucntion = mitk::TransferFunction::New(); + transferFucntion->SetColorTransferFunction( colorTransferFunction ); + + //set the rendering mode to use the transfer function + renderingHelper.SetImageProperty("Image Rendering.Mode", mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR)); + //set the property for the image + renderingHelper.SetImageProperty("Image Rendering.Transfer Function", mitk::TransferFunctionProperty::New(transferFucntion)); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv, 20.0) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkSurfaceVtkMapper3DTest.cpp b/Core/Code/Testing/mitkSurfaceVtkMapper3DTest.cpp index c94526cdd3..be479ee684 100644 --- a/Core/Code/Testing/mitkSurfaceVtkMapper3DTest.cpp +++ b/Core/Code/Testing/mitkSurfaceVtkMapper3DTest.cpp @@ -1,129 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include #include #include //VTK #include #include #include #include #include #include #include #include int mitkSurfaceVtkMapper3DTest(int argc, char* argv[]) { // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkSurfaceVtkMapper3DTest") - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); //3D rendering test, thus 3D mapper ID. renderingHelper.SetMapperID(mitk::BaseRenderer::Standard3D); vtkSmartPointer textureCoordinates = vtkSmartPointer::New(); textureCoordinates->SetNumberOfComponents(2); textureCoordinates->SetName("TextureCoordinates"); mitk::Image::Pointer textureImage = static_cast< mitk::Image* > ( renderingHelper.GetDataStorage()->GetNode( mitk::NodePredicateDataType::New("Image"))->GetData() ); //generate texture coordinates assuming that surface and texture can be mapped 1 to 1 unsigned int* dims = textureImage->GetDimensions(); for(unsigned int j = 0; j < dims[1]; ++j) { for(unsigned int i = 0; i < dims[0]; ++i) { int pixelID = i + j*dims[0]; float xNorm = (((float)i)/dims[0]); float yNorm = ((float)j)/dims[1]; textureCoordinates->InsertTuple2(pixelID, xNorm, yNorm); } } mitk::Surface::Pointer surfaceToPutTextureOn = static_cast< mitk::Surface* > ( renderingHelper.GetDataStorage()->GetNode( mitk::NodePredicateDataType::New("Surface"))->GetData() ); surfaceToPutTextureOn->GetVtkPolyData()->GetPointData()->SetTCoords(textureCoordinates); mitk::SmartPointerProperty::Pointer textureProperty = mitk::SmartPointerProperty::New(textureImage); renderingHelper.GetDataStorage()->GetNode(mitk::NodePredicateDataType::New("Surface"))->SetProperty("Surface.Texture", textureProperty); //remove the image from the data storage in order to not disturb the world geometry //(only the surface geometry should be used for rendering) renderingHelper.GetDataStorage()->Remove( renderingHelper.GetDataStorage()->GetNode( mitk::NodePredicateDataType::New("Image")) ); //Perform reinit, because we removed data. mitk::RenderingManager::GetInstance()->InitializeViews( renderingHelper.GetDataStorage()->ComputeBoundingGeometry3D(renderingHelper.GetDataStorage()->GetAll()) ); //Find a nice camera position to view the surface from the front. //This has to be done after calling renderingHelper.Render(), //because it would overwrite the camera position with global reinit. //It is not necessary, but else the surface is ugly rendered from the side. mitk::Point3D surfaceCenter= surfaceToPutTextureOn->GetGeometry()->GetCenter(); vtkCamera* camera3d = renderingHelper.GetVtkRenderer()->GetActiveCamera(); //1m distance to camera should be a nice default value for most cameras camera3d->SetPosition(0,0,-1000); camera3d->SetViewUp(0,-1,0); camera3d->SetFocalPoint(0,0,surfaceCenter[2]); camera3d->SetViewAngle(40); // camera3d->SetClippingRange(1, 10000); renderingHelper.GetVtkRenderer()->ResetCamera(); - - renderingHelper.Render(); //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); } - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); MITK_TEST_END(); } diff --git a/Core/Code/Testing/mitkSurfaceVtkMapper3DTexturedSphereTest.cpp b/Core/Code/Testing/mitkSurfaceVtkMapper3DTexturedSphereTest.cpp index 2fd221aadc..5161978eaa 100644 --- a/Core/Code/Testing/mitkSurfaceVtkMapper3DTexturedSphereTest.cpp +++ b/Core/Code/Testing/mitkSurfaceVtkMapper3DTexturedSphereTest.cpp @@ -1,114 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //MITK #include "mitkTestingMacros.h" #include "mitkRenderingTestHelper.h" #include #include #include //VTK #include #include #include #include #include #include #include /** * @brief mitkSurfaceVtkMapper3DTexturedSphereTest This test puts a texture onto a sphere. It is a nice example how to use VTK methods to generate texture coordinates for MITK surfaces. * @param argv Just any image serving as texture. */ int mitkSurfaceVtkMapper3DTexturedSphereTest(int argc, char* argv[]) { // load all arguments into a datastorage, take last argument as reference rendering // setup a renderwindow of fixed size X*Y // render the datastorage // compare rendering to reference image MITK_TEST_BEGIN("mitkSurfaceVtkMapper3DTexturedSphereTest") - // enough parameters? - if ( argc < 2 ) - { - MITK_TEST_OUTPUT( << "Usage: " << std::string(*argv) << " [file1 file2 ...] outputfile" ) - MITK_TEST_OUTPUT( << "Will render a central axial slice of all given files into outputfile" ) - exit( EXIT_SUCCESS ); - } - mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); //This is a test for a 3D surface, thus we need to set the mapper ID to 3D renderingHelper.SetMapperID(mitk::BaseRenderer::Standard3D); //######## Exmaple code begin ######## //Generate a sphere in order to map texture on it vtkSmartPointer sphere = vtkSmartPointer::New(); sphere->SetThetaResolution(12); sphere->SetPhiResolution(12); sphere->SetRadius(50.0); //just to make it huge sphere->SetCenter(50,0,0); //just to center the sphere in the screen //taken from VTK example: http://www.vtk.org/Wiki/VTK/Examples/Python/Visualization/SphereTexture vtkSmartPointer mapToSphere = vtkSmartPointer::New(); mapToSphere->SetInputConnection(sphere->GetOutputPort()); mapToSphere->PreventSeamOn(); //get the texture image from the helper's data storage mitk::Image::Pointer textureImage = static_cast< mitk::Image* > ( renderingHelper.GetDataStorage()->GetNode( mitk::NodePredicateDataType::New("Image"))->GetData() ); //Generate MITK surface mitk::Surface::Pointer surfaceToPutTextureOn = mitk::Surface::New(); surfaceToPutTextureOn->SetVtkPolyData(static_cast(mapToSphere->GetOutput())); //Generate a node mitk::DataNode::Pointer surfaceNode = mitk::DataNode::New(); surfaceNode->SetData( surfaceToPutTextureOn ); //Make a Property and add to the node mitk::SmartPointerProperty::Pointer textureProperty = mitk::SmartPointerProperty::New(textureImage); surfaceNode->SetProperty("Surface.Texture", textureProperty); //add to data storage renderingHelper.AddNodeToStorage(surfaceNode); //######## Exmaple code end ######## - renderingHelper.Render(); - //use this to generate a reference screenshot or save the file: bool generateReferenceScreenshot = false; if(generateReferenceScreenshot) { - renderingHelper.SaveAsPNG("/home/kilgus/Pictures/RenderingTestData/output.png"); + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/RenderingTestData/output.png"); } - //### Usage of vtkRegressionTestImage: - //vtkRegressionTestImage( vtkRenderWindow ) - //Set a vtkRenderWindow containing the desired scene. - //vtkRegressionTestImage automatically searches in argc and argv[] - //for a path a valid image with -V. If the test failed with the - //first image (foo.png) check if there are images of the form - //foo_N.png (where N=1,2,3...) and compare against them. - renderingHelper.PrepareRender(); - int retVal = vtkRegressionTestImage( renderingHelper.GetVtkRenderWindow() ); - - //retVal meanings: (see VTK/Rendering/vtkTesting.h) - //0 = test failed - //1 = test passed - //2 = test not run - //3 = something with vtkInteraction - MITK_TEST_CONDITION( retVal == 1, "VTK test result positive" ); + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv, 50.0) == true, "CompareRenderWindowAgainstReference test result positive?" ); MITK_TEST_END(); } diff --git a/Core/Documentation/Doxygen/Concepts/DataInteraction.dox b/Core/Documentation/Doxygen/Concepts/DataInteraction.dox index 6c74c6b905..f26fad6c3d 100644 --- a/Core/Documentation/Doxygen/Concepts/DataInteraction.dox +++ b/Core/Documentation/Doxygen/Concepts/DataInteraction.dox @@ -1,204 +1,222 @@ /** \page DataInteractionPage Interaction Concepts \tableofcontents \section InteractionPage_Introduction Introduction to Interaction in MITK Interaction is a very important task in medical image processing software. Therefore MITK provides a special interaction concept that provides the developer with an easy way to develop and maintain user interaction separately from the algorithms processing the input. This allows e.g. for common interaction schemes to be re-used in different contexts. The core of the interaction concept is based on entities called \b DataInteractors that listen for certain pre-defined events and execute actions when such an event is triggered.\n In the following the different components of the interaction concept are explained. First a a high-level overview about how the different components interact is given, then some parts are explained in more detail. \subsection FurtherReadingInteraction Topics related to interaction - further information: See the \ref DataInteractionTechnicalPage page for a more technical explanation. \n Consult \ref HowToUseDataInteractor for usage information.\n -See \ref SectionImplementationDataInteractor for an example on how to implement a new DataInteractor \n +See \ref SectionImplementationDataInteractor for an example on how to implement a new mitk::DataInteractor \n for information about how to create new events refer to ImplementNewEventsPage.\n The documentation of the depricated former concept can be found at \ref InteractionPage. -\section HandlingSection Event Handling & Window Manager Abstraction +\section HandlingSection Event Handling & GUI Toolkit Abstraction -The following sequence diagram gives an examplary overview of the process from creating an event until executing an action in the DataInteractor. -This diagram assumes the usage of the Qt framework, but also shows that the interaction concept itself is implemented independent of any specific window manager. +The following sequence diagram gives an exemplary overview of the process from creating an event until executing an action in the mitk::DataInteractor. +This diagram assumes the usage of the Qt framework, but also shows that the interaction concept itself is implemented independent of any specific +graphical user interface toolkit. \image html event_handling.png
  1. a user event is triggered and send to MITK -
  2. this layler serves as an adapter from window manager (here Qt) events to MITK internal events (later refered to as InteractionEvents). -
  3. once the event is adapted it is send to a Dispatcher, which is linked to a render window, to be handled. -
  4. on Dispatcher level all objects are known that can react to incoming events (DataInteractors) -
  5. a DataInteractor is offered an event and checks its EventConfig object, which returns if a variant if this event has been defined for this DataInteractor. +
  6. this layer serves as an adapter from the GUI toolkit (here Qt) events to MITK internal events (later referred to as \link mitk::InteractionEvent InteractionEvents\endlink). +
  7. once the event is adapted it is send to a mitk::Dispatcher, which is linked to a render window, to be handled. +
  8. on the mitk::Dispatcher level all objects are known that can react to incoming events (mitk::DataInteractor and mitk::InteractionEventObserver instances) +
  9. a mitk::DataInteractor is offered an event and checks its mitk::EventConfig object, which returns if a variant of this event has been defined for this DataInteractor.
  10. if the DataInteractor has a variant for the event, it consults its state machine to check if the input can be handled in the current state -
  11. the actions asociated with a state change (transition) are executed and the event is successfully handled. +
  12. the actions associated with a state change (transition) are executed and the event is successfully handled.
\section EventPage Events Events can describe any sort of user input, such as key strokes, mouse clicks or touch gestures. These events are mapped from an UI framework like Qt to an MITK internal representation -and send to the Dispatcher which in turn deals with further processing of the event. -These events are not limited to classical input devices but can be extened at will, by introducing new classes which e.g. describe +and send to the mitk::Dispatcher which in turn deals with further processing of the event. +These events are not limited to classical input devices but can be extended at will, by introducing new classes which e.g. describe events from tracking devices, etc. Refer to \subpage ImplementNewEventsPage to see how new events and thereby input devices can be integrated. For an overview of available Events see mitk::InteractionEvent, for on overview of parameters see the \subpage DataInteractionTechnicalPage. \section InteractionEventHandlerSection InteractionEventHandler -Is the term describing objects in general that can handle events. These objects can be devided into two groups, namely -DataInteractors and InteractionEventObserver. Their difference is that DataInteractors are linked with a DataNode which they manipulate, -whereas InteractionEventObserver do not have a DataNode and therefore are not supposed to manipulate any data. +Is the term describing objects in general that can handle events. These objects can be divided into two groups, namely +\link mitk::DataInteractor DataInteractors\endlink and mitk::InteractionEventObserver. Their difference is that mitk::DataInteractor instances are +linked with a mitk::DataNode which they manipulate, whereas mitk::InteractionEventObserver instances do not have a mitk::DataNode and therefore +are not supposed to manipulate any data. \dot digraph linker_deps { node [shape=record, fontname=Helvetica, fontsize=10]; a [ label="InteractionEventHandler" ]; - d [ label="{StateMachine|HandleEvent()}" ]; - b [ label="{DataInteractor|HandleEvent()}" ]; - c [ label="{InteractionEventObserver|Notify()}" ]; + d [ label="{EventStateMachine|HandleEvent()}" ]; + b [ label="{DataInteractor|PerformAction()}" ]; a -> d; d -> b; - d -> c; } \enddot \subsection DataInteractorsSection DataInteractors -DataInteractors are specialized InteractionEventHandler which handle events for one spefific DataNode. They are implemented following a concept called state machines +DataInteractors are specialized mitk::InteractionEventHandler which handle events for one spefific DataNode. They are implemented following a concept called state machines (see e.g. Wikipedia ). \subsubsection StateMachinesSection StateMachines -A specific events action is usually desired to dependent on the content of the data object the state of the interaction. -For example if the when adding a line by clicking with the mouse, the first to clicks are supposed to add a point. +A specific events action is usually desired to depend on the content of the data object and the state of the interaction. +For example when adding a line by clicking with the mouse, the first two clicks are supposed to add a point. But the second click should additionally finish the interaction and a subsequent third click should be ignored. State machines provide a great way to model such interaction in which the same user interaction can trigger different actions depending on the current state. Therefore DataInteractors work with so called state machine patterns. The basic idea here is that each interaction can be described by states and transitions which in turn trigger actions. -These patterns define a workflow and different patterns can be applied to the same DataInteractor and cause this DataInteractor +These patterns define a workflow and different patterns can be applied to the same mitk::DataInteractor and cause this mitk::DataInteractor to perform different user interactions. This principle is best described by an example. -Imagine a DataInteractor with the functionality (1) to add Points at a given mouse position and connect them by a line and (2) check if two -points are on the same position. Using this DataInteractor, different StateMachine patterns/descriptions -can be given which each cause the DataInteractor to perform different interaction schemes. +Imagine a mitk::DataInteractor with the functionality (1) to add Points at a given mouse position and connect them by a line and (2) check if two +points are on the same position. Using this mitk::DataInteractor, different mitk::StateMachine patterns/descriptions +can be given which each cause the mitk::DataInteractor to perform different interaction schemes. State machine pattern 1: We want the user to draw a line. A simple state machine could express this by three states like this: \dot digraph linker_deps { node [shape=circle, fontname=Helvetica, fontsize=10]; a [ label="NoPoints" ]; b [ label="OnePoint" ]; c [ label="TwoPoints" ]; a -> b [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; b -> c [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; { rank=same; a b c } } \enddot With each MousePress event the AddPoint function is called and adds a point at the mouse position, unless two points already exist. State machine pattern 2: -The same DataInteractor can also operate after the following state machine, which models the interaction to input a closed contour. -The DataInteractor can detect an AddPoint event on an already existing point and will trigger a PointsMatch event. +The same mitk::DataInteractor can also operate after the following state machine, which models the interaction to input a closed contour. +The mitk::DataInteractor can detect an AddPoint event on an already existing point and will trigger a PointsMatch event. \dot digraph { node [shape=circle, fontname=Helvetica, fontsize=10]; a [ label="StartState" ]; b [ label="ClosedContour"]; a -> a [label="MousePress/AddPoint",fontname=Helvetica, fontsize=10]; a -> b [label="PointsMatch/AddPoint",fontname=Helvetica, fontsize=10]; } \enddot In this way state machines provide both, a nice and structured way to represent interaction tasks and description of the interaction which is separated from the code. One DataInteractor can be re-used for different tasks by simply exchanging the state machine pattern. These patterns are described in XML files. \subsubsection DefinitionStateMachine Definition of a State Machine The definition is made up out of three components.
  • States - represent the current status of the interaction
  • Transitions - describe the events needed to change from one state to another
  • Actions - are executed, when a transition is taken
Each state machine needs exactly one designated start state into which the state machine is set in the beginning. An example of a state machine describing the interaction of example 2 looks like this: \code \endcode Example 1: State machine pattern, that describes adding points to a contour until the PointsMatch event is triggered. -For a more detailed desciption of state machine patterns see here. +For a more detailed description of state machine patterns see here. \subsection InteractionEventObserverSection InteractionEventObserver -InteractionEventObserver are objects which will receive all user input and are intented for observation only, they should never modify any DataNodes. -For InteractionEventObserver it is optional to use the state machine functionality, the default is without. How to use the state machine functionality - is described in the documentation of mitk::InteractionEventObserver::Notify. - -\subsection ConfigurationSection Configuration -In a lot of cases it is preferable to implement interactions independent of a specific event (e.g. left click with mouse), such that is it possible -to easily change this. This is achieved through configuration of InteractionEventHandlers. This allows to change the behavior at runtime. -The InteractionEventHandler provides an interface to easily modify the user input that triggers an action by loading a different configuration, this allows to implement -user-specific behavior of the software on an abstract level and to switch in at runtime. -This is achieved through XML files describing a configuration. These files can be loaded by the InteractionEventHandler and will lead to an internal mapping -from specific user input to an absract description of the event given in the config file. +mitk::InteractionEventObserver instances are objects which will receive all user input and are intended for observation only, +they should never modify any DataNodes. +For mitk::InteractionEventObserver it is optional to use the state machine functionality, the default is without. How to use the state machine functionality +is described in the documentation of mitk::InteractionEventObserver::Notify. -In order to do this we distinguish between a spefic event and an event variant. A specific event is described by its event class, which determines the -category of an event, e.g. the class MousePressEvent, and its parameter which make this event unique, e.g. LeftMouseButton pressed and no modifier keys pressed. -The event variant is a name that is assigned to a spefific event, and to which an InteractionEventHandler listens. +\dot +digraph event_observer { + node [shape=record, fontname=Helvetica, fontsize=10]; + c [ label="{InteractionEventObserver|Notify()}" ]; + a [ label="InteractionEventHandler" ]; + b [ label="{EventStateMachine|HandleEvent()}" ]; + d [ label="{MyCustomObserver|PerformAction()}" ]; + c -> d; + a -> b; + b -> d [style="dashed",label="optional"]; +} +\enddot -To illustrate this, an example is given here for two different configuration files. We assume an InteractionEventHandler that listens to the event variant 'AddPoint', -two possible config files could then look like this: +\subsection ConfigurationSection Configuration +In a lot of cases it is preferable to implement interactions independent of a specific event (e.g. left click with mouse), such that it is possible +to easily change this. This is achieved through configuration of \link mitk::InteractioinEventHandler InteractionEventHandlers\endlink. +This allows to change the behavior at runtime. +The mitk::InteractionEventHandler class provides an interface to easily modify the user input that triggers an action by loading a different +configuration. This allows to implement +user-specific behavior of the software on an abstract level and to switch it at runtime. +This is achieved through XML files describing a configuration. These files can be loaded by the mitk::InteractionEventHandler and will lead to an internal mapping +from specific user input to an abstract description of the event given in the config file. + +In order to do this we distinguish between a specific event and an event variant. A specific event is described by its event class, which determines the +category of an event, e.g. the class mitk::MousePressEvent, and its parameter which make this event unique, e.g. LeftMouseButton pressed and no modifier keys pressed. +The event variant is a name that is assigned to a specific event, and to which an mitk::InteractionEventHandler listens. + +To illustrate this, an example is given here for two different configuration files. We assume that a mitk::InteractionEventHandler listens to the +event variant 'AddPoint', two possible config files could then look like this: \code \endcode Example 2: Event description of a left click with the mouse and \code \endcode Example 3: Event description of a left click with the mouse while pressing the shift-key -If the InteractionEventHandler is loaded with the first configuration the event variant 'MousePress' is triggered when the user performs a mouse click, +If the mitk::InteractionEventHandler is loaded with the first configuration the event variant 'MousePress' is triggered when the user performs a mouse click, while when the second configuration is loaded 'MousePress' is triggered when the user performs a right click while pressing the shift button. -In this way all objects derived by InteractionEventHandler can be configured. For a detailed description about how to create the XML file see \ref ConfigurationTechnical . +In this way all objects derived from mitk::InteractionEventHandler can be configured. For a detailed description about how to create the XML file see the +\ref DataInteractionTechnicalPage page. \section DispatcherSection Dispatcher -This unit receives all events and distributes them to the DataInteractors. This is done by ordering the DataInteractors according to the layer of their -DataNode in descending order. Then the event is offered to the first DataInteractor, which in turn checks if it can handle the event. This is done -for each DataInteractor until the first processes the event, after this the other DataInteractors are skipped and all InteractionEventObservers are notified. +Instances of mitk::Dispatcher receive all events and distribute them to their related mitk::DataInteractor instances. This is done by ordering +the DataInteractors according to the layer of their +mitk::DataNode in descending order. Then the event is offered to the first mitk::DataInteractor, which in turn checks if it can handle the event. This is done +for each mitk::DataInteractor until the first processes the event, after this the other DataInteractors are skipped and all InteractionEventObservers are notified. */ diff --git a/Core/Documentation/Doxygen/Concepts/DataInteractionTechnical.dox b/Core/Documentation/Doxygen/Concepts/DataInteractionTechnical.dox index 45e2f161b5..01447e6b83 100644 --- a/Core/Documentation/Doxygen/Concepts/DataInteractionTechnical.dox +++ b/Core/Documentation/Doxygen/Concepts/DataInteractionTechnical.dox @@ -1,116 +1,115 @@ /** \page DataInteractionTechnicalPage Interaction Concept Implementation \tableofcontents This page describes some technicalities of the implementation and the workflow, for a detailed list of tutorials see \ref FurtherReadingInteraction . \section DataInteractionTechnicalPage_Introduction Description of Interaction Concept Implementation in MITK \section DispatcherSection Dispatcher -After an event is received by the Dispatcher it is given to a DataInteractor that has to decide if it can process this event. +After an event is received by the mitk::Dispatcher it is given to a mitk::DataInteractor that has to decide if it can process this event. On a high level this is done by the mitk::EventStateMachine. First the state machine asks if the received event is known in the -configuration. If it does the matching variant name is returned. Then the state machine checks if there exists a transition +configuration. If it is, the matching variant name is returned. Then the state machine checks if there exists a transition in its current state that is triggered by this event variant. If this is the case all actions that are associated with this transition -are queried and executed. The actions themselves are implemented on DataInteractor level. The following diagram illustrates the process: +are queried and executed. The actions themselves are implemented on mitk::DataInteractor level. The following diagram illustrates the process: \image html sm_and_config.png -Each BaseRenderer creates a mitk::BindDispatcherInteractor object which encapsulates the connection between the DataStorage and the Dispatcher, -and thereby allowing a DataInteractor to register with a Dispatcher when only knowing the DataNode. +Each mitk::BaseRenderer creates a mitk::BindDispatcherInteractor object which encapsulates the connection between the mitk::DataStorage and +the mitk::Dispatcher, and thereby allowing a mitk::DataInteractor to register with a mitk::Dispatcher when only knowing the mitk::DataNode. -BindDispatcherInteractor creates a new Dispatcher object and registers for DataNode events at the DataStorage, as a callback function the -Dispatchers AddDataInteractor() and RemoveDataInteractor() functions are set. +mitk::BindDispatcherInteractor creates a new mitk::Dispatcher object and registers for mitk::DataNode events at the mitk::DataStorage, as a callback function the +dispatchers AddDataInteractor() and RemoveDataInteractor() functions are set. \dot digraph { node [shape=record, fontname=Helvetica, fontsize=10]; a [ label="{BaseRenderer|m_BindDispatcherInteractor}"]; b [ label="{BindDispatcherInteractor|m_Dispatcher\n m_DataStorage}" ]; c [ label="Dispatcher" ]; d [ label="DataStorage" ]; a -> b; b -> c; b -> d; } \enddot -This way the Dispatcher is notified about all changes regarding -DataNodes that are shown in the BaseRenderer. When a node is added, remove or modified the Dispatcher can check it a DataInterator is set, -and accordingly add or remove this DataInteractor from its internal list. +This way the mitk::Dispatcher is notified about all changes regarding +DataNodes that are shown in the mitk::BaseRenderer. When a node is added, remove or modified the mitk::Dispatcher can check if a mitk::DataInterator is set, +and accordingly add or remove this mitk::DataInteractor from its internal list. \dot digraph { node [shape=record, fontname=Helvetica, fontsize=10]; d [ label="DataInteractor" ]; a [ label="DataNode" ]; b [ label="DataStorage" ]; c [ label="Dispatcher" ]; e [ label="BaseRenderer"] edge [fontname=Helvetica, fontsize=10] d -> a [label="SetDataInteractor(this)"]; a -> b [label="Modified()"]; b -> c [label="NodeModified(dataNode)"]; e -> c [label="HandleEvent(interactionEvent)"]; { rank=same; b c a } { rank=same; e } } \enddot -Events that are generated within the scope of the BaseRenderer are sent to the associated Dispatcher to be handled. +Events that are generated within the scope of the mitk::BaseRenderer are sent to the associated mitk::Dispatcher to be handled. \subsection DispatcherEventDistSection Event Distribution - A Dispatcher can operate in different processing modes, which determine how the interactor that receives an event is chosen. - These modes are managed and set by the Dispatcher itself. + A mitk::Dispatcher can operate in different processing modes, which determine how the interactor that receives an event is chosen. + These modes are managed and set by the mitk::Dispatcher itself.
  • \b Regular: \n DataInteractors are sorted by their layer, and distribution is stared with the top-most. -
  • \bConnected \b Mouse \b Action: - - A connected mouse action is described by the sequence of Mouse-Press, (optionally) Mouse-Move , Mouse-Release Events.\n - Within this sequence all events are sent to the same DateInteractor, the one which received the event from the Mouse-Press action.\n +
  • Connected Mouse Action: \n + A connected mouse action is described by the sequence of Mouse-Press, (optionally) Mouse-Move , Mouse-Release Events.\n + Within this sequence all events are sent to the same mitk::DataInteractor, the one which received the event from the Mouse-Press action.\n \b m_ConnectedMouseAction - is set to true, when a Mouse-Down Event occurs and a DataInterator takes the event and \b m_SelectedInteractor is then set to this DataInteractor.\n \b m_ConnectedMouseAction is reset to false, after the Mouse-Release Event occurs,\n while it is true, the m_SelectedInteractor is the only one that receives Mouse-Events. -
  • \b Grab \b Input:\n - Whenever a DataInteractor performs a state change into a state that is marked by the grab input-tag, the Dispatcher switches into this mode. - As long as it is in this mode ONLY the selected DataInteractor will receive the event. This mode is ended when the DataInteractor switches back to - a state without a tag/ or the REGULAR-tag.\n - \note In this mode EventObservers will NOT receive the events. +
  • Grab Input:\n + Whenever a mitk::DataInteractor performs a state change into a state that is marked by the grab input-tag, the mitk::Dispatcher switches into this mode. + As long as it is in this mode ONLY the selected mitk::DataInteractor will receive the event. This mode is ended when the mitk::DataInteractor + switches back to a state without a tag/ or the REGULAR-tag.\n + \note In this mode mitk::InteractionEventObserver instances will NOT receive the events.
  • \b Prefer \b Input: \n - Basically works as Grab Input, with the difference that if the Interactor in an prefer input state, cannot process the event offered, + Basically works as Grab Input, with the difference that if the mitk::DataInteractor is in the prefer input state but cannot process the event offered, it will be offered to the other interactors in the regular way.\n - In this mode EventObservers ARE informed. + In this mode mitk::InteractionEventObserver instances ARE informed.
\section StateMachineSection State Machine & Configuration A mitk::EventStateMachine points to a \b state, which in turn references \b transitions (which describe a change from one state to another) and \b actions (indicating which functions are executed when a transition is taken). \dot digraph { node [shape=record, fontname=Helvetica, fontsize=10]; d [ label="{StateMachine|m_CurrentState}" ]; a [ label="{StateMachineState|m_Transitions}" ]; b [ label="{StateMachineTransitions|m_Actions}"]; c [ label="{StateMachineAction}"]; edge [fontname=Helvetica, fontsize=10] d -> a [label="1 : 1"]; a -> b [label="1 : n"]; b -> c [label="1 : n"]; } \enddot - */ \ No newline at end of file + */ diff --git a/Core/Documentation/Doxygen/Concepts/Pipelining.dox b/Core/Documentation/Doxygen/Concepts/Pipelining.dox index 576fd2bdfb..5b97d384eb 100644 --- a/Core/Documentation/Doxygen/Concepts/Pipelining.dox +++ b/Core/Documentation/Doxygen/Concepts/Pipelining.dox @@ -1,94 +1,94 @@ /** \page PipelineingConceptPage Pipelining Concept Available Sections: -# \ref PipelineingConceptPage_Introduction "Introduction to Pipelining" -# \ref PipelineingConceptPage_InMITK "Pipelining in MITK" -# \ref PipelineingConceptPage_Update "The Update() Mechanism" -# \ref PipelineingConceptPage_Hierarchy "Pipeline Hierarchy" -# \ref PipelineingConceptPage_WorkWith "Working with Filter" -# \ref PipelineingConceptPage_Setup "Setting Up a Pipeline" -# \ref PipelineingConceptPage_Implement "Writing your own Filter" \section PipelineingConceptPage_Introduction Introduction to Pipelining Image processing in MITK draws heavily from the pipelining concept, and a clear understaning of it is crucial when developing with MITK. This document will first clarify the general idea behind pipelining and then discuss some MITK specifics that you should know about. In the real world, a pipeline connects a source of some kind with a consumer of another. So we identify three key concepts: 1. The source, which generates data of some kind. -2. The pipeline, which transports the data. Many different pipeline segements can be switched in line to achieve this. +2. The pipeline, which transports the data. Many different pipeline segments can be switched in line to achieve this. 3. The consumer, which uses the data to do something of interest. The analogy to real pipelines falls a little short in one point: A physical pipeline would never process it's contents, while in software development a pipeline usually does (this is why they are often dubbed filters as well). One might ask why one shouldn't just implement the processing logic in the consumer onject itself, since it onviously knows best what to do with it's data. The two main reasons for this are reusability and flexibility. Say, one wants to display a bone segmentation from a CT-image. Let's also assume for the sake of this introduction, that this is a simple task. One could build a monolithic class that solves the problem. Or one builds a pipeline between the displaying class and the source. We know that bones are very bright in a CT Scan, so we use a treshold filter, and then a segmentation Filter to solve the problem. \image html pipelining_example_ct.png Now let's further assume that after successfully selling this new technology to a large firm, we plan to do the same with ultrasound imaging technology. The brithness relations in Ultrasound images are basically the same, but ultrasound images are very noisy, and the contrast is significantly lower. Since we used pipelining, this is no problem: We don't need to change our old segmentation class - we just plug two new filters in front of the pipeline: \image html pipelining_example_us.png This may seem trivial, but when working with several input streams from many different devices that themselves stem from many different vendors, pipelining can save the day when it comes to broad range support of different specifications. \section PipelineingConceptPage_InMITK Pipelining in MITK \subsection PipelineingConceptPage_Update The Update() Mechanism The flow of data inside a pipeline is triggered by only one function call to the consumer, which is Update(). Each part of the pipeline then triggers the Update() method of it's antecessor. Finally, the source creates a new batch of data using it's own GenerateData() method, and notifies its successor that new data is available. The pipeline can then start to process the data until the finished data batch is available as an output of the last Filter. \image html pipelining_update.png \subsection PipelineingConceptPage_Hierarchy The Pipeline Hierarchy Tha base class for all parts of the pipeline except the consumer (which can be of any class) is mitk::Baseprocess. This class introduces the ability to process data, has an output and may have an input as well. You will however rarly work with this class directly. \image html pipelining_hierarchy.png Several source classes extend BaseProcess. Depending on the type of data they deliver, these are ImageSource, PointSetSource and SurfaceSource. All of these mark the start of a pipeline. The filters themselves extend one of the source classes. This may not immediately make sense, but remember that a filter basically is a source with an additional input. \section PipelineingConceptPage_WorkWith Working with Filter \subsection PipelineingConceptPage_Setup Setting Up a Pipeline \verbatim // Create Participants mitk::USVideoDevice::Pointer videoDevice = mitk::USVideoDevice::New("-1", "Manufacturer", "Model"); TestUSFilter::Pointer filter = TestUSFilter::New(); // Make Videodevice produce it's first set of Data, so it's output isn't empty videoDevice->Update(); // attacht filter input to device output filter->SetInput(videoDevice->GetOutput()); // Pipeline is now functional filter->Update(); \endverbatim \subsection PipelineingConceptPage_Implement Writing Your Own Filter When writing your first Filter, this is the recommended way to go about: - Identify which kinds of Data you require for input, and which for output - According to the information from step one, extend the most specific subclass of BaseProcess available. E.g. a filter that processes images, should extend ImageToImageFilter. - Identify how many inputs and how many outputs you require. - In the constructor, define the number of outputs, and create an output. \verbatim //set number of outputs this->SetNumberOfOutputs(1); //create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); \endverbatim - Implement MakeOutput(). This Method creats a new, clean Output that can be written to. Refer to Filters with similiar task for this. - Implement GenerateData(). This Method will generate the output based on the input it. At time of execution you can assume that the Data in input is a new set. */ \ No newline at end of file diff --git a/Core/Documentation/Doxygen/Concepts/images/geometryoverview/CoordinateTypes.png b/Core/Documentation/Doxygen/Concepts/images/geometryoverview/CoordinateTypes.png index c7585e19bf..a2d87a5614 100644 Binary files a/Core/Documentation/Doxygen/Concepts/images/geometryoverview/CoordinateTypes.png and b/Core/Documentation/Doxygen/Concepts/images/geometryoverview/CoordinateTypes.png differ diff --git a/Core/Documentation/Doxygen/Concepts/images/pipelining/pipelining_example_us.png b/Core/Documentation/Doxygen/Concepts/images/pipelining/pipelining_example_us.png index 00f1c88427..1ea5fcc538 100644 Binary files a/Core/Documentation/Doxygen/Concepts/images/pipelining/pipelining_example_us.png and b/Core/Documentation/Doxygen/Concepts/images/pipelining/pipelining_example_us.png differ diff --git a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox index 542dd477c9..a5b5e4d1f9 100644 --- a/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox +++ b/Documentation/Doxygen/DeveloperManual/Starting/GettingToKnow/Tutorial/Step10.dox @@ -1,432 +1,433 @@ /** \page Step10Page MITK Tutorial - Step 10: Adding new Interaction \tableofcontents \section HowToUseDataInteractor How to use an existing DataInteractor MITK provides finished DataInteractors for a variety of tasks, they can be found in Code/Core/Interactors. They can be used with -state machine patterns and config files located under Resources/Interaction. +state machine patterns and config files located under Resources/Interactions. -A DataInteractor consists of four parts. The class describing the functionality and two XML files; one describes the state machine pattern, that is the workflow of an interaction and -the second describes the user events which trigger an action. Lastly every DataInteractor works on a DataNode in which it stores and manipulates data. -To use a DataInteractor these parts have to be brought together. +A mitk::DataInteractor consists of four parts. The class describing the functionality and two XML files; one describes the state machine pattern, that is the workflow of an interaction and +the second describes the user events which trigger an action. Lastly every mitk::DataInteractor works on a mitk::DataNode in which it stores and manipulates data. +To use a mitk::DataInteractor these parts have to be brought together. -This code demonstrates the use of an existing DataInteractor exemplary for the PointSetDataInteractor: +This code demonstrates the use of an existing mitk::DataInteractor exemplary for the mitk::PointSetDataInteractor: -First we need a DataNode that is added to the DataStorage. +First we need a mitk::DataNode that is added to the mitk::DataStorage. \code mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); GetDataStorage()->Add(dataNode.GetPointer()); \endcode -Then we create an instance of to PointSetDataInteractor and load a statemachine pattern as well as a configuration +Then we create an instance of a mitk::PointSetDataInteractor and load a statemachine pattern as well as a configuration for it: \code m_CurrentInteractor = mitk::PointSetDataInteractor::New(); m_CurrentInteractor->LoadStateMachine("PointSet.xml"); - m_CurrentInteractor->LoadEventConfig("PointSetConfig.xml"); + m_CurrentInteractor->SetEventConfig("PointSetConfig.xml"); \endcode -Lastly the DataNode is added to the DataInteractor +Lastly the mitk::DataNode is added to the mitk::DataInteractor \code m_CurrentInteractor->SetDataNode(dataNode); \endcode -now the DataInteractor is ready for usage. +now the mitk::DataInteractor is ready for usage. \section SectionImplementationDataInteractor How to implement a new DataInteractor This second part of the tutorial step goes beyond the activation of an interactor, that modifies data by user interaction) as shown above. It shows what needs to be implemented to add a new way of interaction within your MITK application. Please see \ref DataInteractionPage as an introduction to the MITK interaction mechanism, you may also want to read \ref DataInteractionTechnicalPage. This tutorial is structured as follows: The first section deals with config files, describing all the parameters of events and how to use them in a configuration file. In the second section the basics are described that are needed to write a state machine pattern. The last section -deals with brining configuration, state machine pattern and code together and gives an examplary implementation of a DataInteractor. +deals with brining configuration, state machine pattern and code together and gives an exemplary implementation of a mitk::DataInteractor. \section ConfigFileDescriptionSection How to create a Config-File \subsection EventDescriptionSection Event Description Events are described by their parameters. Each event type has its own set of parameters that can be set in the configuration file. -If a parameter is ommitted it is set to its default value. Following all possible parameters are listed and described, to which parameters -events have is decribed in their respective documentation. +If a parameter is omitted it is set to its default value. All possible parameters are listed and described below. Event parameters +are also described in the documentation of the event class itself. Mandatory for each event description is the event class and the event variant. The parameters of an event are set by attribute tags. \note Refer to \ref EventClassSection for the meaning of event class. \b Mouse \b Buttons \n -mitk::MouseButtons represent the buttons. They can be used for two attributes. First the EventButton which describes the button that triggered the event, -this allways is a single button. Secondly the ButtonState attribute that describes which buttons were pressed at the moment the event has been generated. -For example assume the right mouse button and the middle mouse button are already pressed, now also the left mouse button is pressed too and generates a second event, +mitk::InteractionEvent::MouseButtons represent the buttons. They can be used for two attributes. First the EventButton attribute which describes +the button that triggered the event, +this always is a single button. Secondly the ButtonState attribute that describes which buttons were pressed at the moment the event has been generated. +For example assume the right mouse button and the middle mouse button are already pressed, now the left mouse button is pressed too and generates a second event, this would be described as follows: \code \endcode -Note: Technically the LeftMouseButton is also pressed and should be listed in the ButtonState, but this is taken care of by the mitk:EventFactory . +Note: Technically the LeftMouseButton is also pressed and should be listed in the ButtonState, but this is taken care of by the mitk::EventFactory . Key Events \n mitk::InteractionKeyEvent represents a pressed key, which key is pressed is provided with the Key attribute like this \code \endcode or \code \endcode -\note Key Events do not require an explicit configuration all, for all key events there exists +\note Key Events do not require an explicit configuration, for all key events there exists a predefined event variant with the name 'Std' + value, that is key a is named 'StdA'. The names for special keys are listed here: -\dontinclude mitkInteractionEventConst.h +\dontinclude mitkInteractionEvent.h \skipline // Special Keys \until // End special keys Modifier Keys \n -mitk::ModifierKeys represent the combination of pressed modifier keys, several modifier keys pressed at the same time +mitk::InteractionEvent::ModifierKeys represent the combination of pressed modifier keys, several modifier keys pressed at the same time are denoted by listing them all separated by commas. \code \endcode \b ScrollDirection \n This attribute is unique to the mitk::MouseWheelEvent and describes the direction in which the mouse wheel is rotated. In the event description actual only the direction is provided, but the event is generated with the actual value, and this value can be retrieved from the object. \code \endcode \subsection ExamplesSection Examples Examples for key events: \code \endcode Examples for MousePress events: \code \endcode There exists a standard configuration file for the most common events called GlobalConfig.xml that can be used to as a default and can be extended by a specific definition. \subsection ParameterDescriptionSection Parameter Description It is also possible to store parameters in the config file. Those are stored using the param-tag, like this: \code \endcode Within the application these properties can then be access via a mitk::PropertyList like this: \code // sm - state machine loaded with config file example2 mitk::PropertyList::Pointer properties = GetAttributes(); std::string prop1; properties->GetStringProperty("property1",prop1); \endcode \section HowToStateMachine HowTo Write a State Machine A state machine pattern is described in a XML file. \subsection StateSection States States are described using the state-tag. Each state has to have a name. Exactly one state has to be as start state in each state machine to indicate the state in which the state machine is set when it is constructed. So a valid, but rather useless state machine would like like this: \code \endcode Optionally a state can be assigned a special mode that influences the event distribution. These modes are GRAB_INPUT , PREFER_INPUT and REGULAR (where REGULAR is default and does not need to be indicated). See \ref DispatcherEventDistSection for a description of these modes. Use the special modes only when necessary as they prevent other DataInteractors to receive events. \code \endcode \subsection TransitionSection Transitions -Transitions are part of a state and describe all possible state switches, and are therefore important for modelling an interaction scheme. +Transitions are part of a state and describe all possible state switches, and are therefore important for modeling an interaction scheme. Transitions consist a part that describes the event which triggers the transition (event class and event variant) and a target which is state to which the state machine switches after executing a transition. An event class describes the event type (see mitk::InteractionEvent for the different classes) and the event variant is a specification thereof and the exact description is taken from a config file. Together they determine which event can trigger this transition. For example this state machine will switch from state A to state B when the StdMousePressPrimaryButton event (left mouse button is pressed) occurs. \subsubsection EventClassSection Event Class The event class description supports the polymorphism of the event classes. Therefore state machine patters should be written in the most general ways possible. So for a given class hierarchy like this: \dot digraph { node [shape=record, fontname=Helvetica, fontsize=10]; - a [ label="{PositionEvent}"]; + a [ label="{InteractionPositionEvent}"]; b [ label="{MousePressEvent}" ]; c [ label="MouseReleaseEvent" ]; d [ label="TouchEvent", style=dotted ]; a -> b; a -> c; a -> d; } \enddot -in the state machine pattern the PositionEvent can be declared as event class to restrict to the events which hold a position information. -The actual implementation is then given in the configuration file. In this case it allows to define event of the classes PositionEvent itself, or -MousePressEvent,MouseReleaseEvent,TouchEvent. +in the state machine pattern the mitk::InteractionPositionEvent can be declared as event class to restrict to the events which hold a position information. +The actual implementation is then given in the configuration file. In this case it allows to define events of the classes mitk::InteractionPositionEvent +itself, or mitk::MousePressEvent, mitk::MouseReleaseEvent, mitk::TouchEvent. This has the advantage that the patterns remain the same no matter what input devices are used, and the state machine patterns can be configured -for newly added event classes as long as they match the class hierachy (this ensures they hold the neccessary properties). +for newly added event classes as long as they match the class hierarchy (this ensures they hold the necessary properties). \code \endcode \subsection ActionSection Actions -Actions can be added to transitions and represent functions in the DataInteractor that are executed on taking a transition. +Actions can be added to transitions and represent functions in the mitk::DataInteractor that are executed on taking a transition. The following simple state machine will listen for left mouse clicks and execute two actions (and actually never stop). \code \endcode -In order to tell the DataInteractor which function to execute these actions are made known to the DataInteractor using -the CONNECT_FUNCTION macro. This example assumes that there exists an ExampleInteractor which inherits from DataInteractor. +In order to tell the mitk::DataInteractor which function to execute these actions are made known to the mitk::DataInteractor using +the CONNECT_FUNCTION macro. This example assumes that there exists an ExampleInteractor which inherits from mitkDataInteractor. This class implements the functions AddPoint and CountClicks. The actions are introduced by implementing the virtual method ConnectActionsAndFunctions(): \code void mitk::ExampleInteractor::ConnectActionsAndFunctions() { CONNECT_FUNCTION("addPoint", AddPoint); CONNECT_FUNCTION("countClicks", CountClicks); } \endcode \section HowToDataInteractor Implementation a new DataInteractor DataInteractors are to inherit from mitk::DataInteractor. Their functionality is implemented in functions that follow this interface: \code bool SomeFunctionality(StateMachineAction* , InteractionEvent*); \endcode Your functions are connected with actions by implementing the function ConnectActionsAndFunctions(), e.g. \code void mitk::ExampleInteractor::ConnectActionsAndFunctions() { CONNECT_FUNCTION("addPoint", AddPoint); CONNECT_FUNCTION("enoughPoints", EnoughPoints); } \endcode Now all that is left it to write a state machine pattern and a config file as is described in the tutorials. \subsection ExampleInternalEvent PointSetDataInteractor To provide a useful example the mitk::PointSetDataInteractor is annotated with comments that describe the important parts for an implementation -of a DataInteractor. +of a mitk::DataInteractor. -This step assumes knowlege of the Interaction concept described in \ref DataInteractionPage and some background of the implementation which is described in +This step assumes knowledge of the Interaction concept described in \ref DataInteractionPage and some background of the implementation which is described in \ref DataInteractionPageTechnical. Please refer to these pages before proceeding. DataInteractor are to inherit from mitk::DataInteractor. Their functionality is implemented in functions that follow this interface: \code bool SomeFunctionality(StateMachineAction* , InteractionEvent*); \endcode Your functions are connected with actions by implementing the function ConnectActionsAndFunctions(), e.g. \code void mitk::ExampleInteractor::ConnectActionsAndFunctions() { CONNECT_FUNCTION("addPoint", AddPoint); CONNECT_FUNCTION("enoughPoints", EnoughPoints); } \endcode Now all that is left it to write a state machine pattern and a config file as is described in the tutorials. \subsection ExampleInternalEvent Example Interactor using InternalEvent -A useful tool in creating DataInteractors are mitk::InternalEvents which allow to the DataInteractor send signals on its own. -The following will describe how to build a DataInteractor that allows to add points until a certain number of points is reached. +A useful tool in creating DataInteractors is mitk::InternalEvent which allows the mitk::DataInteractor to send signals on its own. +The following will describe how to build a mitk::DataInteractor that allows to add points until a certain number of points is reached. The number of accepted points is provided in the config file as a parameter. -So we start by writing a state machine pattern that add points until it receives an InternalEvent telling it, that enough points +So we start by writing a state machine pattern that add points until it receives an mitk::InternalEvent telling it, that enough points have been added. \code <--! dead state, nothing happens any more, once we reached this --> \endcode In our config file we set the number of maximal points to 10, and define AddPointClick as a right mouse click with the ctrl button pressed. \code \endcode -The implementation is desribed in the following. \see Step10.h \see Step10.cpp +The implementation is described in the following. \see Step10.h \see Step10.cpp \dontinclude Step10.h Implementation of protected functions: \skipline protected: \until virtual void ConfigurationChanged(); ConnectActionsAndFunctions - Is inherited from mitk::InteractionStateMachine, here action strings from the xml are connected with -functions in the Interactor (as seen above). In our example this looks like this: +functions in the mitk::DataInteractor (as seen above). In our example this looks like this: \dontinclude Step10.cpp \skipline void mitk::ExampleInteractor::ConnectActionsAndFunctions() \until } ConfigurationChanged - Is called whenever a new configuration file is loaded (by the mitk::InteractionEventHandler super class), this function allows to implement initialization code that depends on configuration values. In our example we want to set the limit of allowed points: \dontinclude Step10.cpp \skipline void mitk::ExampleInteractor::ConfigurationChang \until } Next the actual functionality of the DataInteractor is implemented, by providing one function per action, following this prototype: \code bool FUNCTION_NAME (StateMachineAction* , InteractionEvent*); \endcode \dontinclude Step10.h \skipline private: \until bool EnoughPoints(StateMac Each function has to return a boolean value. True if the action has been executed, and false if the action has not been executed. \dontinclude Step10.cpp \skipline bool mitk::ExampleInteractor::AddPoint(StateM \until //- Here we see an internal event used to signal that the point set reached the maximal number of allowed points. The event is created and added to the Dispatchers event queue. \dontinclude Step10.cpp \skipline // create internal \until positionEvent->GetSender( -\note That internal events do not need any mapping to event variants. Their signal same is equivalent with the event variant. +\note Internal events do not need any mapping to event variants. Their signal same is equivalent with the event variant. - There are also two documented classes implementing a DataInteractor and an InteractionEventObserver which can be looked at for further + There are also two documented classes implementing a mitk::DataInteractor and a mitk::InteractionEventObserver which can be looked at for further understanding: \see mitk::PointSetDataInteractor \see mitk::DisplayInteractor Have fun with creating your own interaction and please think about contributing it to MITK! If you meet any difficulties during this step, don't hesitate to ask on the MITK mailing list mitk-users@lists.sourceforge.net! People there are kind and will try to help you. \ref Step09Page "[Previous step]" \ref TutorialPage "[Main tutorial page]" */ diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt index 9005b35b9d..dc1781f1a1 100644 --- a/Modules/CMakeLists.txt +++ b/Modules/CMakeLists.txt @@ -1,59 +1,60 @@ set(LIBPOSTFIX "Ext") # Modules must be listed according to their dependencies set(module_dirs SceneSerializationBase PlanarFigure ImageExtraction ImageStatistics LegacyAdaptors IpPicSupport MitkExt SceneSerialization + GraphAlgorithms Segmentation Qmitk QmitkExt - GraphAlgorithms + Properties DiffusionImaging GPGPU IGT CameraCalibration IGTUI RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport Overlays InputDevices ToFHardware ToFProcessing ToFUI US ClippingTools USUI DicomUI Simulation Python ) set(MITK_DEFAULT_SUBPROJECTS MITK-Modules) foreach(module_dir ${module_dirs}) add_subdirectory(${module_dir}) endforeach() if(MITK_PRIVATE_MODULES) file(GLOB all_subdirs RELATIVE ${MITK_PRIVATE_MODULES} ${MITK_PRIVATE_MODULES}/*) foreach(subdir ${all_subdirs}) string(FIND ${subdir} "." _result) if(_result EQUAL -1) if(EXISTS ${MITK_PRIVATE_MODULES}/${subdir}/CMakeLists.txt) message(STATUS "Found private module ${subdir}") add_subdirectory(${MITK_PRIVATE_MODULES}/${subdir} private_modules/${subdir}) endif() endif() endforeach() endif(MITK_PRIVATE_MODULES) diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp new file mode 100644 index 0000000000..71a534c155 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.cpp @@ -0,0 +1,80 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __itkDftImageFilter_txx +#define __itkDftImageFilter_txx + +#include +#include +#include + +#include "itkDftImageFilter.h" +#include +#include +#include + +#define _USE_MATH_DEFINES +#include + +namespace itk { + +template< class TPixelType > +DftImageFilter< TPixelType > +::DftImageFilter() +{ + this->SetNumberOfRequiredInputs( 1 ); +} + +template< class TPixelType > +void DftImageFilter< TPixelType > +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId) +{ + typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); + + ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); + + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + + int szx = outputImage->GetLargestPossibleRegion().GetSize(0); + int szy = outputImage->GetLargestPossibleRegion().GetSize(1); + + while( !oit.IsAtEnd() ) + { + int kx = oit.GetIndex()[0]; + int ky = oit.GetIndex()[1]; + + vcl_complex s(0,0); + InputIteratorType it(inputImage, inputImage->GetLargestPossibleRegion() ); + while( !it.IsAtEnd() ) + { + int x = it.GetIndex()[0]; + int y = it.GetIndex()[1]; + + vcl_complex f = it.Get(); + s += f * exp( std::complex(0, -2 * M_PI * (kx*(double)x/szx + ky*(double)y/szy) ) ); + + ++it; + } + double magn = sqrt(s.real()*s.real()+s.imag()*s.imag()); + oit.Set(magn); + + ++oit; + } +} + +} +#endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h new file mode 100644 index 0000000000..44ac8af59a --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkDftImageFilter.h @@ -0,0 +1,74 @@ +/*=================================================================== + +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. + +===================================================================*/ + +/*=================================================================== + +This file is based heavily on a corresponding ITK filter. + +===================================================================*/ +#ifndef __itkDftImageFilter_h_ +#define __itkDftImageFilter_h_ + +#include "FiberTrackingExports.h" +#include +#include +#include + +namespace itk{ + +/** +* \brief Performes deterministic streamline tracking on the input tensor image. */ + + template< class TPixelType > + class DftImageFilter : + public ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< TPixelType > > + { + + public: + + typedef DftImageFilter Self; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef ImageToImageFilter< Image< vcl_complex< TPixelType > >, Image< TPixelType > > Superclass; + + /** Method for creation through the object factory. */ + itkNewMacro(Self) + + /** Runtime information support. */ + itkTypeMacro(DftImageFilter, ImageToImageFilter) + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + + protected: + DftImageFilter(); + ~DftImageFilter() {} + + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId); + + private: + + }; + +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkDftImageFilter.cpp" +#endif + +#endif //__itkDftImageFilter_h_ + diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp index 42c816e097..ed4dedef0b 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp @@ -1,512 +1,509 @@ /*=================================================================== 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 "itkGibbsTrackingFilter.h" // MITK #include #include #include #include #include //#include #include #include // ITK #include #include #include // MISC #include #include #include #include +#include namespace itk{ template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::GibbsTrackingFilter(): m_StartTemperature(0.1), m_EndTemperature(0.001), m_Iterations(500000), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ConnectionPotential(10), m_InexBalance(0), m_ParticlePotential(0.2), m_MinFiberLength(10), m_AbortTracking(false), m_NumConnections(0), m_NumParticles(0), m_NumAcceptedFibers(0), m_CurrentStep(0), m_BuildFibers(false), m_Steps(10), m_ProposalAcceptance(0), m_CurvatureThreshold(0.7), m_DuplicateImage(true), m_RandomSeed(-1), m_LoadParameterFile(""), m_LutPath(""), m_IsInValidState(true) { } template< class ItkQBallImageType > GibbsTrackingFilter< ItkQBallImageType >::~GibbsTrackingFilter() { } // fill output fiber bundle datastructure template< class ItkQBallImageType > typename GibbsTrackingFilter< ItkQBallImageType >::FiberPolyDataType GibbsTrackingFilter< ItkQBallImageType >::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType > ::EstimateParticleWeight() { MITK_INFO << "GibbsTrackingFilter: estimating particle weight"; float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; float m_ParticleLength = 1.5*minSpacing; float m_ParticleWidth = 0.5*minSpacing; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // instantiate all necessary components SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } ParticleGrid* particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); GibbsEnergyComputer* encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); // EnergyComputer* encomp = new EnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); MetropolisHastingsSampler* sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); float alpha = log(m_EndTemperature/m_StartTemperature); m_ParticleWeight = 0.01; int ppv = 0; // main loop int neededParts = 3000; while (ppvSetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); for( int step = 0; step < 10; step++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*step)/((1.0)*10))); sampler->SetTemperature(temperature); for (unsigned long i=0; i<10000; i++) sampler->MakeProposal(); } ppv = particleGrid->m_NumParticles; particleGrid->ResetGrid(); } delete sampler; delete encomp; delete particleGrid; delete interpolator; MITK_INFO << "GibbsTrackingFilter: finished estimating particle weight"; } // perform global tracking template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::GenerateData() { TimeProbe preClock; preClock.Start(); // check if input is qball or tensor image and generate qball if necessary if (m_QBallImage.IsNull() && m_TensorImage.IsNotNull()) { TensorImageToQBallImageFilter::Pointer filter = TensorImageToQBallImageFilter::New(); filter->SetInput( m_TensorImage ); filter->Update(); m_QBallImage = filter->GetOutput(); } else if (m_DuplicateImage) // generate local working copy of QBall image (if not disabled) { typedef itk::ImageDuplicator< ItkQBallImageType > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_QBallImage ); duplicator->Update(); m_QBallImage = duplicator->GetOutput(); } // perform mean subtraction on odfs typedef ImageRegionIterator< ItkQBallImageType > InputIteratorType; InputIteratorType it(m_QBallImage, m_QBallImage->GetLargestPossibleRegion() ); it.GoToBegin(); while (!it.IsAtEnd()) { itk::OrientationDistributionFunction odf(it.Get().GetDataPointer()); float mean = odf.GetMeanValue(); odf -= mean; it.Set(odf.GetDataPointer()); ++it; } // check if mask image is given if it needs resampling PrepareMaskImage(); // load parameter file LoadParameters(); // prepare parameters float minSpacing; if(m_QBallImage->GetSpacing()[0]GetSpacing()[1] && m_QBallImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[0]; else if (m_QBallImage->GetSpacing()[1] < m_QBallImage->GetSpacing()[2]) minSpacing = m_QBallImage->GetSpacing()[1]; else minSpacing = m_QBallImage->GetSpacing()[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) EstimateParticleWeight(); float alpha = log(m_EndTemperature/m_StartTemperature); m_Steps = m_Iterations/10000; if (m_Steps<10) m_Steps = 10; if (m_Steps>m_Iterations) { MITK_INFO << "GibbsTrackingFilter: not enough iterations!"; m_AbortTracking = true; } if (m_CurvatureThreshold < mitk::eps) m_CurvatureThreshold = 0; unsigned long singleIts = (unsigned long)((1.0*m_Iterations) / (1.0*m_Steps)); // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // load sphere interpolator to evaluate the ODFs SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } // initialize the actual tracking components (ParticleGrid, Metropolis Hastings Sampler and Energy Computer) ParticleGrid* particleGrid; GibbsEnergyComputer* encomp; MetropolisHastingsSampler* sampler; try{ particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); encomp = new GibbsEnergyComputer(m_QBallImage, m_MaskImage, particleGrid, interpolator, randGen); encomp->SetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); } catch(...) { MITK_ERROR << "Particle grid allocation failed. Not enough memory? Try to increase the particle length."; m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; return; } MITK_INFO << "----------------------------------------"; MITK_INFO << "Iterations: " << m_Iterations; MITK_INFO << "Steps: " << m_Steps; MITK_INFO << "Particle length: " << m_ParticleLength; MITK_INFO << "Particle width: " << m_ParticleWidth; MITK_INFO << "Particle weight: " << m_ParticleWeight; MITK_INFO << "Start temperature: " << m_StartTemperature; MITK_INFO << "End temperature: " << m_EndTemperature; MITK_INFO << "In/Ex balance: " << m_InexBalance; MITK_INFO << "Min. fiber length: " << m_MinFiberLength; MITK_INFO << "Curvature threshold: " << m_CurvatureThreshold; MITK_INFO << "Random seed: " << m_RandomSeed; MITK_INFO << "----------------------------------------"; // main loop preClock.Stop(); TimeProbe clock; clock.Start(); m_NumAcceptedFibers = 0; unsigned long counter = 1; + + boost::progress_display disp(m_Steps*singleIts); if (!m_AbortTracking) for( m_CurrentStep = 1; m_CurrentStep <= m_Steps; m_CurrentStep++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*m_CurrentStep)/((1.0)*m_Steps))); sampler->SetTemperature(temperature); for (unsigned long i=0; iMakeProposal(); if (m_BuildFibers || (i==singleIts-1 && m_CurrentStep==m_Steps)) { m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); m_BuildFibers = false; } counter++; } m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/counter; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; - MITK_INFO << "GibbsTrackingFilter: proposal acceptance: " << 100*m_ProposalAcceptance << "%"; - MITK_INFO << "GibbsTrackingFilter: particles: " << m_NumParticles; - MITK_INFO << "GibbsTrackingFilter: connections: " << m_NumConnections; - MITK_INFO << "GibbsTrackingFilter: progress: " << 100*(float)m_CurrentStep/m_Steps << "%"; - MITK_INFO << "GibbsTrackingFilter: cell overflows: " << particleGrid->m_NumCellOverflows; - MITK_INFO << "----------------------------------------"; - if (m_AbortTracking) break; } if (m_AbortTracking) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); } clock.Stop(); delete sampler; delete encomp; delete interpolator; delete particleGrid; m_AbortTracking = true; m_BuildFibers = false; int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: finished gibbs tracking in " << h << "h, " << m << "m and " << s << "s"; m = (int)preClock.GetTotal()/60; s = (int)preClock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: preparation of the data took " << m << "m and " << s << "s"; MITK_INFO << "GibbsTrackingFilter: " << m_NumAcceptedFibers << " fibers accepted"; SaveParameters(); } template< class ItkQBallImageType > void GibbsTrackingFilter< ItkQBallImageType >::PrepareMaskImage() { if(m_MaskImage.IsNull()) { MITK_INFO << "GibbsTrackingFilter: generating default mask image"; m_MaskImage = ItkFloatImageType::New(); m_MaskImage->SetSpacing( m_QBallImage->GetSpacing() ); m_MaskImage->SetOrigin( m_QBallImage->GetOrigin() ); m_MaskImage->SetDirection( m_QBallImage->GetDirection() ); m_MaskImage->SetRegions( m_QBallImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1.0); } else if ( m_MaskImage->GetLargestPossibleRegion().GetSize()[0]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[0] || m_MaskImage->GetLargestPossibleRegion().GetSize()[1]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[1] || m_MaskImage->GetLargestPossibleRegion().GetSize()[2]!=m_QBallImage->GetLargestPossibleRegion().GetSize()[2] || m_MaskImage->GetSpacing()[0]!=m_QBallImage->GetSpacing()[0] || m_MaskImage->GetSpacing()[1]!=m_QBallImage->GetSpacing()[1] || m_MaskImage->GetSpacing()[2]!=m_QBallImage->GetSpacing()[2] ) { MITK_INFO << "GibbsTrackingFilter: resampling mask image"; typedef itk::ResampleImageFilter< ItkFloatImageType, ItkFloatImageType, float > ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); resampler->SetOutputSpacing( m_QBallImage->GetSpacing() ); resampler->SetOutputOrigin( m_QBallImage->GetOrigin() ); resampler->SetOutputDirection( m_QBallImage->GetDirection() ); resampler->SetSize( m_QBallImage->GetLargestPossibleRegion().GetSize() ); resampler->SetInput( m_MaskImage ); resampler->SetDefaultPixelValue(0.0); resampler->Update(); m_MaskImage = resampler->GetOutput(); MITK_INFO << "GibbsTrackingFilter: resampling finished"; } } // load tracking paramters from xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::LoadParameters() { m_AbortTracking = true; try { if( m_LoadParameterFile.length()==0 ) { m_AbortTracking = false; return true; } MITK_INFO << "GibbsTrackingFilter: loading parameter file " << m_LoadParameterFile; TiXmlDocument doc( m_LoadParameterFile ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); QString iterations(pElem->Attribute("iterations")); m_Iterations = iterations.toULong(); QString particleLength(pElem->Attribute("particle_length")); m_ParticleLength = particleLength.toFloat(); QString particleWidth(pElem->Attribute("particle_width")); m_ParticleWidth = particleWidth.toFloat(); QString partWeight(pElem->Attribute("particle_weight")); m_ParticleWeight = partWeight.toFloat(); QString startTemp(pElem->Attribute("temp_start")); m_StartTemperature = startTemp.toFloat(); QString endTemp(pElem->Attribute("temp_end")); m_EndTemperature = endTemp.toFloat(); QString inExBalance(pElem->Attribute("inexbalance")); m_InexBalance = inExBalance.toFloat(); QString fiberLength(pElem->Attribute("fiber_length")); m_MinFiberLength = fiberLength.toFloat(); QString curvThres(pElem->Attribute("curvature_threshold")); m_CurvatureThreshold = cos(curvThres.toFloat()*M_PI/180); m_AbortTracking = false; MITK_INFO << "GibbsTrackingFilter: parameter file loaded successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not load parameter file"; return false; } } // save current tracking paramters to xml file (.gtp) template< class ItkQBallImageType > bool GibbsTrackingFilter< ItkQBallImageType >::SaveParameters() { try { if( m_SaveParameterFile.length()==0 ) { MITK_INFO << "GibbsTrackingFilter: no filename specified to save parameters"; return true; } MITK_INFO << "GibbsTrackingFilter: saving parameter file " << m_SaveParameterFile; TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", QString::number(m_Iterations).toStdString()); paramXML->SetAttribute("particle_length", QString::number(m_ParticleLength).toStdString()); paramXML->SetAttribute("particle_width", QString::number(m_ParticleWidth).toStdString()); paramXML->SetAttribute("particle_weight", QString::number(m_ParticleWeight).toStdString()); paramXML->SetAttribute("temp_start", QString::number(m_StartTemperature).toStdString()); paramXML->SetAttribute("temp_end", QString::number(m_EndTemperature).toStdString()); paramXML->SetAttribute("inexbalance", QString::number(m_InexBalance).toStdString()); paramXML->SetAttribute("fiber_length", QString::number(m_MinFiberLength).toStdString()); paramXML->SetAttribute("curvature_threshold", QString::number(m_CurvatureThreshold).toStdString()); mainXML->LinkEndChild(paramXML); QString filename(m_SaveParameterFile.c_str()); if(!filename.endsWith(".gtp")) filename += ".gtp"; documentXML.SaveFile( filename.toStdString() ); MITK_INFO << "GibbsTrackingFilter: parameter file saved successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not save parameter file"; return false; } } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h index c792454cfc..831e995140 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.h @@ -1,153 +1,153 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef itkGibbsTrackingFilter_h #define itkGibbsTrackingFilter_h // MITK #include // ITK #include #include #include #include // VTK #include #include #include #include #include namespace itk{ /** * \brief Performes global fiber tractography on the input Q-Ball or tensor image (Gibbs tracking, Reisert 2010). */ template< class ItkQBallImageType > class GibbsTrackingFilter : public ProcessObject { public: typedef GibbsTrackingFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; itkNewMacro(Self) itkTypeMacro( GibbsTrackingFilter, ProcessObject ) typedef Image< DiffusionTensor3D, 3 > ItkTensorImage; typedef typename ItkQBallImageType::Pointer ItkQBallImageTypePointer; typedef Image< float, 3 > ItkFloatImageType; typedef vtkSmartPointer< vtkPolyData > FiberPolyDataType; // parameter setter itkSetMacro( StartTemperature, float ) itkSetMacro( EndTemperature, float ) itkSetMacro( Iterations, unsigned long ) itkSetMacro( ParticleWeight, float ) itkSetMacro( ParticleWidth, float ) itkSetMacro( ParticleLength, float ) itkSetMacro( ConnectionPotential, float ) itkSetMacro( InexBalance, float ) itkSetMacro( ParticlePotential, float ) itkSetMacro( MinFiberLength, int ) itkSetMacro( AbortTracking, bool ) itkSetMacro( CurvatureThreshold, float) itkSetMacro( DuplicateImage, bool ) itkSetMacro( RandomSeed, int ) itkSetMacro( LoadParameterFile, std::string ) itkSetMacro( SaveParameterFile, std::string ) itkSetMacro( LutPath, std::string ) // getter itkGetMacro( ParticleWeight, float ) itkGetMacro( ParticleWidth, float ) itkGetMacro( ParticleLength, float ) itkGetMacro( CurrentStep, unsigned long ) itkGetMacro( NumParticles, int ) itkGetMacro( NumConnections, int ) itkGetMacro( NumAcceptedFibers, int ) itkGetMacro( ProposalAcceptance, float ) itkGetMacro( Steps, unsigned int) itkGetMacro( IsInValidState, bool) // input data itkSetMacro(QBallImage, typename ItkQBallImageType::Pointer) itkSetMacro(MaskImage, ItkFloatImageType::Pointer) itkSetMacro(TensorImage, ItkTensorImage::Pointer) void GenerateData(); virtual void Update(){ this->GenerateData(); } FiberPolyDataType GetFiberBundle(); protected: GibbsTrackingFilter(); virtual ~GibbsTrackingFilter(); void EstimateParticleWeight(); void PrepareMaskImage(); bool LoadParameters(); bool SaveParameters(); // Input Images typename ItkQBallImageType::Pointer m_QBallImage; typename ItkFloatImageType::Pointer m_MaskImage; typename ItkTensorImage::Pointer m_TensorImage; // Tracking parameters - float m_StartTemperature; // Start temperature - float m_EndTemperature; // End temperature - unsigned long m_Iterations; // Total number of iterations - unsigned long m_CurrentStep; // current tracking step - float m_ParticleWeight; // w (unitless) - float m_ParticleWidth; // sigma (mm) - float m_ParticleLength; // l (mm) - float m_ConnectionPotential; // gross L (chemisches potential, default 10) - float m_InexBalance; // gewichtung zwischen den lambdas; -5 ... 5 -> nur intern ... nur extern,default 0 - float m_ParticlePotential; // default 0.2 - int m_MinFiberLength; // discard all fibers shortan than the specified length in mm - bool m_AbortTracking; // set flag to abort tracking - int m_NumAcceptedFibers; // number of reconstructed fibers generated by the FiberBuilder - volatile bool m_BuildFibers; // set flag to generate fibers from particle grid - unsigned int m_Steps; // number of temperature decrease steps - float m_ProposalAcceptance; // proposal acceptance rate (0-1) - float m_CurvatureThreshold; // curvature threshold in radians (1 -> no curvature is accepted, -1 all curvature angles are accepted) - bool m_DuplicateImage; // generates a working copy of the qball image so that the original image won't be changed by the mean subtraction - int m_NumParticles; // current number of particles in grid - int m_NumConnections; // current number of connections between particles in grid - int m_RandomSeed; // seed value for random generator (-1 for standard seeding) - std::string m_LoadParameterFile; // filename of parameter file (reader) - std::string m_SaveParameterFile; // filename of parameter file (writer) - std::string m_LutPath; // path to lookuptables used by the sphere interpolator - bool m_IsInValidState; // Whether the filter is in a valid state, false if error occured - - FiberPolyDataType m_FiberPolyData; // container for reconstructed fibers + float m_StartTemperature; ///< Start temperature + float m_EndTemperature; ///< End temperature + unsigned long m_Iterations; ///< Total number of iterations + unsigned long m_CurrentStep; ///< current tracking step + float m_ParticleWeight; ///< w (unitless) + float m_ParticleWidth; ///< sigma (mm) + float m_ParticleLength; ///< l (mm) + float m_ConnectionPotential; ///< gross L (chemisches potential, default 10) + float m_InexBalance; ///< gewichtung zwischen den lambdas; -5 ... 5 -> nur intern ... nur extern,default 0 + float m_ParticlePotential; ///< default 0.2 + int m_MinFiberLength; ///< discard all fibers shortan than the specified length in mm + bool m_AbortTracking; ///< set flag to abort tracking + int m_NumAcceptedFibers; ///< number of reconstructed fibers generated by the FiberBuilder + volatile bool m_BuildFibers; ///< set flag to generate fibers from particle grid + unsigned int m_Steps; ///< number of temperature decrease steps + float m_ProposalAcceptance; ///< proposal acceptance rate (0-1) + float m_CurvatureThreshold; ///< curvature threshold in radians (1 -> no curvature is accepted, -1 all curvature angles are accepted) + bool m_DuplicateImage; ///< generates a working copy of the qball image so that the original image won't be changed by the mean subtraction + int m_NumParticles; ///< current number of particles in grid + int m_NumConnections; ///< current number of connections between particles in grid + int m_RandomSeed; ///< seed value for random generator (-1 for standard seeding) + std::string m_LoadParameterFile; ///< filename of parameter file (reader) + std::string m_SaveParameterFile; ///< filename of parameter file (writer) + std::string m_LutPath; ///< path to lookuptables used by the sphere interpolator + bool m_IsInValidState; ///< Whether the filter is in a valid state, false if error occured + + FiberPolyDataType m_FiberPolyData; ///< container for reconstructed fibers //Constant values static const int m_ParticleGridCellCapacity = 1024; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkGibbsTrackingFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp new file mode 100644 index 0000000000..28d46f4ed7 --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.cpp @@ -0,0 +1,167 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __itkKspaceImageFilter_txx +#define __itkKspaceImageFilter_txx + +#include +#include +#include + +#include "itkKspaceImageFilter.h" +#include +#include +#include + +#define _USE_MATH_DEFINES +#include + +namespace itk { + +template< class TPixelType > +KspaceImageFilter< TPixelType > +::KspaceImageFilter() + : m_tLine(1) + , m_kOffset(0) +{ + this->SetNumberOfRequiredInputs( 1 ); +} + +template< class TPixelType > +void KspaceImageFilter< TPixelType > +::BeforeThreadedGenerateData() +{ + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + m_SpectrumImage = InputImageType::New(); + m_SpectrumImage->SetSpacing( inputImage->GetSpacing() ); + m_SpectrumImage->SetOrigin( inputImage->GetOrigin() ); + m_SpectrumImage->SetDirection( inputImage->GetDirection() ); + m_SpectrumImage->SetLargestPossibleRegion( inputImage->GetLargestPossibleRegion() ); + m_SpectrumImage->SetBufferedRegion( inputImage->GetLargestPossibleRegion() ); + m_SpectrumImage->SetRequestedRegion( inputImage->GetLargestPossibleRegion() ); + m_SpectrumImage->Allocate(); + m_SpectrumImage->FillBuffer(0); + + if (m_FrequencyMap.IsNull()) + { + m_FrequencyMap = InputImageType::New(); + m_FrequencyMap->SetSpacing( inputImage->GetSpacing() ); + m_FrequencyMap->SetOrigin( inputImage->GetOrigin() ); + m_FrequencyMap->SetDirection( inputImage->GetDirection() ); + m_FrequencyMap->SetLargestPossibleRegion( inputImage->GetLargestPossibleRegion() ); + m_FrequencyMap->SetBufferedRegion( inputImage->GetLargestPossibleRegion() ); + m_FrequencyMap->SetRequestedRegion( inputImage->GetLargestPossibleRegion() ); + m_FrequencyMap->Allocate(); + m_FrequencyMap->FillBuffer(0); + } + + m_tLine /= 1000; +} + +template< class TPixelType > +void KspaceImageFilter< TPixelType > +::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId) +{ + typename OutputImageType::Pointer outputImage = static_cast< OutputImageType * >(this->ProcessObject::GetOutput(0)); + + ImageRegionIterator< OutputImageType > oit(outputImage, outputRegionForThread); + + typedef ImageRegionConstIterator< InputImageType > InputIteratorType; + typename InputImageType::Pointer inputImage = static_cast< InputImageType * >( this->ProcessObject::GetInput(0) ); + + double szx = outputImage->GetLargestPossibleRegion().GetSize(0); + double szy = outputImage->GetLargestPossibleRegion().GetSize(1); + double numPix = szx*szy; + double dt = m_tLine/szx; + + double fromMaxEcho = - m_tLine*szy/2; + + while( !oit.IsAtEnd() ) + { + double kx = oit.GetIndex()[0]; + double ky = oit.GetIndex()[1]; + + int temp_k = kx; + if (oit.GetIndex()[1]%2 == 1) + { + temp_k = szx-kx-1; // reverse readout direction + kx -= m_kOffset; // add gradient delay induced offset + } + else + kx += m_kOffset; // add gradient delay induced offset + + double t = fromMaxEcho + (ky*szx+temp_k)*dt; + + vcl_complex s(0,0); + InputIteratorType it(inputImage, inputImage->GetLargestPossibleRegion() ); + while( !it.IsAtEnd() ) + { + double x = it.GetIndex()[0]; + double y = it.GetIndex()[1]; + + vcl_complex f(it.Get(), 0); + s += f * exp( std::complex(0, 2 * M_PI * (kx*x/szx + ky*y/szy) + m_FrequencyMap->GetPixel(it.GetIndex())*10*t ) ); + + ++it; + } + s /= numPix; + double magn = sqrt(s.real()*s.real()+s.imag()*s.imag()); + m_SpectrumImage->SetPixel(oit.GetIndex(), magn); + oit.Set(s); + + ++oit; + } +} + +template< class TPixelType > +void KspaceImageFilter< TPixelType > +::AfterThreadedGenerateData() +{ + ImageRegion<2> region = m_SpectrumImage->GetLargestPossibleRegion(); + typename InputImageType::Pointer rearrangedSlice = InputImageType::New(); + rearrangedSlice->SetLargestPossibleRegion( region ); + rearrangedSlice->SetBufferedRegion( region ); + rearrangedSlice->SetRequestedRegion( region ); + rearrangedSlice->Allocate(); + + int xHalf = region.GetSize(0)/2; + int yHalf = region.GetSize(1)/2; + + for (int y=0; yGetPixel(idx); + + if( idx[0] < xHalf ) + idx[0] = idx[0] + xHalf; + else + idx[0] = idx[0] - xHalf; + + if( idx[1] < yHalf ) + idx[1] = idx[1] + yHalf; + else + idx[1] = idx[1] - yHalf; + + rearrangedSlice->SetPixel(idx, pix); + } + + m_SpectrumImage = rearrangedSlice; +} + +} +#endif diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h new file mode 100644 index 0000000000..d258c6f19f --- /dev/null +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkKspaceImageFilter.h @@ -0,0 +1,87 @@ +/*=================================================================== + +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. + +===================================================================*/ + +/*=================================================================== + +This file is based heavily on a corresponding ITK filter. + +===================================================================*/ +#ifndef __itkKspaceImageFilter_h_ +#define __itkKspaceImageFilter_h_ + +#include "FiberTrackingExports.h" +#include +#include +#include + +namespace itk{ + +/** +* \brief Performes deterministic streamline tracking on the input tensor image. */ + + template< class TPixelType > + class KspaceImageFilter : + public ImageToImageFilter< Image< TPixelType >, Image< vcl_complex< TPixelType > > > + { + + public: + + typedef KspaceImageFilter Self; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef ImageToImageFilter< Image< TPixelType >, Image< vcl_complex< TPixelType > > > Superclass; + + /** Method for creation through the object factory. */ + itkNewMacro(Self) + + /** Runtime information support. */ + itkTypeMacro(KspaceImageFilter, ImageToImageFilter) + + typedef typename Superclass::InputImageType InputImageType; + typedef typename Superclass::OutputImageType OutputImageType; + typedef typename Superclass::OutputImageRegionType OutputImageRegionType; + + itkGetMacro( SpectrumImage, typename InputImageType::Pointer ) + + itkSetMacro( FrequencyMap, typename InputImageType::Pointer ) + itkSetMacro( tLine, double ) + itkSetMacro( kOffset, double ) + + protected: + KspaceImageFilter(); + ~KspaceImageFilter() {} + + void BeforeThreadedGenerateData(); + void ThreadedGenerateData( const OutputImageRegionType &outputRegionForThread, int threadId); + void AfterThreadedGenerateData(); + + typename InputImageType::Pointer m_SpectrumImage; + typename InputImageType::Pointer m_FrequencyMap; + double m_tLine; + double m_kOffset; + + private: + + }; + +} + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkKspaceImageFilter.cpp" +#endif + +#endif //__itkKspaceImageFilter_h_ + diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp index 4a0b9e729a..0208fac36e 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.cpp @@ -1,613 +1,651 @@ /*=================================================================== 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 "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include namespace itk { TractsToDWIImageFilter::TractsToDWIImageFilter() : m_CircleDummy(false) , m_VolumeAccuracy(10) , m_Upsampling(1) , m_NumberOfRepetitions(1) , m_EnforcePureFiberVoxels(false) , m_InterpolationShrink(10) , m_FiberRadius(20) , m_SignalScale(300) + , m_kOffset(0) + , m_tLine(1) { m_Spacing.Fill(2.5); m_Origin.Fill(0.0); m_DirectionMatrix.SetIdentity(); m_ImageRegion.SetSize(0, 10); m_ImageRegion.SetSize(1, 10); m_ImageRegion.SetSize(2, 10); } TractsToDWIImageFilter::~TractsToDWIImageFilter() { } -std::vector< TractsToDWIImageFilter::DoubleDwiType::Pointer > TractsToDWIImageFilter::AddKspaceArtifacts( std::vector< DoubleDwiType::Pointer >& images ) +std::vector< TractsToDWIImageFilter::DoubleDwiType::Pointer > TractsToDWIImageFilter::DoKspaceStuff( std::vector< DoubleDwiType::Pointer >& images ) { // create slice object SliceType::Pointer slice = SliceType::New(); ImageRegion<2> region; region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); region.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); slice->SetLargestPossibleRegion( region ); slice->SetBufferedRegion( region ); slice->SetRequestedRegion( region ); slice->Allocate(); + // frequency map slice + SliceType::Pointer fMap = NULL; + if (m_FrequencyMap.IsNotNull()) + { + fMap = SliceType::New(); + ImageRegion<2> region; + region.SetSize(0, m_UpsampledImageRegion.GetSize()[0]); + region.SetSize(1, m_UpsampledImageRegion.GetSize()[1]); + fMap->SetLargestPossibleRegion( region ); + fMap->SetBufferedRegion( region ); + fMap->SetRequestedRegion( region ); + fMap->Allocate(); + } + boost::progress_display disp(images.size()*images[0]->GetVectorLength()*images[0]->GetLargestPossibleRegion().GetSize(2)); std::vector< DoubleDwiType::Pointer > outImages; for (int i=0; iSetSpacing( m_Spacing ); newImage->SetOrigin( m_Origin ); newImage->SetDirection( m_DirectionMatrix ); newImage->SetLargestPossibleRegion( m_ImageRegion ); newImage->SetBufferedRegion( m_ImageRegion ); newImage->SetRequestedRegion( m_ImageRegion ); newImage->SetVectorLength( image->GetVectorLength() ); newImage->Allocate(); DiffusionSignalModel* signalModel; if (iGetVectorLength(); g++) for (int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { ++disp; // extract slice from channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::PixelType pix2D = image->GetPixel(index3D)[g]; slice->SetPixel(index2D, pix2D); + + if (fMap.IsNotNull()) + fMap->SetPixel(index2D, m_FrequencyMap->GetPixel(index3D)); } // fourier transform slice - itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::Pointer fft = itk::FFTRealToComplexConjugateImageFilter< SliceType::PixelType, 2 >::New(); - fft->SetInput(slice); - fft->Update(); - ComplexSliceType::Pointer fSlice = fft->GetOutput(); + ComplexSliceType::Pointer fSlice; + itk::KspaceImageFilter< SliceType::PixelType >::Pointer idft = itk::KspaceImageFilter< SliceType::PixelType >::New(); + idft->SetInput(slice); + idft->SetkOffset(m_kOffset); + idft->SettLine(m_tLine); + idft->SetFrequencyMap(fMap); + idft->Update(); + + fSlice = idft->GetOutput(); fSlice = RearrangeSlice(fSlice); // add artifacts for (int a=0; aSetT2(signalModel->GetT2()); fSlice = m_KspaceArtifacts.at(a)->AddArtifact(fSlice); } // save k-space slice of s0 image if (g==m_FiberModels.at(0)->GetFirstBaselineIndex()) for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; double kpix = sqrt(fSlice->GetPixel(index2D).real()*fSlice->GetPixel(index2D).real()+fSlice->GetPixel(index2D).imag()*fSlice->GetPixel(index2D).imag()); m_KspaceImage->SetPixel(index3D, m_KspaceImage->GetPixel(index3D)+kpix); } // inverse fourier transform slice SliceType::Pointer newSlice; - itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::Pointer ifft = itk::FFTComplexConjugateToRealImageFilter< SliceType::PixelType, 2 >::New(); - ifft->SetInput(fSlice); - ifft->Update(); - newSlice = ifft->GetOutput(); + itk::DftImageFilter< SliceType::PixelType >::Pointer dft = itk::DftImageFilter< SliceType::PixelType >::New(); + dft->SetInput(fSlice); + dft->Update(); + newSlice = dft->GetOutput(); // put slice back into channel g for (int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType pix3D = newImage->GetPixel(index3D); SliceType::IndexType index2D; index2D[0]=x; index2D[1]=y; pix3D[g] = newSlice->GetPixel(index2D); newImage->SetPixel(index3D, pix3D); } } outImages.push_back(newImage); } return outImages; } TractsToDWIImageFilter::ComplexSliceType::Pointer TractsToDWIImageFilter::RearrangeSlice(ComplexSliceType::Pointer slice) { ImageRegion<2> region = slice->GetLargestPossibleRegion(); ComplexSliceType::Pointer rearrangedSlice = ComplexSliceType::New(); rearrangedSlice->SetLargestPossibleRegion( region ); rearrangedSlice->SetBufferedRegion( region ); rearrangedSlice->SetRequestedRegion( region ); rearrangedSlice->Allocate(); int xHalf = region.GetSize(0)/2; int yHalf = region.GetSize(1)/2; for (int y=0; y pix = slice->GetPixel(idx); if( idx[0] < xHalf ) idx[0] = idx[0] + xHalf; else idx[0] = idx[0] - xHalf; if( idx[1] < yHalf ) idx[1] = idx[1] + yHalf; else idx[1] = idx[1] - yHalf; rearrangedSlice->SetPixel(idx, pix); } return rearrangedSlice; } void TractsToDWIImageFilter::GenerateData() { // check input data if (m_FiberBundle.IsNull()) itkExceptionMacro("Input fiber bundle is NULL!"); int numFibers = m_FiberBundle->GetNumFibers(); if (numFibers<=0) itkExceptionMacro("Input fiber bundle contains no fibers!"); if (m_FiberModels.empty()) itkExceptionMacro("No diffusion model for fiber compartments defined!"); if (m_NonFiberModels.empty()) itkExceptionMacro("No diffusion model for non-fiber compartments defined!"); int baselineIndex = m_FiberModels[0]->GetFirstBaselineIndex(); if (baselineIndex<0) itkExceptionMacro("No baseline index found!"); // determine k-space undersampling for (int i=0; i*>(m_KspaceArtifacts.at(i)) ) m_Upsampling = dynamic_cast*>(m_KspaceArtifacts.at(i))->GetKspaceCropping(); if (m_Upsampling<1) m_Upsampling = 1; if (m_TissueMask.IsNotNull()) { // use input tissue mask m_Spacing = m_TissueMask->GetSpacing(); m_Origin = m_TissueMask->GetOrigin(); m_DirectionMatrix = m_TissueMask->GetDirection(); m_ImageRegion = m_TissueMask->GetLargestPossibleRegion(); if (m_Upsampling>1) { ImageRegion<3> region = m_ImageRegion; region.SetSize(0, m_ImageRegion.GetSize(0)*m_Upsampling); region.SetSize(1, m_ImageRegion.GetSize(1)*m_Upsampling); mitk::Vector3D spacing = m_Spacing; spacing[0] /= m_Upsampling; spacing[1] /= m_Upsampling; itk::RescaleIntensityImageFilter::Pointer rescaler = itk::RescaleIntensityImageFilter::New(); rescaler->SetInput(0,m_TissueMask); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_TissueMask); resampler->SetSize(region.GetSize()); resampler->SetOutputSpacing(spacing); resampler->Update(); m_TissueMask = resampler->GetOutput(); } MITK_INFO << "Using tissue mask"; } // initialize output dwi image OutputImageType::Pointer outImage = OutputImageType::New(); outImage->SetSpacing( m_Spacing ); outImage->SetOrigin( m_Origin ); outImage->SetDirection( m_DirectionMatrix ); outImage->SetLargestPossibleRegion( m_ImageRegion ); outImage->SetBufferedRegion( m_ImageRegion ); outImage->SetRequestedRegion( m_ImageRegion ); outImage->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); outImage->Allocate(); OutputImageType::PixelType temp; temp.SetSize(m_FiberModels[0]->GetNumGradients()); temp.Fill(0.0); outImage->FillBuffer(temp); // is input slize size a power of two? - int x=2; int y=2; - while (x " << x << " --> " << x*m_Upsampling; m_ImageRegion.SetSize(0, x); } if (y!=m_ImageRegion.GetSize(1)) { MITK_INFO << "Adjusting image height: " << m_ImageRegion.GetSize(1) << " --> " << y << " --> " << y*m_Upsampling; m_ImageRegion.SetSize(1, y); } // initialize k-space image m_KspaceImage = ItkDoubleImgType::New(); m_KspaceImage->SetSpacing( m_Spacing ); m_KspaceImage->SetOrigin( m_Origin ); m_KspaceImage->SetDirection( m_DirectionMatrix ); m_KspaceImage->SetLargestPossibleRegion( m_ImageRegion ); m_KspaceImage->SetBufferedRegion( m_ImageRegion ); m_KspaceImage->SetRequestedRegion( m_ImageRegion ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(0); // apply undersampling to image parameters m_UpsampledSpacing = m_Spacing; m_UpsampledImageRegion = m_ImageRegion; m_UpsampledSpacing[0] /= m_Upsampling; m_UpsampledSpacing[1] /= m_Upsampling; m_UpsampledImageRegion.SetSize(0, m_ImageRegion.GetSize()[0]*m_Upsampling); m_UpsampledImageRegion.SetSize(1, m_ImageRegion.GetSize()[1]*m_Upsampling); // everything from here on is using the upsampled image parameters!!! if (m_TissueMask.IsNull()) { m_TissueMask = ItkUcharImgType::New(); m_TissueMask->SetSpacing( m_UpsampledSpacing ); m_TissueMask->SetOrigin( m_Origin ); m_TissueMask->SetDirection( m_DirectionMatrix ); m_TissueMask->SetLargestPossibleRegion( m_UpsampledImageRegion ); m_TissueMask->SetBufferedRegion( m_UpsampledImageRegion ); m_TissueMask->SetRequestedRegion( m_UpsampledImageRegion ); m_TissueMask->Allocate(); m_TissueMask->FillBuffer(1); } + // resample frequency map + if (m_FrequencyMap.IsNotNull()) + { + itk::ResampleImageFilter::Pointer resampler = itk::ResampleImageFilter::New(); + resampler->SetInput(m_FrequencyMap); + resampler->SetOutputParametersFromImage(m_FrequencyMap); + resampler->SetSize(m_UpsampledImageRegion.GetSize()); + resampler->SetOutputSpacing(m_UpsampledSpacing); + resampler->Update(); + m_FrequencyMap = resampler->GetOutput(); + } + // resample fiber bundle for sufficient voxel coverage double segmentVolume = 0.0001; float minSpacing = 1; if(m_UpsampledSpacing[0]GetDeepCopy(); fiberBundle->ResampleFibers(minSpacing/m_VolumeAccuracy); double mmRadius = m_FiberRadius/1000; if (mmRadius>0) segmentVolume = M_PI*mmRadius*mmRadius*minSpacing/m_VolumeAccuracy; // generate double images to wokr with because we don't want to lose precision // we use a separate image for each compartment model std::vector< DoubleDwiType::Pointer > compartments; for (int i=0; iSetSpacing( m_UpsampledSpacing ); doubleDwi->SetOrigin( m_Origin ); doubleDwi->SetDirection( m_DirectionMatrix ); doubleDwi->SetLargestPossibleRegion( m_UpsampledImageRegion ); doubleDwi->SetBufferedRegion( m_UpsampledImageRegion ); doubleDwi->SetRequestedRegion( m_UpsampledImageRegion ); doubleDwi->SetVectorLength( m_FiberModels[0]->GetNumGradients() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_FiberModels[0]->GetNumGradients()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); compartments.push_back(doubleDwi); } double interpFact = 2*atan(-0.5*m_InterpolationShrink); double maxVolume = 0; vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); vtkSmartPointer vLines = fiberPolyData->GetLines(); vLines->InitTraversal(); MITK_INFO << "Generating signal of " << m_FiberModels.size() << " fiber compartments"; boost::progress_display disp(numFibers); for( int i=0; iGetNextCell ( numPoints, points ); if (numPoints<2) continue; for( int j=0; jGetPoint(points[j]); itk::Point vertex = GetItkPoint(temp); itk::Vector v = GetItkVector(temp); itk::Vector dir(3); if (jGetPoint(points[j+1]))-v; else dir = v-GetItkVector(fiberPolyData->GetPoint(points[j-1])); itk::Index<3> idx; itk::ContinuousIndex contIndex; m_TissueMask->TransformPhysicalPointToIndex(vertex, idx); m_TissueMask->TransformPhysicalPointToContinuousIndex(vertex, contIndex); double frac_x = contIndex[0] - idx[0]; double frac_y = contIndex[1] - idx[1]; double frac_z = contIndex[2] - idx[2]; if (frac_x<0) { idx[0] -= 1; frac_x += 1; } if (frac_y<0) { idx[1] -= 1; frac_y += 1; } if (frac_z<0) { idx[2] -= 1; frac_z += 1; } frac_x = atan((0.5-frac_x)*m_InterpolationShrink)/interpFact + 0.5; frac_y = atan((0.5-frac_y)*m_InterpolationShrink)/interpFact + 0.5; frac_z = atan((0.5-frac_z)*m_InterpolationShrink)/interpFact + 0.5; // use trilinear interpolation itk::Index<3> newIdx; for (int x=0; x<2; x++) { frac_x = 1-frac_x; for (int y=0; y<2; y++) { frac_y = 1-frac_y; for (int z=0; z<2; z++) { frac_z = 1-frac_z; newIdx[0] = idx[0]+x; newIdx[1] = idx[1]+y; newIdx[2] = idx[2]+z; double frac = frac_x*frac_y*frac_z; // is position valid? if (!m_TissueMask->GetLargestPossibleRegion().IsInside(newIdx) || m_TissueMask->GetPixel(newIdx)<=0) continue; // generate signal for each fiber compartment for (int k=0; kSetFiberDirection(dir); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(newIdx); pix += segmentVolume*frac*m_FiberModels[k]->SimulateMeasurement(); doubleDwi->SetPixel(newIdx, pix ); if (pix[baselineIndex]>maxVolume) maxVolume = pix[baselineIndex]; } } } } } } MITK_INFO << "Generating signal of " << m_NonFiberModels.size() << " non-fiber compartments"; ImageRegionIterator it3(m_TissueMask, m_TissueMask->GetLargestPossibleRegion()); boost::progress_display disp3(m_TissueMask->GetLargestPossibleRegion().GetNumberOfPixels()); double voxelVolume = m_UpsampledSpacing[0]*m_UpsampledSpacing[1]*m_UpsampledSpacing[2]; double fact = 1; if (m_FiberRadius<0.0001) fact = voxelVolume/maxVolume; while(!it3.IsAtEnd()) { ++disp3; DoubleDwiType::IndexType index = it3.GetIndex(); if (it3.Get()>0) { // get fiber volume fraction DoubleDwiType::Pointer fiberDwi = compartments.at(0); DoubleDwiType::PixelType fiberPix = fiberDwi->GetPixel(index); // intra axonal compartment if (fact>1) // auto scale intra-axonal if no fiber radius is specified { fiberPix *= fact; fiberDwi->SetPixel(index, fiberPix); } double f = fiberPix[baselineIndex]; if (f>voxelVolume || f>0 && m_EnforcePureFiberVoxels) // more fiber than space in voxel? { fiberDwi->SetPixel(index, fiberPix*voxelVolume/f); for (int i=1; iSetPixel(index, pix); } } else { double nonf = voxelVolume-f; // non-fiber volume double inter = 0; if (m_FiberModels.size()>1) inter = nonf * f; // intra-axonal fraction of non fiber compartment scales linearly with f double other = nonf - inter; // rest of compartment // adjust non-fiber and intra-axonal signal for (int i=1; iGetPixel(index); if (pix[baselineIndex]>0) pix /= pix[baselineIndex]; pix *= inter; doubleDwi->SetPixel(index, pix); } for (int i=0; iGetPixel(index) + m_NonFiberModels[i]->SimulateMeasurement()*other*m_NonFiberModels[i]->GetWeight(); doubleDwi->SetPixel(index, pix); } } } ++it3; } // do k-space stuff MITK_INFO << "Adjusting complex signal"; - compartments = AddKspaceArtifacts(compartments); + compartments = DoKspaceStuff(compartments); MITK_INFO << "Summing compartments and adding noise"; unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (outImage, outImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_FiberModels[0]->GetNumGradients()); boost::progress_display disp4(outImage->GetLargestPossibleRegion().GetNumberOfPixels()); while(!it4.IsAtEnd()) { ++disp4; DWIImageType::IndexType index = it4.GetIndex(); signal.Fill(0.0); // adjust fiber signal for (int i=0; iGetPixel(index)*m_SignalScale; // adjust non-fiber signal for (int i=0; iGetPixel(index)*m_SignalScale; DoubleDwiType::PixelType accu = signal; accu.Fill(0.0); for (int i=0; iAddNoise(temp); accu += temp; } signal = accu/m_NumberOfRepetitions; for (int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]>window) window = signal[i]; if (!m_FiberModels.at(0)->IsBaselineIndex(i) && signal[i]SetNthOutput(0, outImage); } itk::Point TractsToDWIImageFilter::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } itk::Vector TractsToDWIImageFilter::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } vnl_vector_fixed TractsToDWIImageFilter::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h index 27044e66da..b629c37fff 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToDWIImageFilter.h @@ -1,132 +1,138 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ // MITK #include #include #include #include #include #include // ITK #include #include #include #include #include #include typedef itk::VectorImage< short, 3 > DWIImageType; namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. */ class TractsToDWIImageFilter : public ImageSource< DWIImageType > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< DWIImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundleX::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef std::vector< mitk::KspaceArtifact* > KspaceArtifactList; typedef std::vector< mitk::DiffusionSignalModel* > DiffusionModelList; typedef itk::Matrix MatrixType; typedef mitk::DiffusionNoiseModel NoiseModelType; typedef itk::Image< double, 2 > SliceType; typedef itk::FFTRealToComplexConjugateImageFilter< double, 2 >::OutputImageType ComplexSliceType; itkNewMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageToImageFilter ) // input itkSetMacro( SignalScale, double ) itkSetMacro( FiberRadius, double ) itkSetMacro( InterpolationShrink, double ) ///< large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation) itkSetMacro( VolumeAccuracy, unsigned int ) ///< determines fiber sampling density and thereby the accuracy of the fiber volume fraction itkSetMacro( FiberBundle, FiberBundleType ) ///< input fiber bundle itkSetMacro( Spacing, mitk::Vector3D ) ///< output image spacing itkSetMacro( Origin, mitk::Point3D ) ///< output image origin itkSetMacro( DirectionMatrix, MatrixType ) ///< output image rotation itkSetMacro( EnforcePureFiberVoxels, bool ) ///< treat all voxels containing at least one fiber as fiber-only (actually disable non-fiber compartments for this voxel). itkSetMacro( ImageRegion, ImageRegion<3> ) ///< output image size itkSetMacro( NumberOfRepetitions, unsigned int ) ///< number of acquisition repetitions to reduce noise (default is no additional repetition) itkSetMacro( TissueMask, ItkUcharImgType::Pointer ) ///< voxels outside of this binary mask contain only noise (are treated as air) itkGetMacro( KspaceImage, ItkDoubleImgType::Pointer ) void SetNoiseModel(NoiseModelType* noiseModel){ m_NoiseModel = noiseModel; } ///< generates the noise added to the image values void SetFiberModels(DiffusionModelList modelList){ m_FiberModels = modelList; } ///< generate signal of fiber compartments void SetNonFiberModels(DiffusionModelList modelList){ m_NonFiberModels = modelList; } ///< generate signal of non-fiber compartments void SetKspaceArtifacts(KspaceArtifactList artifactList){ m_KspaceArtifacts = artifactList; } mitk::LevelWindow GetLevelWindow(){ return m_LevelWindow; } + itkSetMacro( FrequencyMap, ItkDoubleImgType::Pointer ) + itkSetMacro( kOffset, double ) + itkSetMacro( tLine, double ) void GenerateData(); protected: TractsToDWIImageFilter(); virtual ~TractsToDWIImageFilter(); itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); /** Transform generated image compartment by compartment, channel by channel and slice by slice using FFT and add k-space artifacts. */ - std::vector< DoubleDwiType::Pointer > AddKspaceArtifacts(std::vector< DoubleDwiType::Pointer >& images); + std::vector< DoubleDwiType::Pointer > DoKspaceStuff(std::vector< DoubleDwiType::Pointer >& images); /** Rearrange FFT output to shift low frequencies to the iamge center (correct itk). */ TractsToDWIImageFilter::ComplexSliceType::Pointer RearrangeSlice(ComplexSliceType::Pointer slice); mitk::Vector3D m_Spacing; ///< output image spacing mitk::Vector3D m_UpsampledSpacing; mitk::Point3D m_Origin; ///< output image origin MatrixType m_DirectionMatrix; ///< output image rotation ImageRegion<3> m_ImageRegion; ///< output image size ImageRegion<3> m_UpsampledImageRegion; ItkUcharImgType::Pointer m_TissueMask; ///< voxels outside of this binary mask contain only noise (are treated as air) + ItkDoubleImgType::Pointer m_FrequencyMap; ///< map of the B0 inhomogeneities + double m_kOffset; + double m_tLine; FiberBundleType m_FiberBundle; ///< input fiber bundle DiffusionModelList m_FiberModels; ///< generate signal of fiber compartments DiffusionModelList m_NonFiberModels; ///< generate signal of non-fiber compartments KspaceArtifactList m_KspaceArtifacts; NoiseModelType* m_NoiseModel; ///< generates the noise added to the image values bool m_CircleDummy; unsigned int m_VolumeAccuracy; ItkDoubleImgType::Pointer m_KspaceImage; unsigned int m_Upsampling; unsigned int m_NumberOfRepetitions; bool m_EnforcePureFiberVoxels; double m_InterpolationShrink; double m_FiberRadius; double m_SignalScale; mitk::LevelWindow m_LevelWindow; }; } #include "itkTractsToDWIImageFilter.cpp" #endif diff --git a/Modules/DiffusionImaging/FiberTracking/files.cmake b/Modules/DiffusionImaging/FiberTracking/files.cmake index dec7c0be87..11ae2bcac7 100644 --- a/Modules/DiffusionImaging/FiberTracking/files.cmake +++ b/Modules/DiffusionImaging/FiberTracking/files.cmake @@ -1,100 +1,102 @@ set(CPP_FILES # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriter.cpp IODataStructures/FiberBundleX/mitkFiberBundleXReader.cpp IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.cpp IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.cpp IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.cpp # DataStructures -> PlanarFigureComposite IODataStructures/PlanarFigureComposite/mitkPlanarFigureComposite.cpp # DataStructures IODataStructures/mitkFiberTrackingObjectFactory.cpp # Rendering Rendering/mitkFiberBundleXMapper2D.cpp Rendering/mitkFiberBundleXMapper3D.cpp Rendering/mitkFiberBundleXThreadMonitorMapper3D.cpp #Rendering/mitkPlanarFigureMapper3D.cpp # Interactions Interactions/mitkFiberBundleInteractor.cpp # Algorithms Algorithms/mitkTractAnalyzer.cpp # Tractography Algorithms/GibbsTracking/mitkParticleGrid.cpp Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.cpp Algorithms/GibbsTracking/mitkEnergyComputer.cpp Algorithms/GibbsTracking/mitkGibbsEnergyComputer.cpp Algorithms/GibbsTracking/mitkFiberBuilder.cpp Algorithms/GibbsTracking/mitkSphereInterpolator.cpp ) set(H_FILES # Rendering Rendering/mitkFiberBundleXMapper3D.h Rendering/mitkFiberBundleXMapper2D.h Rendering/mitkFiberBundleXThreadMonitorMapper3D.h #Rendering/mitkPlanarFigureMapper3D.h # DataStructures -> FiberBundleX IODataStructures/FiberBundleX/mitkFiberBundleX.h IODataStructures/FiberBundleX/mitkFiberBundleXWriter.h IODataStructures/FiberBundleX/mitkFiberBundleXReader.h IODataStructures/FiberBundleX/mitkFiberBundleXIOFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXWriterFactory.h IODataStructures/FiberBundleX/mitkFiberBundleXSerializer.h IODataStructures/FiberBundleX/mitkFiberBundleXThreadMonitor.h IODataStructures/mitkFiberTrackingObjectFactory.h # Algorithms Algorithms/itkTractDensityImageFilter.h Algorithms/itkTractsToFiberEndingsImageFilter.h Algorithms/itkTractsToRgbaImageFilter.h Algorithms/itkElectrostaticRepulsionDiffusionGradientReductionFilter.h Algorithms/itkFibersFromPlanarFiguresFilter.h Algorithms/itkTractsToDWIImageFilter.h Algorithms/itkTractsToVectorImageFilter.h + Algorithms/itkKspaceImageFilter.h + Algorithms/itkDftImageFilter.h # (old) Tractography Algorithms/itkGibbsTrackingFilter.h Algorithms/itkStochasticTractographyFilter.h Algorithms/itkStreamlineTrackingFilter.h Algorithms/GibbsTracking/mitkParticle.h Algorithms/GibbsTracking/mitkParticleGrid.h Algorithms/GibbsTracking/mitkMetropolisHastingsSampler.h Algorithms/GibbsTracking/mitkSimpSamp.h Algorithms/GibbsTracking/mitkEnergyComputer.h Algorithms/GibbsTracking/mitkGibbsEnergyComputer.h Algorithms/GibbsTracking/mitkSphereInterpolator.h Algorithms/GibbsTracking/mitkFiberBuilder.h # Signal Models SignalModels/mitkDiffusionSignalModel.h SignalModels/mitkTensorModel.h SignalModels/mitkBallModel.h SignalModels/mitkDotModel.h SignalModels/mitkAstroStickModel.h SignalModels/mitkStickModel.h SignalModels/mitkDiffusionNoiseModel.h SignalModels/mitkRicianNoiseModel.h SignalModels/mitkKspaceArtifact.h SignalModels/mitkGibbsRingingArtifact.h SignalModels/mitkSignalDecay.h ) set(RESOURCE_FILES # Binary directory resources FiberTrackingLUTBaryCoords.bin FiberTrackingLUTIndices.bin # Shaders Shaders/mitkShaderFiberClipping.xml ) diff --git a/Modules/GraphAlgorithms/files.cmake b/Modules/GraphAlgorithms/files.cmake index 0de34bc90f..433112a1c8 100644 --- a/Modules/GraphAlgorithms/files.cmake +++ b/Modules/GraphAlgorithms/files.cmake @@ -1,9 +1,10 @@ set(CPP_FILES itkShortestPathNode.cpp ) set(H_FILES itkShortestPathCostFunction.h itkShortestPathCostFunctionTbss.h itkShortestPathNode.h itkShortestPathImageFilter.h + itkShortestPathCostFunctionLiveWire.h ) diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h new file mode 100644 index 0000000000..033c92951c --- /dev/null +++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.h @@ -0,0 +1,204 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __itkShortestPathCostFunctionLiveWire_h +#define __itkShortestPathCostFunctionLiveWire_h + +#include "itkObject.h" +#include "itkObjectFactory.h" +#include "itkShortestPathCostFunction.h" // Superclass of Metrics + +#include + + + + +namespace itk +{ + /** \brief Cost function for LiveWire purposes. + Specific features are considered to calculate cummulative + costs of a link between two pixels. These are: + + - Gradient Magnitude + - Gradient Direction + - Laplacian Zero Crossing + + By default the Gradient Magnitude is mapped linear to costs + between 0 (good) and 1 (bad). Via SetDynamicCostMap( std::map< int, int > &costMap) + a cost map can be set to dynamically map Gradient Magnitude (non + linear). Thus lower values can be considered with lower costs + than higher values of gradient magnitudes. + To compute the costs of the gradient magnitude dynamically + a iverted map of the histogram of gradient magnitude image is used. + + */ + template + class ITK_EXPORT ShortestPathCostFunctionLiveWire : public ShortestPathCostFunction + { + public: + /** Standard class typedefs. */ + typedef ShortestPathCostFunctionLiveWire Self; + typedef ShortestPathCostFunction Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + typedef itk::ImageRegionConstIterator ConstIteratorType; + + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(ShortestPathCostFunctionLiveWire, ShortestPathCostFunction); + + + typedef itk::Image UnsignedCharImageType; + typedef itk::Image FloatImageType; + + typedef float ComponentType; + typedef itk::CovariantVector< ComponentType, 2 > OutputPixelType; + typedef itk::Image< OutputPixelType, 2 > VectorOutputImageType; + + typedef typename TInputImageType::IndexType IndexType; + typedef TInputImageType ImageType; + typedef itk::ImageRegion<2> RegionType; + + + + /** \brief calculates the costs for going from p1 to p2*/ + virtual double GetCost(IndexType p1, IndexType p2); + + /** \brief returns the minimal costs possible (needed for A*)*/ + virtual double GetMinCost(); + + /** \brief Initialize the metric*/ + virtual void Initialize (); + + + /** \brief Set repulsive path*/ + virtual void AddRepulsivePoint( itk::Index<3> ); + + /** \brief Clear repulsive path*/ + virtual void ClearRepulsivePoints( ); + + + + ShortestPathCostFunctionLiveWire(); + + + itkSetMacro (RequestedRegion, RegionType); + itkGetMacro (RequestedRegion, RegionType); + + // Set/Get function for sigma parameter + itkSetMacro (UseApproximateGradient, bool); + itkGetMacro (UseApproximateGradient, bool); + + virtual void SetImage(const TInputImageType* _arg) + { + if (this->m_Image != _arg) + { + this->m_Image = _arg; + this->Modified(); + this->m_Initialized = false; + } + } + + void SetDynamicCostMap( std::map< int, int > &costMap) + { + this->m_CostMap = costMap; + this->m_UseCostMap = true; + this->m_MaxMapCosts = -1; + this->Modified(); + } + + void SetUseCostMap(bool useCostMap) + { + this->m_UseCostMap = useCostMap; + } + + /** + \brief Set the maximum of the dynamic cost map to save computation time. + */ + void SetCostMapMaximum(double max) + { + this->m_MaxMapCosts = max; + } + + + enum Constants{ + MAPSCALEFACTOR = 10 + }; + + /** \brief Returns the y value of gaussian with given offset and amplitude + + gaussian approximation + f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 ) + + \param x + \param xOfGaussian - offset + \param yOfGaussian - amplitude + */ + static double Gaussian(double x, double xOfGaussian, double yOfGaussian); + + protected: + + virtual ~ShortestPathCostFunctionLiveWire() {}; + + + typename ImageType::Pointer m_GradientMagnImage; + typename UnsignedCharImageType::Pointer m_ZeroCrossingsImage; + typename FloatImageType::Pointer m_EdgeImage; + typename VectorOutputImageType::Pointer m_GradientImage; + + double minCosts; + + bool m_UseRepulsivePoint; + + std::vector< itk::Index<3> > m_RepulsivePoints; + + typename Superclass::PixelType val; + + typename Superclass::PixelType startValue; + typename Superclass::PixelType endValue; + + double m_GradientMax; + + RegionType m_RequestedRegion; + + bool m_UseApproximateGradient; + + bool m_Initialized; + + std::map< int, int > m_CostMap; + + bool m_UseCostMap; + + double m_MaxMapCosts; + + private: + + double SigmoidFunction(double I, double max, double min, double alpha, double beta); + + + }; + +} // end namespace itk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkShortestPathCostFunctionLiveWire.txx" +#endif + +#endif /* __itkShortestPathCostFunctionLiveWire_h */ diff --git a/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx new file mode 100644 index 0000000000..a9ad943a75 --- /dev/null +++ b/Modules/GraphAlgorithms/itkShortestPathCostFunctionLiveWire.txx @@ -0,0 +1,441 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __itkShortestPathCostFunctionLiveWire_txx +#define __itkShortestPathCostFunctionLiveWire_txx + +#include "itkShortestPathCostFunctionLiveWire.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace itk +{ + + // Constructor + template + ShortestPathCostFunctionLiveWire + ::ShortestPathCostFunctionLiveWire() + { + m_UseRepulsivePoint = false; + m_GradientMax = 0.0; + m_Initialized = false; + m_UseCostMap = false; + m_MaxMapCosts = -1.0; + } + + + + template + void ShortestPathCostFunctionLiveWire + ::AddRepulsivePoint( itk::Index<3> c ) + { + m_RepulsivePoints.push_back(c); + m_UseRepulsivePoint = true; + } + + + + template + void ShortestPathCostFunctionLiveWire + ::ClearRepulsivePoints() + { + m_RepulsivePoints.clear(); + m_UseRepulsivePoint = false; + } + + + + template + double ShortestPathCostFunctionLiveWire + ::GetCost(IndexType p1 ,IndexType p2) + { + + unsigned long xMAX = this->m_Image->GetLargestPossibleRegion().GetSize()[0]; + unsigned long yMAX = this->m_Image->GetLargestPossibleRegion().GetSize()[1]; + + double gradientX, gradientY; + gradientX = gradientY = 0.0; + + double gradientCost; + + double gradientMagnitude; + + /* ++++++++++++++++++++ GradientMagnitude costs ++++++++++++++++++++++++++*/ + + gradientMagnitude = this->m_GradientMagnImage->GetPixel(p2); + gradientX = m_GradientImage->GetPixel(p2)[0]; + gradientY = m_GradientImage->GetPixel(p2)[1]; + + + + if(m_UseCostMap && !m_CostMap.empty()) + { + std::map< int, int >::iterator end = m_CostMap.end(); + std::map< int, int >::iterator last = --(m_CostMap.end()); + + //current position + std::map< int, int >::iterator x; + //std::map< int, int >::key_type keyOfX = static_cast::key_type>(gradientMagnitude * 1000); + int keyOfX = static_cast(gradientMagnitude /* ShortestPathCostFunctionLiveWire::MAPSCALEFACTOR*/); + x = m_CostMap.find( keyOfX ); + + std::map< int, int >::iterator left2; + std::map< int, int >::iterator left1; + std::map< int, int >::iterator right1; + std::map< int, int >::iterator right2; + + if( x == end ) + {//x can also be == end if the key is not in the map but between two other keys + //search next key within map from x upwards + right1 = m_CostMap.lower_bound( keyOfX ); + } + else + { + right1 = x; + } + + if(right1 == end || right1 == last ) + { + right2 = end; + } + else//( right1 != (end-1) ) + { + std::map< int, int >::iterator temp = right1; + right2 = ++right1;//rght1 + 1 + right1 = temp; + } + + + if( right1 == m_CostMap.begin() ) + { + left1 = end; + left2 = end; + } + else if( right1 == (++(m_CostMap.begin())) ) + { + std::map< int, int >::iterator temp = right1; + left1 = --right1;//rght1 - 1 + right1 = temp; + left2 = end; + } + else + { + std::map< int, int >::iterator temp = right1; + left1 = --right1;//rght1 - 1 + left2 = --right1;//rght1 - 2 + right1 = temp; + } + + double partRight1, partRight2, partLeft1, partLeft2; + partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0; + + + /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 ) + + gaussian approximation + + where + v(bin) is the value in the map + k(bin) is the key + */ + if( left2 != end ) + { + partLeft2 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left2->first, left2->second); + } + + if( left1 != end ) + { + partLeft1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, left1->first, left1->second); + } + + if( right1 != end ) + { + partRight1 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right1->first, right1->second); + } + + if( right2 != end ) + { + partRight2 = ShortestPathCostFunctionLiveWire::Gaussian(keyOfX, right2->first, right2->second); + } + /*----------------------------------------------------------------------------*/ + + + if( m_MaxMapCosts > 0.0 ) + { + gradientCost = 1.0 - ( (partRight1 + partRight2 + partLeft1 + partLeft2) / m_MaxMapCosts ); + } + else + {//use linear mapping + gradientCost = 1.0 - (gradientMagnitude / m_GradientMax); + } + + } + else + {//use linear mapping + //value between 0 (good) and 1 (bad) + gradientCost = 1.0 - (gradientMagnitude / m_GradientMax); + + } + /* -----------------------------------------------------------------------------*/ + + + + /* ++++++++++++++++++++ Laplacian zero crossing costs ++++++++++++++++++++++++++*/ + // f(p) = 0; if I(p)=0 + // or 1; if I(p)!=0 + double laplacianCost; + typename Superclass::PixelType laplaceImageValue; + + + laplaceImageValue = m_EdgeImage->GetPixel(p2); + + if(laplaceImageValue < 0 || laplaceImageValue > 0) + { + laplacianCost = 1.0; + } + else + { + laplacianCost = 0.0; + } + + /* -----------------------------------------------------------------------------*/ + + + + /* ++++++++++++++++++++ Gradient direction costs ++++++++++++++++++++++++++*/ + //vector q-p i.e. p2-p1 + double vQP[2]; + vQP[0] = p2[0] - p1[0]; + vQP[1] = p2[1] - p1[1]; + //------- + + //vector p-q i.e. p1-p2 + double vPQ[2]; + vPQ[0] = p1[0] - p2[0]; + vPQ[1] = p1[1] - p2[1]; + //------- + + // gradient vector at p1 + double nGradientAtP1[2]; + nGradientAtP1[0] = gradientX;//previously computed for gradient magnitude + nGradientAtP1[1] = gradientY; + + //gradient direction unit vector of p1 + nGradientAtP1[0] /= gradientMagnitude; + nGradientAtP1[1] /= gradientMagnitude; + //------- + + // gradient vector at p1 + double nGradientAtP2[2]; + + + nGradientAtP2[0] = m_GradientImage->GetPixel(p2)[0]; + nGradientAtP2[1] = m_GradientImage->GetPixel(p2)[1]; + + nGradientAtP2[0] /= m_GradientMagnImage->GetPixel(p2); + nGradientAtP2[1] /= m_GradientMagnImage->GetPixel(p2); + + + double scalarProduct = (nGradientAtP1[0] * nGradientAtP2[0]) + (nGradientAtP1[1] * nGradientAtP2[1]); + if( abs(scalarProduct) >= 1.0) + { + //this should probably not happen; make sure the input for acos is valid + scalarProduct = 0.999999999; + } + + double gradientDirectionCost = acos( scalarProduct ) / 3.14159265; + /*------------------------------------------------------------------------*/ + + + + + /*+++++++++++++++++++++ local component costs +++++++++++++++++++++++++++*/ + /*weights*/ + double w1; + double w2; + double w3; + double costs = 0.0; + + if (this->m_UseCostMap){ + w1 = 0.43; + w2= 0.43; + w3 = 0.14; + }else{ + w1 = 0.10; + w2= 0.85; + w3 = 0.05; + } + costs = w1 * laplacianCost + w2 * gradientCost + w3 * gradientDirectionCost; + + + //scale by euclidian distance + double costScale; + if( p1[0] == p2[0] || p1[1] == p2[1]) + { + //horizontal or vertical neighbor + costScale = 1.0; + } + else + { + //diagonal neighbor + costScale = sqrt(2.0); + } + + costs *= costScale; + + return costs; + } + + + + template + double ShortestPathCostFunctionLiveWire + ::GetMinCost() + { + return minCosts; + } + + + + template + void ShortestPathCostFunctionLiveWire + ::Initialize() + { + if(!m_Initialized) + { + + + typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType; + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(this->m_Image); + + + // init gradient magnitude image + typedef itk::GradientMagnitudeImageFilter< FloatImageType, FloatImageType> GradientMagnitudeFilterType; + typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); + gradientFilter->SetInput(castFilter->GetOutput()); + //gradientFilter->SetNumberOfThreads(4); + //gradientFilter->GetOutput()->SetRequestedRegion(m_RequestedRegion); + + gradientFilter->Update(); + m_GradientMagnImage = gradientFilter->GetOutput(); + + typedef itk::StatisticsImageFilter StatisticsImageFilterType; + typename StatisticsImageFilterType::Pointer statisticsImageFilter = StatisticsImageFilterType::New(); + statisticsImageFilter->SetInput(this->m_GradientMagnImage); + statisticsImageFilter->Update(); + + m_GradientMax = statisticsImageFilter->GetMaximum(); + + + + //Filter class is instantiated + /*typedef itk::GradientRecursiveGaussianImageFilter GradientFilterType;*/ + + typedef itk::GradientImageFilter< FloatImageType > GradientFilterType; + + typename GradientFilterType::Pointer filter = GradientFilterType::New(); + //sigma is specified in millimeters + //filter->SetSigma( 1.5 ); + filter->SetInput(castFilter->GetOutput()); + filter->Update(); + + m_GradientImage = filter->GetOutput(); + + + // init zero crossings + //typedef itk::ZeroCrossingImageFilter< TInputImageType, UnsignedCharImageType > ZeroCrossingImageFilterType; + //ZeroCrossingImageFilterType::Pointer zeroCrossingImageFilter = ZeroCrossingImageFilterType::New(); + //zeroCrossingImageFilter->SetInput(this->m_Image); + //zeroCrossingImageFilter->SetBackgroundValue(1); + //zeroCrossingImageFilter->SetForegroundValue(0); + //zeroCrossingImageFilter->SetNumberOfThreads(4); + //zeroCrossingImageFilter->Update(); + + //m_EdgeImage = zeroCrossingImageFilter->GetOutput(); + + + //cast image to float to apply canny edge dection filter + /*typedef itk::CastImageFilter< TInputImageType, FloatImageType > CastFilterType; + CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(this->m_Image);*/ + + //typedef itk::LaplacianImageFilter filterType; + //filterType::Pointer laplacianFilter = filterType::New(); + //laplacianFilter->SetInput( castFilter->GetOutput() ); // NOTE: input image type must be double or float + //laplacianFilter->Update(); + + //m_EdgeImage = laplacianFilter->GetOutput(); + + //init canny edge detection + typedef itk::CannyEdgeDetectionImageFilter CannyEdgeDetectionImageFilterType; + typename CannyEdgeDetectionImageFilterType::Pointer cannyEdgeDetectionfilter = CannyEdgeDetectionImageFilterType::New(); + cannyEdgeDetectionfilter->SetInput(castFilter->GetOutput()); + cannyEdgeDetectionfilter->SetUpperThreshold(30); + cannyEdgeDetectionfilter->SetLowerThreshold(15); + cannyEdgeDetectionfilter->SetVariance(4); + cannyEdgeDetectionfilter->SetMaximumError(.01f); + + cannyEdgeDetectionfilter->Update(); + m_EdgeImage = cannyEdgeDetectionfilter->GetOutput(); + + + // set minCosts + minCosts = 0.0; // The lower, the more thouroughly! 0 = dijkstra. If estimate costs are lower than actual costs everything is fine. If estimation is higher than actual costs, you might not get the shortest but a different path. + + m_Initialized = true; + } + + // check start/end point value + startValue= this->m_Image->GetPixel(this->m_StartIndex); + endValue= this->m_Image->GetPixel(this->m_EndIndex); + } + + + + template + double ShortestPathCostFunctionLiveWire::SigmoidFunction(double I, double max, double min, double alpha, double beta) + { + // Using the SIgmoid formula from ITK Software Guide 6.3.2 Non Linear Mappings + double Exponent = -1 * ((I - beta) / alpha); + double Factor = 1 / (1 + exp(Exponent)); + double newI = (max - min) * Factor + min; + + return newI; + } + + + template + double ShortestPathCostFunctionLiveWire::Gaussian(double x, double xOfGaussian, double yOfGaussian) + { + return yOfGaussian * exp( -0.5 * pow( (x - xOfGaussian), 2) ); + } + +} // end namespace itk + +#endif // __itkShortestPathCostFunctionLiveWire_txx diff --git a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h index c93a0204a3..1a3216a6dc 100644 --- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.h +++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.h @@ -1,225 +1,232 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShortestPathImageFilter_h #define __itkShortestPathImageFilter_h #include "itkImageToImageFilter.h" #include "itkShortestPathCostFunction.h" #include "itkShortestPathNode.h" #include #include // ------- INFORMATION ---------- /// SET FUNCTIONS //void SetInput( ItkImage ) // Compulsory //void SetStartIndex (const IndexType & StartIndex); // Compulsory //void SetEndIndex(const IndexType & EndIndex); // Compulsory //void SetFullNeighborsMode(bool) // Optional (default=false), if false N4, if true N26 //void SetActivateTimeOut(bool) // Optional (default=false), for debug issues: after 30s algorithms terminates. You can have a look at the VectorOrderImage to see how far it came //void SetMakeOutputImage(bool) // Optional (default=true), Generate an outputimage of the path. You can also get the path directoy with GetVectorPath() //void SetCalcAllDistances(bool) // Optional (default=false), Calculate Distances over the whole image. CAREFUL, algorithm time extends a lot. Necessary for GetDistanceImage //void SetStoreVectorOrder(bool) // Optional (default=false), Stores in which order the pixels were checked. Necessary for GetVectorOrderImage //void AddEndIndex(const IndexType & EndIndex) //Optional. By calling this function you can add several endpoints! The algorithm will look for several shortest Pathes. From Start to all Endpoints. // /// GET FUNCTIONS //std::vector< itk::Index<3> > GetVectorPath(); // returns the shortest path as vector //std::vector< std::vector< itk::Index<3> > GetMultipleVectorPathe(); // returns a vector of shortest Pathes (which are vectors of points) //GetDistanceImage // Returns the distance image //GetVectorOrderIMage // Returns the Vector Order image // // EXAMPLE USE // pleae see qmitkmitralvalvesegmentation4dtee bundle namespace itk { template class ShortestPathImageFilter : public ImageToImageFilter { public: //Standard Typedefs typedef ShortestPathImageFilter Self; typedef ImageToImageFilter Superclass; typedef SmartPointer Pointer; typedef SmartPointer ConstPointer; // Typdefs for metric typedef ShortestPathCostFunction< TInputImageType > CostFunctionType; typedef typename CostFunctionType::Pointer CostFunctionTypePointer; // More typdefs for convenience typedef TInputImageType InputImageType; typedef typename TInputImageType::Pointer InputImagePointer; typedef typename TInputImageType::PixelType InputImagePixelType; typedef typename TInputImageType::SizeType InputImageSizeType; typedef typename TInputImageType::IndexType IndexType; typedef typename itk::ImageRegionIteratorWithIndex< InputImageType > InputImageIteratorType; typedef TOutputImageType OutputImageType; typedef typename TOutputImageType::Pointer OutputImagePointer; typedef typename TOutputImageType::PixelType OutputImagePixelType; typedef typename TOutputImageType::IndexType OutputImageIndexType; typedef ImageRegionIteratorWithIndex< OutputImageType > OutputImageIteratorType; typedef itk::ShapedNeighborhoodIterator< TInputImageType > itkShapedNeighborhoodIteratorType; // New Macro for smartpointer instantiation itkNewMacro(Self) // Run-time type information itkTypeMacro(ShortestPathImageFilter, ImageToImageFilter) // Display void PrintSelf( std::ostream& os, Indent indent ) const; // Compare function for A_STAR struct CompareNodeStar { bool operator()(ShortestPathNode *a, ShortestPathNode *b) { return (a->distAndEst > b->distAndEst); } }; // \brief Set Starpoint for ShortestPath Calculation void SetStartIndex (const IndexType & StartIndex); // \brief Adds Endpoint for multiple ShortestPath Calculation void AddEndIndex (const IndexType & index); // \brief Set Endpoint for ShortestPath Calculation void SetEndIndex(const IndexType & EndIndex); // \brief Set FullNeighborsMode. false = no diagonal neighbors, in 2D this means N4 Neigborhood. true = would be N8 in 2D itkSetMacro (FullNeighborsMode, bool); itkGetMacro (FullNeighborsMode, bool); // \brief (default=true), Produce output image, which shows the shortest path. But you can also get the shortest Path directly as vector with the function GetVectorPath itkSetMacro (MakeOutputImage, bool); itkGetMacro (MakeOutputImage, bool); // \brief (default=false), Store an Vector of Order, so you can call getVectorOrderImage after update itkSetMacro (StoreVectorOrder, bool); itkGetMacro (StoreVectorOrder, bool); // \brief (default=false), // Calculate all Distances to all pixels, so you can call getDistanceImage after update (warning algo will take a long time) itkSetMacro (CalcAllDistances, bool); itkGetMacro (CalcAllDistances, bool); // \brief (default=false), for debug issues: after 30s algorithms terminates. You can have a look at the VectorOrderImage to see how far it came itkSetMacro (ActivateTimeOut, bool); itkGetMacro (ActivateTimeOut, bool); // \brief returns shortest Path as vector - std::vector< itk::Index<3> > GetVectorPath(); + std::vector< IndexType > GetVectorPath(); // \brief returns Multiple shortest Paths. You can call this function, when u performed a multiple shortest path search (one start, several ends) - std::vector< std::vector< itk::Index<3> > > GetMultipleVectorPaths(); + std::vector< std::vector< IndexType > > GetMultipleVectorPaths(); // \brief returns the vector order image. It shows in which order the pixels were checked. good for debugging. Be sure to have m_StoreVectorOrder=true OutputImagePointer GetVectorOrderImage(); // \brief returns the distance image. It shows the distances from the startpoint to all other pixels. Be sure to have m_CalcAllDistances=true OutputImagePointer GetDistanceImage(); + + // \brief Fill m_VectorPath + void MakeShortestPathVector(); + // \brief cleans up the filter void CleanUp(); itkSetObjectMacro( CostFunction, CostFunctionType ); // itkSetObjectMacro = set function that uses pointer as parameter itkGetObjectMacro( CostFunction, CostFunctionType ); protected: std::vector< IndexType > m_endPoints; // if you fill this vector, the algo will not rest until all endPoints have been reached std::vector< IndexType > m_endPointsClosed; ShortestPathNode* m_Nodes; // main list that contains all nodes NodeNumType m_Graph_NumberOfNodes; NodeNumType m_Graph_StartNode; NodeNumType m_Graph_EndNode; int m_ImageDimensions; bool m_Graph_fullNeighbors; std::vector m_Graph_DiscoveredNodeList; ShortestPathImageFilter(Self&); // intentionally not implemented void operator=(const Self&); // intentionally not implemented const static int BACKGROUND = 0; const static int FOREGROUND = 255; bool m_FullNeighborsMode; bool m_MakeOutputImage; bool m_StoreVectorOrder; // Store an Vector of Order, so you can call getVectorOrderImage after update bool m_CalcAllDistances; // Calculate all Distances, so you can call getDistanceImage after update (warning algo will take a long time) bool multipleEndPoints; bool m_ActivateTimeOut; // if true, then i search max. 30 secs. then abort + + bool m_Initialized; + + CostFunctionTypePointer m_CostFunction; IndexType m_StartIndex, m_EndIndex; - std::vector< itk::Index<3> > m_VectorPath; - std::vector< std::vector< itk::Index<3> > > m_MultipleVectorPaths; + std::vector< IndexType > m_VectorPath; + std::vector< std::vector< IndexType > > m_MultipleVectorPaths; std::vector< NodeNumType > m_VectorOrder; ShortestPathImageFilter(); - // \brief Fill m_VectorPath - void MakeShortestPathVector(); + ~ShortestPathImageFilter(); // \brief Create all the outputs void MakeOutputs(); // \brief Generate Data void GenerateData(); // \brief gets the estimate costs from pixel a to target. double getEstimatedCostsToTarget(const IndexType & a); typename InputImageType::Pointer m_magnitudeImage; // \brief Convert a indexnumber of a node in m_Nodes to image coordinates typename TInputImageType::IndexType NodeToCoord(NodeNumType); // \brief Convert image coordinate to a indexnumber of a node in m_Nodes unsigned int CoordToNode(IndexType); // \brief Returns the neighbors of a node std::vector GetNeighbors(NodeNumType nodeNum, bool FullNeighbors); // \brief Check if coords are in bounds of image bool CoordIsInBounds(IndexType); // \brief Initializes the graph void InitGraph(); // \brief Start ShortestPathSearch void StartShortestPathSearch(); }; } // end of namespace itk #include "itkShortestPathImageFilter.txx" #endif diff --git a/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx index a255040bfb..933130fe43 100644 --- a/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx +++ b/Modules/GraphAlgorithms/itkShortestPathImageFilter.txx @@ -1,939 +1,951 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __itkShortestPathImageFilter_txx #define __itkShortestPathImageFilter_txx #include "time.h" #include "mitkMemoryUtilities.h" #include #include #include namespace itk { // Constructor (initialize standard values) template ShortestPathImageFilter ::ShortestPathImageFilter() : m_FullNeighborsMode(false), m_MakeOutputImage(true), m_StoreVectorOrder(false), m_CalcAllDistances(false), m_ActivateTimeOut(false), - multipleEndPoints(false), - m_Nodes(0), - m_Graph_NumberOfNodes(0) + multipleEndPoints(false), + m_Initialized(false), + m_Nodes(0), + m_Graph_NumberOfNodes(0) { - m_endPoints.clear(); - m_endPointsClosed.clear(); + m_endPoints.clear(); + m_endPointsClosed.clear(); - if (m_MakeOutputImage) - { - this->SetNumberOfRequiredOutputs(1); - this->SetNthOutput( 0, OutputImageType::New() ); - } + if (m_MakeOutputImage) + { + this->SetNumberOfRequiredOutputs(1); + this->SetNthOutput( 0, OutputImageType::New() ); + } } + + + template + ShortestPathImageFilter + ::~ShortestPathImageFilter() + { + delete [] m_Nodes; + } + + + + template inline typename ShortestPathImageFilter::IndexType ShortestPathImageFilter ::NodeToCoord (NodeNumType node) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; IndexType coord; if (dim == 2) { coord[1] = node / size[0]; coord[0] = node % size[0]; if ((coord[0] >= size[0]) || (coord[1] >= size[1])) { coord[0] = 0; coord[1] = 0; } } if (dim == 3) { coord[2] = node / (size[0]*size[1]); coord[1] = (node % (size[0]*size[1])) / size[0]; coord[0] = (node % (size[0]*size[1])) % size[0]; if ((coord[0] >= size[0]) || (coord[1] >= size[1]) || (coord[2] >= size[2])) { coord[0] = 0; coord[1] = 0; coord[2] = 0; } } return coord; } template inline typename itk::NodeNumType ShortestPathImageFilter:: CoordToNode (IndexType coord) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; NodeNumType node = 0; if (dim == 2) { node = (coord[1]*size[0]) + coord[0]; } if (dim == 3) { node = (coord[2]*size[0]*size[1]) + (coord[1]*size[0]) + coord[0]; } if ((m_Graph_NumberOfNodes > 0) && (node >= m_Graph_NumberOfNodes)) - { - MITK_INFO << "WARNING! Coordinates outside image!"; - MITK_INFO << "Coords = " << coord ; - MITK_INFO << "ImageDim = " << dim ; - MITK_INFO << "RequestedRegionSize = " << size ; + { + /*MITK_INFO << "WARNING! Coordinates outside image!"; + MITK_INFO << "Coords = " << coord ; + MITK_INFO << "ImageDim = " << dim ; + MITK_INFO << "RequestedRegionSize = " << size ;*/ node = 0; - } + } return node; } template inline bool ShortestPathImageFilter:: CoordIsInBounds (IndexType coord) { const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); int dim = InputImageType::ImageDimension; if (dim == 2) { if ((coord[0] >= 0) && (coord[0] < size[0]) && (coord[1] >= 0 ) && (coord[1] < size[1] )) { return true; } } if (dim == 3) { if ((coord[0] >= 0) && (coord[0] < size[0]) && (coord[1] >= 0 ) && (coord[1] < size[1] ) && (coord[2] >= 0 ) && (coord[2] < size[2] )) { return true; } } return false; } template inline std::vector< ShortestPathNode* > ShortestPathImageFilter:: GetNeighbors (unsigned int nodeNum, bool FullNeighbors) { // returns a vector of nodepointers.. these nodes are the neighbors int dim = InputImageType::ImageDimension; IndexType Coord = NodeToCoord(nodeNum); IndexType NeighborCoord; std::vector nodeList; int neighborDistance = 1; //if i increase that, i might not hit the endnote - // maybe use itkNeighborhoodIterator here, might be faster + // maybe use itkNeighborhoodIterator here, might be faster if ( dim == 2) { // N4 NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); if (FullNeighbors) { // N8 NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); } } if ( dim == 3) { // N6 NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); if (FullNeighbors) { // N26 // Middle Slice NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); // BackSlice (Diagonal) NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); //BackSlice (Non-Diag) NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]-neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); // FrontSlice (Diagonal) NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); //FrontSlice(Non-Diag) NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]-neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]+neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]; NeighborCoord[1] = Coord[1]+neighborDistance; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); NeighborCoord[0] = Coord[0]-neighborDistance; NeighborCoord[1] = Coord[1]; NeighborCoord[2] = Coord[2]+neighborDistance; if (CoordIsInBounds(NeighborCoord)) nodeList.push_back(&m_Nodes[CoordToNode(NeighborCoord)]); } } return nodeList; } template void ShortestPathImageFilter:: SetStartIndex (const typename TInputImageType::IndexType &StartIndex) { for (unsigned int i=0;i v; + itk::Vector v; v[0] = m_EndIndex[0]-a[0]; v[1] = m_EndIndex[1]-a[1]; v[2] = m_EndIndex[2]-a[2]; - return m_CostFunction->GetMinCost() * v.GetNorm(); + return m_CostFunction->GetMinCost() * v.GetNorm(); } template void ShortestPathImageFilter:: InitGraph() { - // Clean up previous stuff - CleanUp(); + if(!m_Initialized) + { + // Clean up previous stuff + CleanUp(); - // initalize cost function - m_CostFunction->Initialize(); + // Calc Number of nodes + m_ImageDimensions = TInputImageType::ImageDimension; + const InputImageSizeType &size = this->GetInput()->GetRequestedRegion().GetSize(); + m_Graph_NumberOfNodes = 1; + for (NodeNumType i=0; iGetInput()->GetRequestedRegion().GetSize(); - m_Graph_NumberOfNodes = 1; - for (NodeNumType i=0; iInitialize(); } template void ShortestPathImageFilter:: StartShortestPathSearch() { - // Setup Timer + // Setup Timer clock_t startAll = clock(); clock_t stopAll = clock(); - // init variables + // init variables double durationAll = 0; bool timeout = false; bool makeNewHeapNecessary = false; - NodeNumType mainNodeListIndex = 0; + NodeNumType mainNodeListIndex = 0; DistanceType curNodeDistance = 0; DistanceType curNodeDistAndEst = 0; - NodeNumType numberOfNodesChecked = 0; + NodeNumType numberOfNodesChecked = 0; - // Create Multimap (tree structure for fast searching) - std::multimap myMap; - std::pair< std::multimap::iterator, std::multimap::iterator> ret; - std::multimap::iterator it; + // Create Multimap (tree structure for fast searching) + std::multimap myMap; + std::pair< std::multimap::iterator, std::multimap::iterator> ret; + std::multimap::iterator it; - // At first, only startNote is discovered. - myMap.insert( std::pair (m_Nodes[m_Graph_StartNode].distAndEst, &m_Nodes[m_Graph_StartNode]) ); + // At first, only startNote is discovered. + myMap.insert( std::pair (m_Nodes[m_Graph_StartNode].distAndEst, &m_Nodes[m_Graph_StartNode]) ); // While there are discovered Nodes, pick the one with lowest distance, - // update its neighbors and eventually delete it from the discovered Nodes list. + // update its neighbors and eventually delete it from the discovered Nodes list. while(!myMap.empty()) { - numberOfNodesChecked++; - if ( (numberOfNodesChecked % (m_Graph_NumberOfNodes/100)) == 0) - { - MITK_INFO << "Checked " << ( numberOfNodesChecked / (m_Graph_NumberOfNodes/100) ) << "% List: " << myMap.size() << "\n"; - } - - // Get element with lowest score - mainNodeListIndex = myMap.begin()->second->mainListIndex; + numberOfNodesChecked++; + /*if ( (numberOfNodesChecked % (m_Graph_NumberOfNodes/100)) == 0) + { + MITK_INFO << "Checked " << ( numberOfNodesChecked / (m_Graph_NumberOfNodes/100) ) << "% List: " << myMap.size() << "\n"; + }*/ + + // Get element with lowest score + mainNodeListIndex = myMap.begin()->second->mainListIndex; curNodeDistAndEst = myMap.begin()->second->distAndEst; curNodeDistance = myMap.begin()->second->distance; - myMap.begin()->second->closed = true; // close it + myMap.begin()->second->closed = true; // close it - // Debug: - //MITK_INFO << "INFO: size " << myMap.size(); - /* - for (it = myMap.begin(); it != myMap.end(); ++it) - { - MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; - } - */ + // Debug: + //MITK_INFO << "INFO: size " << myMap.size(); + /* + for (it = myMap.begin(); it != myMap.end(); ++it) + { + MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; + } + */ // Kicks out element with lowest score - myMap.erase( myMap.begin() ); + myMap.erase( myMap.begin() ); - // if wanted, store vector order + // if wanted, store vector order if (m_StoreVectorOrder) - { + { m_VectorOrder.push_back(mainNodeListIndex); - } + } // Check neighbors std::vector neighborNodes = GetNeighbors(mainNodeListIndex, m_Graph_fullNeighbors); for (NodeNumType i=0; iclosed) - continue; // this nodes is already closed, go to next neighbor + if (neighborNodes[i]->closed) + continue; // this nodes is already closed, go to next neighbor IndexType coordCurNode = NodeToCoord(mainNodeListIndex); IndexType coordNeighborNode = NodeToCoord(neighborNodes[i]->mainListIndex); // calculate the new Distance to the current neighbor double newDistance = curNodeDistance + (m_CostFunction->GetCost(coordCurNode, coordNeighborNode)); // if it is shorter than any yet known path to this neighbor, than the current path is better. Save that! if ((newDistance < neighborNodes[i]->distance) || (neighborNodes[i]->distance == -1) ) { // if that neighbornode is not in discoverednodeList yet, Push it there and update if (neighborNodes[i]->distance == -1) { neighborNodes[i]->distance = newDistance; neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode); neighborNodes[i]->prevNode = mainNodeListIndex; - myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); - /* - MITK_INFO << "Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; - MITK_INFO << "INFO: size " << myMap.size(); - for (it = myMap.begin(); it != myMap.end(); ++it) - { - MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; - } - */ + myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); + /* + MITK_INFO << "Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; + MITK_INFO << "INFO: size " << myMap.size(); + for (it = myMap.begin(); it != myMap.end(); ++it) + { + MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; + } + */ } // or if is already in discoverednodelist, update else { - /* - it = myMap.find(neighborNodes[i]->distAndEst); - if (it == myMap.end() ) - { - MITK_INFO << "Nothing!"; - // look further - for (it = myMap.begin(); it != myMap.end(); ++it) - { - if ((*it).second->mainListIndex == lookForId) - { - MITK_INFO << "But it is there!!!"; - MITK_INFO << "Searched for: " << lookFor << " but had: " << (*it).second->distAndEst; - } - - } - } - */ + /* + it = myMap.find(neighborNodes[i]->distAndEst); + if (it == myMap.end() ) + { + MITK_INFO << "Nothing!"; + // look further + for (it = myMap.begin(); it != myMap.end(); ++it) + { + if ((*it).second->mainListIndex == lookForId) + { + MITK_INFO << "But it is there!!!"; + MITK_INFO << "Searched for: " << lookFor << " but had: " << (*it).second->distAndEst; + } - // 1st : find and delete old element - bool found = false; - double lookFor = neighborNodes[i]->distAndEst; - unsigned int lookForId = neighborNodes[i]->mainListIndex; - ret = myMap.equal_range(neighborNodes[i]->distAndEst); + } + } + */ - if ((ret.first == ret.second)) - { - MITK_INFO << "No exact match!"; // if this happens, you are screwed - /* - MITK_INFO << "Was looking for: " << lookFor << " ID: " << lookForId; - if (ret.first != myMap.end() ) - { - it = ret.first; - MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; - ++it; - MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; - --it; - --it; - MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; - } - - // look if that ID is found in the map - for (it = myMap.begin(); it != myMap.end(); ++it) - { - if ((*it).second->mainListIndex == lookForId) - { - MITK_INFO << "But it is there!!!"; - MITK_INFO << "Searched dist: " << lookFor << " found dist: " << (*it).second->distAndEst; - } - - } - */ - } - else - { - for (it=ret.first; it!=ret.second; ++it) - { - if (it->second->mainListIndex == neighborNodes[i]->mainListIndex) - { - found = true; - myMap.erase(it); - /* - MITK_INFO << "INFO: size " << myMap.size(); - MITK_INFO << "Erase: " << it->first << "|" << it->second->mainListIndex; - - MITK_INFO << "INFO: size " << myMap.size(); - for (it = myMap.begin(); it != myMap.end(); ++it) - { - MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; - } - */ - break; - } - } - } + // 1st : find and delete old element + bool found = false; + double lookFor = neighborNodes[i]->distAndEst; + unsigned int lookForId = neighborNodes[i]->mainListIndex; + ret = myMap.equal_range(neighborNodes[i]->distAndEst); + if ((ret.first == ret.second)) + { + /*+++++++++++++ no exact match +++++++++++++*/ + //MITK_INFO << "No exact match!"; // if this happens, you are screwed + /* + MITK_INFO << "Was looking for: " << lookFor << " ID: " << lookForId; + if (ret.first != myMap.end() ) + { + it = ret.first; + MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; + ++it; + MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; + --it; + --it; + MITK_INFO << "Found: " << it->first << " ID: " << it->second->mainListIndex; + } + + // look if that ID is found in the map + for (it = myMap.begin(); it != myMap.end(); ++it) + { + if ((*it).second->mainListIndex == lookForId) + { + MITK_INFO << "But it is there!!!"; + MITK_INFO << "Searched dist: " << lookFor << " found dist: " << (*it).second->distAndEst; + } + + } + */ + } + else + { + for (it=ret.first; it!=ret.second; ++it) + { + if (it->second->mainListIndex == neighborNodes[i]->mainListIndex) + { + found = true; + myMap.erase(it); + /* + MITK_INFO << "INFO: size " << myMap.size(); + MITK_INFO << "Erase: " << it->first << "|" << it->second->mainListIndex; - if (!found) + MITK_INFO << "INFO: size " << myMap.size(); + for (it = myMap.begin(); it != myMap.end(); ++it) { - MITK_INFO << "Could not find it! :("; - continue; + MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; } + */ + break; + } + } + } - // 2nd: update and insert new element - neighborNodes[i]->distance = newDistance; + if (!found) + { + //MITK_INFO << "Could not find it! :("; + continue; + } + + // 2nd: update and insert new element + neighborNodes[i]->distance = newDistance; neighborNodes[i]->distAndEst = newDistance + getEstimatedCostsToTarget(coordNeighborNode); neighborNodes[i]->prevNode = mainNodeListIndex; - //myMap.insert( std::pair (neighborNodes[i]->distAndEst, neighborNodes[i])); - myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); + //myMap.insert( std::pair (neighborNodes[i]->distAndEst, neighborNodes[i])); + myMap.insert( std::pair (m_Nodes[neighborNodes[i]->mainListIndex].distAndEst, &m_Nodes[neighborNodes[i]->mainListIndex]) ); - //MITK_INFO << "Re-Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; - //MITK_INFO << "INFO: size " << myMap.size(); - /*for (it = myMap.begin(); it != myMap.end(); ++it) - { - MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; - }*/ + //MITK_INFO << "Re-Inserted: " << m_Nodes[neighborNodes[i]->mainListIndex].distAndEst << "|" << m_Nodes[neighborNodes[i]->mainListIndex].mainListIndex; + //MITK_INFO << "INFO: size " << myMap.size(); + /*for (it = myMap.begin(); it != myMap.end(); ++it) + { + MITK_INFO << "(1) " << it->first << "|" << it->second->distAndEst << "|"<second->mainListIndex; + }*/ } } } // finished with checking all neighbors. // Check Timeout, if activated if (m_ActivateTimeOut) { stopAll = clock(); durationAll = (double)(stopAll - startAll) / CLOCKS_PER_SEC; if (durationAll >= 30) { - MITK_INFO << "TIMEOUT!! Search took over 30 seconds"; + //MITK_INFO << "TIMEOUT!! Search took over 30 seconds"; timeout = true ; } } - // Check end criteria: - // For multiple points - if ( multipleEndPoints ) - { - // super slow, make it faster - for (int i=0 ;i void ShortestPathImageFilter:: MakeOutputs() { - MITK_INFO << "Make Output"; + //MITK_INFO << "Make Output"; - if (m_MakeOutputImage) + if (m_MakeOutputImage) + { + OutputImagePointer output0 = this->GetOutput(0); + output0->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); + output0->Allocate(); + OutputImageIteratorType shortestPathImageIt (output0, output0->GetRequestedRegion()); + // Create ShortestPathImage (Output 0) + for (shortestPathImageIt.GoToBegin(); !shortestPathImageIt.IsAtEnd(); ++shortestPathImageIt) { - OutputImagePointer output0 = this->GetOutput(0); - output0->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); - output0->Allocate(); - OutputImageIteratorType shortestPathImageIt (output0, output0->GetRequestedRegion()); - // Create ShortestPathImage (Output 0) - for (shortestPathImageIt.GoToBegin(); !shortestPathImageIt.IsAtEnd(); ++shortestPathImageIt) - { - // First intialize with background color - shortestPathImageIt.Set( BACKGROUND ) ; - } - - if (!multipleEndPoints) // Only one path was calculated - { - for (int i=0; i< m_VectorPath.size(); i++) + // First intialize with background color + shortestPathImageIt.Set( BACKGROUND ) ; + } + + if (!multipleEndPoints) // Only one path was calculated + { + for (int i=0; i< m_VectorPath.size(); i++) + { + shortestPathImageIt.SetIndex( m_VectorPath[i] ); + shortestPathImageIt.Set( FOREGROUND ) ; + } + } + else // multiple pathes has been calculated, draw all + { + for (int i =0; i - typename ShortestPathImageFilter::OutputImagePointer + typename ShortestPathImageFilter::OutputImagePointer ShortestPathImageFilter:: GetVectorOrderImage() { - // Create Vector Order Image - // Return it + // Create Vector Order Image + // Return it - OutputImagePointer image = OutputImageType::New(); - image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); - image->Allocate(); - OutputImageIteratorType vectorOrderImageIt (image, image->GetRequestedRegion()); + OutputImagePointer image = OutputImageType::New(); + image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); + image->Allocate(); + OutputImageIteratorType vectorOrderImageIt (image, image->GetRequestedRegion()); - MITK_INFO << "GetVectorOrderImage"; - for (vectorOrderImageIt.GoToBegin(); !vectorOrderImageIt.IsAtEnd(); ++vectorOrderImageIt) - { - // First intialize with background color - vectorOrderImageIt.Value() = BACKGROUND ; - } - for (int i=0; i< m_VectorOrder.size(); i++) - { - vectorOrderImageIt.SetIndex(NodeToCoord(m_VectorOrder[i]) ); - vectorOrderImageIt.Set( BACKGROUND+i) ; - } + //MITK_INFO << "GetVectorOrderImage"; + for (vectorOrderImageIt.GoToBegin(); !vectorOrderImageIt.IsAtEnd(); ++vectorOrderImageIt) + { + // First intialize with background color + vectorOrderImageIt.Value() = BACKGROUND ; + } + for (int i=0; i< m_VectorOrder.size(); i++) + { + vectorOrderImageIt.SetIndex(NodeToCoord(m_VectorOrder[i]) ); + vectorOrderImageIt.Set( BACKGROUND+i) ; + } return image; } template typename ShortestPathImageFilter::OutputImagePointer ShortestPathImageFilter:: GetDistanceImage() { - // Create Distance Image - // Return it - - OutputImagePointer image = OutputImageType::New(); - image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); - image->Allocate();; - OutputImageIteratorType distanceImageIt (image, image->GetRequestedRegion()); - // Create Distance Image (Output 1) - NodeNumType myNodeNum; - for (distanceImageIt.GoToBegin(); !distanceImageIt.IsAtEnd(); ++distanceImageIt) - { - IndexType index = distanceImageIt.GetIndex(); - myNodeNum = CoordToNode(index); - double newVal = m_Nodes[myNodeNum].distance; - distanceImageIt.Set(newVal); - } - } + // Create Distance Image + // Return it + + OutputImagePointer image = OutputImageType::New(); + image->SetRegions( this->GetInput()->GetLargestPossibleRegion() ); + image->Allocate();; + OutputImageIteratorType distanceImageIt (image, image->GetRequestedRegion()); + // Create Distance Image (Output 1) + NodeNumType myNodeNum; + for (distanceImageIt.GoToBegin(); !distanceImageIt.IsAtEnd(); ++distanceImageIt) + { + IndexType index = distanceImageIt.GetIndex(); + myNodeNum = CoordToNode(index); + double newVal = m_Nodes[myNodeNum].distance; + distanceImageIt.Set(newVal); + } + } template - std::vector< itk::Index<3> > + std::vector< typename ShortestPathImageFilter::IndexType > ShortestPathImageFilter:: GetVectorPath() { return m_VectorPath; } - template - std::vector< std::vector< itk::Index<3> > > + template + std::vector< std::vector< typename ShortestPathImageFilter::IndexType > > ShortestPathImageFilter:: GetMultipleVectorPaths() { return m_MultipleVectorPaths; } template void ShortestPathImageFilter:: MakeShortestPathVector() { - MITK_INFO << "Make ShortestPath Vec"; - - // single end point - if ( !multipleEndPoints ) - { - // fill m_VectorPath with the Shortest Path - m_VectorPath.clear(); + //MITK_INFO << "Make ShortestPath Vec"; - // Go backwards from endnote to startnode - NodeNumType prevNode = m_Graph_EndNode; - while (prevNode != -1) - { - m_VectorPath.push_back( NodeToCoord(prevNode) ); + // single end point + if ( !multipleEndPoints ) + { + // fill m_VectorPath with the Shortest Path + m_VectorPath.clear(); - if (prevNode == m_Graph_StartNode) - break; + // Go backwards from endnote to startnode + NodeNumType prevNode = m_Graph_EndNode; + while (prevNode != -1) + { + m_VectorPath.push_back( NodeToCoord(prevNode) ); - prevNode = m_Nodes[prevNode].prevNode; - } + if (prevNode == m_Graph_StartNode) + break; - // reverse it - std::reverse(m_VectorPath.begin(), m_VectorPath.end() ); + prevNode = m_Nodes[prevNode].prevNode; } - // Multiple end end points and pathes - else + + // reverse it + std::reverse(m_VectorPath.begin(), m_VectorPath.end() ); + } + // Multiple end end points and pathes + else + { + for (int i=0; i void ShortestPathImageFilter:: CleanUp() { - - m_VectorPath.clear(); - //TODO: if multiple Path, clear all multiple Paths - /* - for (NodeNumType i=0; i void ShortestPathImageFilter:: GenerateData() { // Build Graph InitGraph(); // Calc Shortest Parth StartShortestPathSearch(); // Fill Shortest Path MakeShortestPathVector(); // Make Outputs MakeOutputs(); } template void ShortestPathImageFilter:: PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf(os,indent); } } /* end namespace itk */ #endif diff --git a/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.cpp b/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.cpp new file mode 100644 index 0000000000..0e7e807ef3 --- /dev/null +++ b/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.cpp @@ -0,0 +1,175 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#include "mitkPropertyListExportToXmlFile.h" +#include +#include +#include "mitkProperties.h" +#include "mitkStringProperty.h" +#include "mitkEnumerationProperty.h" +#include +#include +#include +#include "usServiceReference.h" +#include +#include + +namespace mitk +{ + struct PropertyListExportToXmlFileData + { + const std::string* m_FileName; + const PropertyList* m_PropertyList; + }; + + PropertyListExportToXmlFile::PropertyListExportToXmlFile(const std::string* _FileName, + const PropertyList* _PropertyList) + : d( new PropertyListExportToXmlFileData ) + { + d->m_FileName = _FileName; + d->m_PropertyList = _PropertyList; + } + + PropertyListExportToXmlFile::~PropertyListExportToXmlFile() + { + delete d; + } + + void PropertyListExportToXmlFile::Update() + { + std::string _FileName = *d->m_FileName; + PropertyList::Pointer propList = PropertyList::New(); + + TiXmlDocument doc( _FileName.c_str() ); + TiXmlElement* root = 0; + TiXmlElement* elem = 0; + + std::string className; + d->m_PropertyList->GetStringProperty("ClassName", className); + // check if element is already available + if(doc.LoadFile()) + { + root = doc.FirstChildElement(); + if(!root) + { + MITK_WARN("PropertyListExportToXml") << "No root element found"; + return; + } + elem = root->FirstChildElement( className ); + std::string id; + d->m_PropertyList->GetStringProperty("Id", id); + if( !id.empty() ) + { + std::string foundId; + while(elem) + { + elem->QueryStringAttribute("Id", &foundId); + if( foundId == id ) + break; + elem = elem->NextSiblingElement( className ); + } + } + } + else + { + // document did not exist, create new one with declration + TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" ); + doc.LinkEndChild( decl ); + // create root + root = new TiXmlElement( "data" ); + doc.LinkEndChild( root ); + } + + // create elem if not existent + TiXmlElement* newElem = 0; + if(!elem) + { + elem = new TiXmlElement( className ); + newElem = elem; + } + + const std::map< std::string, BaseProperty::Pointer>* propMap = d->m_PropertyList->GetMap(); + std::map< std::string, BaseProperty::Pointer>::const_iterator propMapIt = propMap->begin(); + while( propMapIt != propMap->end() ) + { + if( propMapIt->first.find_first_of(".") != std::string::npos ) + { + MITK_DEBUG << "meta property found. will not write."; + ++propMapIt; + continue; + } + mitk::IntProperty* intProp = 0; + mitk::FloatProperty* floatProp = 0; + mitk::DoubleProperty* doubleProp = 0; + mitk::BoolProperty* boolProp = 0; + mitk::StringProperty* stringProp = 0; + mitk::EnumerationProperty* enumProp = 0; + + if( (boolProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetAttribute( propMapIt->first, boolProp->GetValue() ? 1 : 0 ); + } + else if( (stringProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetAttribute( propMapIt->first, stringProp->GetValue() ); + } + else if( (intProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetAttribute( propMapIt->first, intProp->GetValue() ); + } + else if( (enumProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetAttribute( propMapIt->first, enumProp->GetValueAsId() ); + } + else if( (doubleProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetDoubleAttribute( propMapIt->first, doubleProp->GetValue() ); + } + else if( (floatProp = dynamic_cast( propMapIt->second.GetPointer() ) ) ) + { + elem->SetDoubleAttribute( propMapIt->first, static_cast( floatProp->GetValue() ) ); + } + else + { + MITK_DEBUG << "trying to look up serializer for baseproperty in AlgorithmRegistry"; + + { + MITK_WARN("PropertyListExportToXmlFile") << "Base property " << propMapIt->first << " is unknown"; + } + } + ++propMapIt; + } + + // add the element node as child + if( newElem ) + root->LinkEndChild(elem); + + if( !doc.SaveFile( _FileName ) ) + { + MITK_DEBUG << "File " << _FileName << " could not be written. Please check permissions."; + MITK_WARN("PropertyListExportToXmlFile") << "Cannot write file"; + } + } + + void PropertyListExportToXmlFile::SetFileName(const std::string* _FileName) + { + d->m_FileName = _FileName; + } + + void PropertyListExportToXmlFile::SetPropertyList(const PropertyList* _PropertyList) + { + d->m_PropertyList = _PropertyList; + } +} // namespace mitk diff --git a/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.h b/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.h new file mode 100644 index 0000000000..6bc4ef6d87 --- /dev/null +++ b/Modules/MitkExt/IO/mitkPropertyListExportToXmlFile.h @@ -0,0 +1,63 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#ifndef mitkPropertyListExportToXmlFile_h +#define mitkPropertyListExportToXmlFile_h + +#include "MitkExtExports.h" +#include + +namespace mitk +{ + /// + /// d pointer forward declaration + /// + struct PropertyListExportToXmlFileData; + /// + /// writes a 2d cv point to an xml file + /// + class MitkExt_EXPORT PropertyListExportToXmlFile + { + public: + /// + /// init default values and save references + /// + PropertyListExportToXmlFile( const std::string* _FileName = 0, + const PropertyList* _PropertyList = 0); + /// + /// executes the algorithm if inputs changed + /// + void Update(); + /// + /// delete d pointer + /// + virtual ~PropertyListExportToXmlFile(); + /// + /// setter for field FileName + /// + void SetFileName(const std::string* _FileName); + /// + /// setter for field PropertyList + /// + void SetPropertyList(const PropertyList* _PropertyList); + private: + /// + /// d pointer + /// + PropertyListExportToXmlFileData* d; + }; +} // namespace mitk + +#endif // mitkPropertyListExportToXmlFile_h diff --git a/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.cpp b/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.cpp new file mode 100644 index 0000000000..aa70e625e1 --- /dev/null +++ b/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.cpp @@ -0,0 +1,203 @@ +/*=================================================================== + +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 "mitkPropertyListImportFromXmlFile.h" +#include +#include +#include +#include "mitkProperties.h" +#include "mitkStringProperty.h" +#include "mitkEnumerationProperty.h" +#include "mitkGenericProperty.h" +//#include "mitkBasePropertyFromString.h" +#include +#include +#include +#include "usServiceReference.h" + +namespace mitk +{ + struct PropertyListImportFromXmlFileData + { + const std::string* m_FileName; + PropertyList* m_PropertyList; + + //private + long int m_FileModifiedTime; + }; + + PropertyListImportFromXmlFile::PropertyListImportFromXmlFile( + const std::string* _FileName, + PropertyList* _PropertyList) + : d( new PropertyListImportFromXmlFileData ) + { + d->m_FileName = _FileName; + d->m_PropertyList = _PropertyList; + d->m_FileModifiedTime = 0; + } + + PropertyListImportFromXmlFile::~PropertyListImportFromXmlFile() + { + delete d; + } + + void GetPropertyListFromXMLFile ( const TiXmlElement* elem, const std::string* _FileName, PropertyList* _PropertyList ) + { + const std::map< std::string, BaseProperty::Pointer>* propMap = _PropertyList->GetMap(); + std::map< std::string, BaseProperty::Pointer>::const_iterator propMapIt = propMap->begin(); + while( propMapIt != propMap->end() ) + { + std::string key = propMapIt->first; + mitk::BaseProperty* prop = propMapIt->second.GetPointer(); + mitk::IntProperty* intProp = 0; + mitk::FloatProperty* floatProp = 0; + mitk::DoubleProperty* doubleProp = 0; + mitk::BoolProperty* boolProp = 0; + mitk::StringProperty* stringProp = 0; + mitk::EnumerationProperty* enumProp = 0; + bool found = false; + + if( (boolProp = dynamic_cast( prop ) ) ) + { + int val = false; + found = elem->QueryIntAttribute(key, &val) == TIXML_SUCCESS; + if( found ) + boolProp->SetValue( val==0 ? false : true ); + } + else if( (stringProp = dynamic_cast( prop ) ) ) + { + std::string val = ""; + found = elem->QueryStringAttribute(key.c_str(), &val) == TIXML_SUCCESS; + if( found ) + stringProp->SetValue( val ); + } + else if( (intProp = dynamic_cast( prop ) ) ) + { + int val = 0; + found = elem->QueryIntAttribute(key, &val) == TIXML_SUCCESS; + if( found ) + intProp->SetValue( val ); + } + else if( (enumProp = dynamic_cast( prop ) ) ) + { + int val = 0; + found = elem->QueryIntAttribute(key, &val) == TIXML_SUCCESS; + if( found && enumProp->IsValidEnumerationValue( val ) ) + enumProp->SetValue( static_cast ( val ) ); + else + { + std::string strval = ""; + found = elem->QueryStringAttribute(key.c_str(), &strval); + if( found && enumProp->IsValidEnumerationValue( strval ) ) + enumProp->SetValue( strval ); + } + } + else if( (doubleProp = dynamic_cast( prop ) ) ) + { + double val = 0; + found = elem->QueryDoubleAttribute(key, &val) == TIXML_SUCCESS; + doubleProp->SetValue( val ); + } + else if( (floatProp = dynamic_cast( prop ) ) ) + { + double val = 0; + found = elem->QueryDoubleAttribute(key, &val) == TIXML_SUCCESS; + floatProp->SetValue( static_cast( val ) ); + } + else + { + MITK_WARN("PropertyListImportFromXmlFile") << "Base property " << key << " is unknown"; + } + + if(!found) + { + MITK_DEBUG << "Attribute " << key << " not found"; + } + + ++propMapIt; + } + } + + void PropertyListImportFromXmlFile::Update() + { + + std::string _FileName = *d->m_FileName; + + MITK_DEBUG << "extracting real path (complete path)"; + _FileName = itksys::SystemTools::GetRealPath( _FileName.c_str() ); + + if( !itksys::SystemTools::FileExists(_FileName.c_str()) ) + { + MITK_WARN("PropertyListFromXml") << " Cannot open file"; + } + + long int _FileModifiedTime = itksys::SystemTools::ModifiedTime( _FileName.c_str() ); + // file has not changed: we know that version... -> do nothing + if( d->m_FileModifiedTime >= _FileModifiedTime ) + return; + + // reread + TiXmlDocument doc( _FileName ); + doc.LoadFile(); + + MITK_DEBUG << "searching for element with classname"; + std::string className; + d->m_PropertyList->GetStringProperty("ClassName", className); + + TiXmlHandle docHandle( &doc ); + TiXmlElement* elem = docHandle.FirstChildElement().FirstChildElement( className ).ToElement(); + + if(!elem) + { + MITK_WARN("PropertyListFromXml") << "Cannot find element"; + return; + } + + std::string id; + d->m_PropertyList->GetStringProperty("Id", id); + if( !id.empty() ) + { + std::string foundId; + while(elem) + { + elem->QueryStringAttribute("Id", &foundId); + if( foundId == id ) + break; + elem = elem->NextSiblingElement( className ); + } + if(!elem) + { + MITK_WARN("PropertyListFromXml") << "Cannot find element by id"; + return; + } + } + + MITK_DEBUG << "element found. now reading attributes into propertylist"; + GetPropertyListFromXMLFile( elem, &_FileName, d->m_PropertyList ); + + MITK_DEBUG << "save that modified time"; + d->m_FileModifiedTime = _FileModifiedTime; + } + + void PropertyListImportFromXmlFile::SetFileName(const std::string* _FileName) + { + d->m_FileName = _FileName; + } + + void PropertyListImportFromXmlFile::SetPropertyList(PropertyList* _PropertyList) + { + d->m_PropertyList = _PropertyList; + } +} // namespace mitk diff --git a/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.h b/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.h new file mode 100644 index 0000000000..e4e983876e --- /dev/null +++ b/Modules/MitkExt/IO/mitkPropertyListImportFromXmlFile.h @@ -0,0 +1,64 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ +#ifndef mitkPropertyListImportFromXmlFile_h +#define mitkPropertyListImportFromXmlFile_h + +#include +#include "MitkExtExports.h" + +namespace mitk +{ + /// + /// d pointer forward declaration + /// + struct PropertyListImportFromXmlFileData; + /// + /// DOCUMENTATION + /// + class MitkExt_EXPORT PropertyListImportFromXmlFile + { + public: + /// + /// init default values and save references + /// + PropertyListImportFromXmlFile( const std::string* _FileName = 0, + PropertyList* _PropertyList = 0 ); + + /// + /// executes the algorithm if inputs changed + /// + void Update(); + /// + /// delete d pointer + /// + virtual ~PropertyListImportFromXmlFile(); + /// + /// setter for field FileName + /// + void SetFileName(const std::string* _FileName); + /// + /// setter for field PropertyList + /// + void SetPropertyList(PropertyList* _PropertyList); + private: + /// + /// d pointer + /// + PropertyListImportFromXmlFileData* d; + }; +} // namespace mitk + +#endif // mitkPropertyListImportFromXmlFile_h diff --git a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp index 9d79d2139c..8a8b215a5d 100644 --- a/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp +++ b/Modules/MitkExt/Rendering/mitkGPUVolumeMapper3D.cpp @@ -1,708 +1,710 @@ /*=================================================================== 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. ===================================================================*/ #define GPU_INFO MITK_INFO("mapper.vr") #define GPU_WARN MITK_WARN("mapper.vr") #define GPU_ERROR MITK_ERROR("mapper.vr") #include "mitkGPUVolumeMapper3D.h" #include "mitkDataNode.h" #include "mitkProperties.h" #include "mitkLevelWindow.h" #include "mitkColorProperty.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkColorProperty.h" #include "mitkVtkPropRenderer.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) #include "vtkMitkGPUVolumeRayCastMapper.h" #endif #include "vtkOpenGLGPUVolumeRayCastMapper.h" #include "vtkMitkOpenGLVolumeTextureMapper3D.h" const mitk::Image* mitk::GPUVolumeMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } void mitk::GPUVolumeMapper3D::MitkRenderVolumetricGeometry(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); VtkMapper::MitkRenderVolumetricGeometry(renderer); if(ls->m_gpuInitialized) ls->m_MapperGPU->UpdateMTime(); } bool mitk::GPUVolumeMapper3D::InitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) return ls->m_gpuSupported; GPU_INFO << "initializing gpu-slicing-vr (vtkMitkOpenGLVolumeTextureMapper3D)"; ls->m_MapperGPU = vtkSmartPointer::New(); ls->m_MapperGPU->SetUseCompressedTexture(false); ls->m_MapperGPU->SetSampleDistance(1.0); ls->m_VolumePropertyGPU = vtkSmartPointer::New(); ls->m_VolumePropertyGPU->ShadeOn(); ls->m_VolumePropertyGPU->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyGPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyGPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyGPU->SetSpecularPower(16.0f); ls->m_VolumePropertyGPU->SetInterpolationTypeToLinear(); ls->m_VolumeGPU = vtkSmartPointer::New(); ls->m_VolumeGPU->SetMapper( ls->m_MapperGPU ); ls->m_VolumeGPU->SetProperty( ls->m_VolumePropertyGPU ); ls->m_VolumeGPU->VisibilityOn(); ls->m_MapperGPU->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_gpuSupported = ls->m_MapperGPU->IsRenderSupported(renderer->GetVtkRenderer(),ls->m_VolumePropertyGPU); ls->m_gpuInitialized = true; return ls->m_gpuSupported; } void mitk::GPUVolumeMapper3D::InitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_cpuInitialized) return; int numThreads = itk::MultiThreader::GetGlobalDefaultNumberOfThreads(); GPU_INFO << "initializing cpu-raycast-vr (vtkFixedPointVolumeRayCastMapper) (" << numThreads << " threads)"; ls->m_MapperCPU = vtkSmartPointer::New(); ls->m_MapperCPU->SetSampleDistance(1.0); // ls->m_MapperCPU->LockSampleDistanceToInputSpacingOn(); ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->IntermixIntersectingGeometryOn(); ls->m_MapperCPU->SetAutoAdjustSampleDistances(0); ls->m_MapperCPU->SetNumberOfThreads( numThreads ); ls->m_VolumePropertyCPU = vtkSmartPointer::New(); ls->m_VolumePropertyCPU->ShadeOn(); ls->m_VolumePropertyCPU->SetAmbient (0.10f); //0.05f ls->m_VolumePropertyCPU->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyCPU->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyCPU->SetSpecularPower(16.0f); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); ls->m_VolumeCPU = vtkSmartPointer::New(); ls->m_VolumeCPU->SetMapper( ls->m_MapperCPU ); ls->m_VolumeCPU->SetProperty( ls->m_VolumePropertyCPU ); ls->m_VolumeCPU->VisibilityOn(); ls->m_MapperCPU->SetInput( m_UnitSpacingImageFilter->GetOutput() );//m_Resampler->GetOutput()); ls->m_cpuInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitGPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_gpuInitialized) { GPU_INFO << "deinitializing gpu-slicing-vr"; - + // deinit renderwindow, this is needed to release the memory allocated on the gpu + // to prevent leaking memory on the gpu + ls->m_MapperGPU->ReleaseGraphicsResources(renderer->GetVtkRenderer()->GetVTKWindow()); ls->m_VolumePropertyGPU = NULL; ls->m_MapperGPU = NULL; ls->m_VolumeGPU = NULL; ls->m_gpuInitialized=false; } } void mitk::GPUVolumeMapper3D::DeinitCPU(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(!ls->m_cpuInitialized) return; GPU_INFO << "deinitializing cpu-raycast-vr"; ls->m_VolumePropertyCPU = NULL; ls->m_MapperCPU = NULL; ls->m_VolumeCPU = NULL; ls->m_cpuInitialized=false; } mitk::GPUVolumeMapper3D::GPUVolumeMapper3D() { m_VolumeNULL=0; m_commonInitialized=false; } mitk::GPUVolumeMapper3D::~GPUVolumeMapper3D() { DeinitCommon(); } void mitk::GPUVolumeMapper3D::InitCommon() { if(m_commonInitialized) return; m_UnitSpacingImageFilter = vtkSmartPointer::New(); m_UnitSpacingImageFilter->SetOutputSpacing( 1.0, 1.0, 1.0 ); CreateDefaultTransferFunctions(); m_commonInitialized=true; } void mitk::GPUVolumeMapper3D::DeinitCommon() { if(!m_commonInitialized) return; m_commonInitialized=false; } bool mitk::GPUVolumeMapper3D::IsRenderable(mitk::BaseRenderer* renderer) { if(!GetDataNode()) return false; DataNode* node = GetDataNode(); bool visible = true; node->GetVisibility(visible, renderer, "visible"); if(!visible) return false; bool value = false; if(!node->GetBoolProperty("volumerendering",value,renderer)) return false; if(!value) return false; mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); if ( !input || !input->IsInitialized() ) return false; vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); if(inputData==NULL) return false; return true; } void mitk::GPUVolumeMapper3D::InitVtkMapper(mitk::BaseRenderer* renderer) { // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(IsRAYEnabled(renderer)) { DeinitCPU(renderer); DeinitGPU(renderer); if(!InitRAY(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else #endif if(IsGPUEnabled(renderer)) { DeinitCPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif if(!InitGPU(renderer)) { GPU_WARN << "hardware renderer can't initialize ... falling back to software renderer"; goto fallback; } } else { fallback: DeinitGPU(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) DeinitRAY(renderer); #endif InitCPU(renderer); } } vtkProp *mitk::GPUVolumeMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { if(!IsRenderable(renderer)) { if(!m_VolumeNULL) { m_VolumeNULL = vtkSmartPointer::New(); m_VolumeNULL->VisibilityOff(); } return m_VolumeNULL; } InitCommon(); InitVtkMapper( renderer ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) return ls->m_VolumeRAY; #endif if(ls->m_gpuInitialized) return ls->m_VolumeGPU; return ls->m_VolumeCPU; } void mitk::GPUVolumeMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { if(!IsRenderable(renderer)) return; InitCommon(); InitVtkMapper( renderer ); mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); vtkImageData *inputData = input->GetVtkImageData( this->GetTimestep() ); m_UnitSpacingImageFilter->SetInput( inputData ); LocalStorage *ls = m_LSH.GetLocalStorage(renderer); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { GenerateDataRAY(renderer); } else #endif if(ls->m_gpuInitialized) { GenerateDataGPU(renderer); } else { GenerateDataCPU(renderer); } // UpdateTransferFunctions UpdateTransferFunctions( renderer ); } void mitk::GPUVolumeMapper3D::GenerateDataGPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool useCompression = false; GetDataNode()->GetBoolProperty("volumerendering.gpu.usetexturecompression",useCompression,renderer); ls->m_MapperGPU->SetUseCompressedTexture(useCompression); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperGPU->SetSampleDistance(2.0); else ls->m_MapperGPU->SetSampleDistance(1.0); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient",value,renderer)) ls->m_VolumePropertyGPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse",value,renderer)) ls->m_VolumePropertyGPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular",value,renderer)) ls->m_VolumePropertyGPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power",value,renderer)) ls->m_VolumePropertyGPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::GenerateDataCPU( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); int nextLod = mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ); if( IsLODEnabled(renderer) && nextLod == 0 ) { ls->m_MapperCPU->SetImageSampleDistance(3.5); ls->m_MapperCPU->SetSampleDistance(1.25); ls->m_VolumePropertyCPU->SetInterpolationTypeToNearest(); } else { ls->m_MapperCPU->SetImageSampleDistance(1.0); ls->m_MapperCPU->SetSampleDistance(1.0); ls->m_VolumePropertyCPU->SetInterpolationTypeToLinear(); } // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperCPU->SetBlendModeToMaximumIntensity(); else ls->m_MapperCPU->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient",value,renderer)) ls->m_VolumePropertyCPU->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse",value,renderer)) ls->m_VolumePropertyCPU->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular",value,renderer)) ls->m_VolumePropertyCPU->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power",value,renderer)) ls->m_VolumePropertyCPU->SetSpecularPower(value); } } void mitk::GPUVolumeMapper3D::CreateDefaultTransferFunctions() { m_DefaultOpacityTransferFunction = vtkSmartPointer::New(); m_DefaultOpacityTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultOpacityTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultOpacityTransferFunction->ClampingOn(); m_DefaultGradientTransferFunction = vtkSmartPointer::New(); m_DefaultGradientTransferFunction->AddPoint( 0.0, 0.0 ); m_DefaultGradientTransferFunction->AddPoint( 255.0, 0.8 ); m_DefaultGradientTransferFunction->ClampingOn(); m_DefaultColorTransferFunction = vtkSmartPointer::New(); m_DefaultColorTransferFunction->AddRGBPoint( 0.0, 0.0, 0.0, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 127.5, 1, 1, 0.0 ); m_DefaultColorTransferFunction->AddRGBPoint( 255.0, 0.8, 0.2, 0 ); m_DefaultColorTransferFunction->ClampingOn(); m_BinaryOpacityTransferFunction = vtkSmartPointer::New(); m_BinaryOpacityTransferFunction->AddPoint( 0, 0.0 ); m_BinaryOpacityTransferFunction->AddPoint( 1, 1.0 ); m_BinaryGradientTransferFunction = vtkSmartPointer::New(); m_BinaryGradientTransferFunction->AddPoint( 0.0, 1.0 ); m_BinaryColorTransferFunction = vtkSmartPointer::New(); } void mitk::GPUVolumeMapper3D::UpdateTransferFunctions( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); vtkPiecewiseFunction *opacityTransferFunction = m_DefaultOpacityTransferFunction; vtkPiecewiseFunction *gradientTransferFunction = m_DefaultGradientTransferFunction; vtkColorTransferFunction *colorTransferFunction = m_DefaultColorTransferFunction; bool isBinary = false; GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if(isBinary) { opacityTransferFunction = m_BinaryOpacityTransferFunction; gradientTransferFunction = m_BinaryGradientTransferFunction; colorTransferFunction = m_BinaryColorTransferFunction; colorTransferFunction->RemoveAllPoints(); float rgb[3]; if( !GetDataNode()->GetColor( rgb,renderer ) ) rgb[0]=rgb[1]=rgb[2]=1; colorTransferFunction->AddRGBPoint( 0,rgb[0],rgb[1],rgb[2] ); colorTransferFunction->Modified(); } else { mitk::TransferFunctionProperty *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction",renderer)); if( transferFunctionProp ) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } } if(ls->m_gpuInitialized) { ls->m_VolumePropertyGPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyGPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyGPU->SetGradientOpacity( gradientTransferFunction ); } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) if(ls->m_rayInitialized) { ls->m_VolumePropertyRAY->SetColor( colorTransferFunction ); ls->m_VolumePropertyRAY->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyRAY->SetGradientOpacity( gradientTransferFunction ); } #endif if(ls->m_cpuInitialized) { ls->m_VolumePropertyCPU->SetColor( colorTransferFunction ); ls->m_VolumePropertyCPU->SetScalarOpacity( opacityTransferFunction ); ls->m_VolumePropertyCPU->SetGradientOpacity( gradientTransferFunction ); } } void mitk::GPUVolumeMapper3D::ApplyProperties(vtkActor* /*actor*/, mitk::BaseRenderer* /*renderer*/) { //GPU_INFO << "ApplyProperties"; } void mitk::GPUVolumeMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { //GPU_INFO << "SetDefaultProperties"; node->AddProperty( "volumerendering", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.usemip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.ambient", mitk::FloatProperty::New( 0.10f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.cpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); bool usegpu = true; #ifdef __APPLE__ usegpu = false; node->AddProperty( "volumerendering.uselod", mitk::BoolProperty::New( true ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.usegpu", mitk::BoolProperty::New( usegpu ), renderer, overwrite ); // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) node->AddProperty( "volumerendering.useray", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.ray.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); #endif node->AddProperty( "volumerendering.gpu.ambient", mitk::FloatProperty::New( 0.25f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.diffuse", mitk::FloatProperty::New( 0.50f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular", mitk::FloatProperty::New( 0.40f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.specular.power", mitk::FloatProperty::New( 16.0f ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.usetexturecompression", mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "volumerendering.gpu.reducesliceartifacts" , mitk::BoolProperty ::New( false ), renderer, overwrite ); node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if(image.IsNotNull() && image->IsInitialized()) { if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto( image ); levWinProp->SetLevelWindow( levelwindow ); node->SetProperty( "levelwindow", levWinProp, renderer ); } if((overwrite) || (node->GetProperty("TransferFunction", renderer)==NULL)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty ( "TransferFunction", mitk::TransferFunctionProperty::New ( tf.GetPointer() ) ); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } bool mitk::GPUVolumeMapper3D::IsLODEnabled( mitk::BaseRenderer * renderer ) const { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.uselod",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsMIPEnabled( mitk::BaseRenderer * renderer ) { bool value = false; return GetDataNode()->GetBoolProperty("volumerendering.usemip",value,renderer) && value; } bool mitk::GPUVolumeMapper3D::IsGPUEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_gpuSupported && GetDataNode()->GetBoolProperty("volumerendering.usegpu",value,renderer) && value; } // Only with VTK 5.6 or above #if ((VTK_MAJOR_VERSION > 5) || ((VTK_MAJOR_VERSION==5) && (VTK_MINOR_VERSION>=6) )) bool mitk::GPUVolumeMapper3D::InitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) return ls->m_raySupported; GPU_INFO << "initializing gpu-raycast-vr (vtkOpenGLGPUVolumeRayCastMapper)"; ls->m_MapperRAY = vtkSmartPointer::New(); ls->m_MapperRAY->SetAutoAdjustSampleDistances(0); ls->m_MapperRAY->SetSampleDistance(1.0); ls->m_VolumePropertyRAY = vtkSmartPointer::New(); ls->m_VolumePropertyRAY->ShadeOn(); ls->m_VolumePropertyRAY->SetAmbient (0.25f); //0.05f ls->m_VolumePropertyRAY->SetDiffuse (0.50f); //0.45f ls->m_VolumePropertyRAY->SetSpecular(0.40f); //0.50f ls->m_VolumePropertyRAY->SetSpecularPower(16.0f); ls->m_VolumePropertyRAY->SetInterpolationTypeToLinear(); ls->m_VolumeRAY = vtkSmartPointer::New(); ls->m_VolumeRAY->SetMapper( ls->m_MapperRAY ); ls->m_VolumeRAY->SetProperty( ls->m_VolumePropertyRAY ); ls->m_VolumeRAY->VisibilityOn(); ls->m_MapperRAY->SetInput( this->m_UnitSpacingImageFilter->GetOutput() ); ls->m_raySupported = ls->m_MapperRAY->IsRenderSupported(renderer->GetRenderWindow(),ls->m_VolumePropertyRAY); ls->m_rayInitialized = true; return ls->m_raySupported; } void mitk::GPUVolumeMapper3D::DeinitRAY(mitk::BaseRenderer* renderer) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if(ls->m_rayInitialized) { GPU_INFO << "deinitializing gpu-raycast-vr"; ls->m_MapperRAY = NULL; ls->m_VolumePropertyRAY = NULL; //Here ReleaseGraphicsResources has to be called to avoid VTK error messages. //This seems like a VTK bug, because ReleaseGraphicsResources() is ment for internal use, //but you cannot just delete the object (last smartpointer reference) without getting the //VTK error. ls->m_VolumeRAY->ReleaseGraphicsResources(renderer->GetVtkRenderer()->GetRenderWindow()); ls->m_VolumeRAY = NULL; ls->m_rayInitialized=false; } } void mitk::GPUVolumeMapper3D::GenerateDataRAY( mitk::BaseRenderer *renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); if( IsLODEnabled(renderer) && mitk::RenderingManager::GetInstance()->GetNextLOD( renderer ) == 0 ) ls->m_MapperRAY->SetImageSampleDistance(4.0); else ls->m_MapperRAY->SetImageSampleDistance(1.0); // Check raycasting mode if(IsMIPEnabled(renderer)) ls->m_MapperRAY->SetBlendModeToMaximumIntensity(); else ls->m_MapperRAY->SetBlendModeToComposite(); // Updating shadings { float value=0; if(GetDataNode()->GetFloatProperty("volumerendering.ray.ambient",value,renderer)) ls->m_VolumePropertyRAY->SetAmbient(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.diffuse",value,renderer)) ls->m_VolumePropertyRAY->SetDiffuse(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular",value,renderer)) ls->m_VolumePropertyRAY->SetSpecular(value); if(GetDataNode()->GetFloatProperty("volumerendering.ray.specular.power",value,renderer)) ls->m_VolumePropertyRAY->SetSpecularPower(value); } } bool mitk::GPUVolumeMapper3D::IsRAYEnabled( mitk::BaseRenderer * renderer ) { LocalStorage *ls = m_LSH.GetLocalStorage(renderer); bool value = false; return ls->m_raySupported && GetDataNode()->GetBoolProperty("volumerendering.useray",value,renderer) && value; } #endif diff --git a/Modules/MitkExt/files.cmake b/Modules/MitkExt/files.cmake index 4061c11ef5..98831db789 100644 --- a/Modules/MitkExt/files.cmake +++ b/Modules/MitkExt/files.cmake @@ -1,151 +1,153 @@ set(CPP_FILES Algorithms/mitkMaskAndCutRoiImageFilter.cpp Algorithms/mitkBoundingObjectToSegmentationFilter.cpp Algorithms/vtkPointSetSlicer.cxx Algorithms/mitkCoreExtObjectFactory.cpp Algorithms/mitkAngleCorrectByPointFilter.cpp Algorithms/mitkAutoCropImageFilter.cpp Algorithms/mitkBoundingObjectCutter.cpp Algorithms/mitkCylindricToCartesianFilter.cpp Algorithms/mitkDopplerToStrainRateFilter.cpp Algorithms/mitkGeometryClipImageFilter.cpp Algorithms/mitkGeometryDataSource.cpp Algorithms/mitkHeightFieldSurfaceClipImageFilter.cpp Algorithms/mitkImageToLookupTableFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkInterpolateLinesFilter.cpp Algorithms/mitkLabeledImageToSurfaceFilter.cpp Algorithms/mitkLabeledImageVolumeCalculator.cpp Algorithms/mitkLookupTableSource.cpp Algorithms/mitkMaskImageFilter.cpp Algorithms/mitkMeshSource.cpp Algorithms/mitkNonBlockingAlgorithm.cpp Algorithms/mitkPadImageFilter.cpp Algorithms/mitkPlaneCutFilter.cpp Algorithms/mitkPlaneFit.cpp Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp Algorithms/mitkPointLocator.cpp Algorithms/mitkPointSetToCurvedGeometryFilter.cpp Algorithms/mitkPointSetToGeometryDataFilter.cpp Algorithms/mitkPointSetIndexToWorldTransformFilter.cpp Algorithms/mitkSurfaceIndexToWorldTransformFilter.cpp Algorithms/mitkPolygonToRingFilter.cpp Algorithms/mitkProbeFilter.cpp Algorithms/mitkSimpleHistogram.cpp Algorithms/mitkSimpleUnstructuredGridHistogram.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkUnstructuredGridHistogram.cpp Algorithms/mitkUnstructuredGridSource.cpp Algorithms/mitkVolumeVisualizationImagePreprocessor.cpp Controllers/mitkIPythonService.cpp Controllers/mitkMovieGenerator.cpp Controllers/mitkMultiStepper.cpp Controllers/mitkToolManager.cpp DataManagement/mitkAffineTransformationOperation.cpp DataManagement/mitkApplyDiffImageOperation.cpp DataManagement/mitkBoundingObject.cpp DataManagement/mitkBoundingObjectGroup.cpp DataManagement/mitkCellOperation.cpp DataManagement/mitkColorConversions.cpp DataManagement/mitkColorSequence.cpp DataManagement/mitkColorSequenceCycleH.cpp DataManagement/mitkColorSequenceHalfTones.cpp DataManagement/mitkColorSequenceRainbow.cpp DataManagement/mitkCompressedImageContainer.cpp DataManagement/mitkCone.cpp DataManagement/mitkCuboid.cpp DataManagement/mitkCylinder.cpp DataManagement/mitkDataStorageSelection.cpp DataManagement/mitkDelegateManager.cpp DataManagement/mitkDrawOperation.cpp DataManagement/mitkEllipsoid.cpp DataManagement/mitkExternAbstractTransformGeometry.cpp DataManagement/mitkFrameOfReferenceUIDManager.cpp DataManagement/mitkGridRepresentationProperty.cpp DataManagement/mitkGridVolumeMapperProperty.cpp DataManagement/mitkItkBaseDataAdapter.cpp DataManagement/mitkLabeledImageLookupTable.cpp DataManagement/mitkLineOperation.cpp DataManagement/mitkMesh.cpp DataManagement/mitkObjectSet.cpp DataManagement/mitkOrganTypeProperty.cpp DataManagement/mitkPlaneLandmarkProjector.cpp DataManagement/mitkPlane.cpp DataManagement/mitkPropertyManager.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkSeedsImage.cpp DataManagement/mitkSeedsImageLookupTableSource.cpp DataManagement/mitkSphereLandmarkProjector.cpp # DataManagement/mitkUSLookupTableSource.cpp DataManagement/mitkUnstructuredGrid.cpp DataManagement/mitkVideoSource.cpp DataManagement/vtkObjectSet.cpp IO/mitkObjFileIOFactory.cpp IO/mitkObjFileReader.cpp IO/mitkPACSPlugin.cpp IO/mitkParRecFileIOFactory.cpp IO/mitkParRecFileReader.cpp + IO/mitkPropertyListExportToXmlFile.cpp + IO/mitkPropertyListImportFromXmlFile.cpp IO/mitkStlVolumeTimeSeriesIOFactory.cpp IO/mitkStlVolumeTimeSeriesReader.cpp IO/mitkUnstructuredGridVtkWriter.cpp IO/mitkUnstructuredGridVtkWriterFactory.cpp IO/mitkVtkUnstructuredGridIOFactory.cpp IO/mitkVtkUnstructuredGridReader.cpp IO/mitkVtkVolumeTimeSeriesIOFactory.cpp IO/mitkVtkVolumeTimeSeriesReader.cpp Interactions/mitkConferenceEventMapper.cpp Interactions/mitkConnectPointsInteractor.cpp #Interactions/mitkCoordinateSupplier.cpp #Interactions/mitkDisplayCoordinateOperation.cpp #Interactions/mitkDisplayInteractor.cpp Interactions/mitkAffineInteractor3D.cpp Interactions/mitkDisplayPointSetInteractor.cpp #Interactions/mitkDisplayVectorInteractor.cpp Interactions/mitkInteractionDebug.cpp Interactions/mitkInteractionDebugger.cpp Interactions/mitkPointInteractor.cpp Interactions/mitkPointSelectorInteractor.cpp #Interactions/mitkPositionTracker.cpp Interactions/mitkSeedsInteractor.cpp Interactions/mitkSocketClient.cpp Interactions/mitkSurfaceDeformationInteractor3D.cpp Interactions/mitkSurfaceInteractor.cpp Interactions/mitkTool.cpp # Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkMorphologicTool.cpp Interactions/mitkErodeTool.cpp Interactions/mitkDilateTool.cpp Interactions/mitkOpeningTool.cpp Interactions/mitkClosingTool.cpp Interactions/mitkPixelManipulationTool.cpp Rendering/mitkEnhancedPointSetVtkMapper3D.cpp Rendering/mitkImageBackground2D.cpp Rendering/mitkLineMapper2D.cpp # Rendering/mitkLineVtkMapper3D.cpp Rendering/mitkMeshMapper2D.cpp Rendering/mitkMeshVtkMapper3D.cpp Rendering/mitkNativeRenderWindowInteractor.cpp Rendering/mitkSplineMapper2D.cpp Rendering/mitkSplineVtkMapper3D.cpp Rendering/mitkUnstructuredGridMapper2D.cpp Rendering/mitkUnstructuredGridVtkMapper3D.cpp Rendering/mitkVectorImageMapper2D.cpp Rendering/vtkUnstructuredGridMapper.cpp Rendering/vtkMaskedGlyph2D.cpp Rendering/vtkMaskedGlyph3D.cpp Rendering/vtkMitkVolumeTextureMapper3D.cpp Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp Rendering/mitkGPUVolumeMapper3D.cpp Rendering/vtkMitkGPUVolumeRayCastMapper.cpp ) if(WIN32 AND NOT MINGW) set(CPP_FILES Controllers/mitkMovieGeneratorWin32.cpp ${CPP_FILES} ) endif(WIN32 AND NOT MINGW) diff --git a/Modules/OpenCL/mitkOclBinaryThresholdImageFilter.cpp b/Modules/OpenCL/mitkOclBinaryThresholdImageFilter.cpp index b44c7c6463..4e7dede7a7 100644 --- a/Modules/OpenCL/mitkOclBinaryThresholdImageFilter.cpp +++ b/Modules/OpenCL/mitkOclBinaryThresholdImageFilter.cpp @@ -1,97 +1,100 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkOclBinaryThresholdImageFilter.h" mitk::OclBinaryThresholdImageFilter::OclBinaryThresholdImageFilter() : m_ckBinaryThreshold( NULL ) { std::string path = "BinaryThresholdFilter.cl"; this->SetSourceFile( path.c_str() ); this->m_FilterID = "BinaryThreshold"; this->m_LowerThreshold = 10; this->m_UpperThreshold = 200; this->m_InsideValue = 100; this->m_OutsideValue = 0; } mitk::OclBinaryThresholdImageFilter::~OclBinaryThresholdImageFilter() { if ( this->m_ckBinaryThreshold ) { clReleaseKernel( m_ckBinaryThreshold ); } } void mitk::OclBinaryThresholdImageFilter::Update() { //Check if context & program available if (!this->Initialize()) { + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + // clean-up also the resources - OpenCLActivator::GetResourceServiceRef()->InvalidateStorage(); + resources->InvalidateStorage(); mitkThrow() <<"Filter is not initialized. Cannot update."; } else{ // Execute this->Execute(); } } void mitk::OclBinaryThresholdImageFilter::Execute() { cl_int clErr = 0; try { this->InitExec( this->m_ckBinaryThreshold ); } catch( const mitk::Exception& e) { MITK_ERROR << "Catched exception while initializing filter: " << e.what(); return; } // set kernel arguments clErr = clSetKernelArg( this->m_ckBinaryThreshold, 2, sizeof(cl_int), &(this->m_LowerThreshold) ); clErr |= clSetKernelArg( this->m_ckBinaryThreshold, 3, sizeof(cl_int), &(this->m_UpperThreshold) ); clErr |= clSetKernelArg( this->m_ckBinaryThreshold, 4, sizeof(cl_int), &(this->m_OutsideValue) ); clErr |= clSetKernelArg( this->m_ckBinaryThreshold, 5, sizeof(cl_int), &(this->m_InsideValue) ); CHECK_OCL_ERR( clErr ); // execute the filter on a 3D NDRange this->ExecuteKernel( m_ckBinaryThreshold, 3); // signalize the GPU-side data changed m_Output->Modified( GPU_DATA ); } bool mitk::OclBinaryThresholdImageFilter::Initialize() { bool buildErr = true; cl_int clErr = 0; if ( OclFilter::Initialize() ) { this->m_ckBinaryThreshold = clCreateKernel( this->m_ClProgram, "ckBinaryThreshold", &clErr); buildErr |= CHECK_OCL_ERR( clErr ); } return (Superclass::IsInitialized() && buildErr ); } diff --git a/Modules/OpenCL/mitkOclFilter.cpp b/Modules/OpenCL/mitkOclFilter.cpp index ea91e778bf..4321af78bf 100644 --- a/Modules/OpenCL/mitkOclFilter.cpp +++ b/Modules/OpenCL/mitkOclFilter.cpp @@ -1,219 +1,228 @@ /*=================================================================== 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. ===================================================================*/ //Ocl #include "mitkOclFilter.h" #include "mitkOclUtils.h" #include "mitkOpenCLActivator.h" //Mitk #include #include #include #include mitk::OclFilter::OclFilter() : m_ClFile(), m_ClSource(NULL), m_ClCompilerFlags(""), m_ClProgram(NULL), m_CommandQue(NULL), m_FilterID("mitkOclFilter"), m_Preambel(" "), m_Initialized(false) { m_ClSourcePath = MITK_ROOT; m_ClSourcePath += "Modules/OpenCL/ShaderSources"; } mitk::OclFilter::OclFilter(const char* filename) : m_ClFile(), m_ClSource(NULL), m_ClCompilerFlags(""), m_ClProgram(NULL), m_CommandQue(NULL), m_FilterID(filename), m_Preambel(" "), m_Initialized(false) { m_ClSourcePath = MITK_ROOT; m_ClSourcePath += "Modules/OpenCL/ShaderSources"; } mitk::OclFilter::~OclFilter() { MITK_DEBUG << "OclFilter Destructor"; // release program if (m_ClProgram) { cl_int clErr = 0; + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + // remove program from storage - OpenCLActivator::GetResourceServiceRef()->RemoveProgram(m_FilterID); + resources->RemoveProgram(m_FilterID); // release program clErr = clReleaseProgram(this->m_ClProgram); CHECK_OCL_ERR(clErr); } } bool mitk::OclFilter::ExecuteKernel( cl_kernel kernel, unsigned int workSizeDim ) { cl_int clErr = 0; clErr = clEnqueueNDRangeKernel( this->m_CommandQue, kernel, workSizeDim, NULL, this->m_GlobalWorkSize, m_LocalWorkSize, 0, NULL, NULL); CHECK_OCL_ERR( clErr ); return ( clErr == CL_SUCCESS ); } bool mitk::OclFilter::Initialize() { - m_CommandQue = OpenCLActivator::GetResourceServiceRef()->GetCommandQueue(); + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + m_CommandQue = resources->GetCommandQueue(); cl_int clErr = 0; m_Initialized = CHECK_OCL_ERR(clErr); if ((m_ClSource==NULL) && (m_ClFile.empty())) { MITK_ERROR<<"No OpenCL Source FILE specified"; return false; } if (m_ClProgram == NULL) { try { - this->m_ClProgram = OpenCLActivator::GetResourceServiceRef()->GetProgram( this->m_FilterID ); + this->m_ClProgram = resources->GetProgram( this->m_FilterID ); } catch(const mitk::Exception& e) { MITK_INFO << "Program not stored in resource manager, compiling."; this->CompileSource(); } } return m_Initialized; } void mitk::OclFilter::SetSourceFile(const char* filename) { MITK_DEBUG("ocl.filter") << "Setting source [" << filename <<" ]"; mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch( m_ClSourcePath.c_str(), true); // search for file m_ClFile = mitk::StandardFileLocations::GetInstance()->FindFile( filename); } void mitk::OclFilter::CompileSource() { if (m_ClFile.empty() && m_ClSource == NULL) { MITK_ERROR("ocl.filter") << "No shader source file was set"; return; } // help variables size_t szKernelLength; int clErr = 0; //get a valid opencl context - cl_context gpuContext = OpenCLActivator::GetResourceServiceRef()->GetContext(); + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + cl_context gpuContext = resources->GetContext(); // load the program source from file m_ClSource = oclLoadProgramSource( m_ClFile.c_str(), this->m_Preambel, &szKernelLength); if (m_ClSource != NULL) { m_ClProgram = clCreateProgramWithSource(gpuContext, 1, (const char**)&m_ClSource, &szKernelLength, &clErr); CHECK_OCL_ERR(clErr); // build the source code MITK_DEBUG << "Building Program Source"; std::string compilerOptions = ""; compilerOptions.append(m_ClCompilerFlags); // activate the include compiler flag compilerOptions.append(" -I"); // set the path of the current gpu source dir as opencl // include folder compilerOptions.append(m_ClSourcePath.c_str()); MITK_DEBUG("ocl.filter") << "cl compiler flags: " << compilerOptions.c_str(); clErr = clBuildProgram(m_ClProgram, 0, NULL, compilerOptions.c_str(), NULL, NULL); CHECK_OCL_ERR(clErr); // if OpenCL Source build failed if (clErr != CL_SUCCESS) { MITK_ERROR("ocl.filter") << "Failed to build source"; - oclLogBuildInfo(m_ClProgram, OpenCLActivator::GetResourceServiceRef()->GetCurrentDevice() ); - oclLogBinary(m_ClProgram, OpenCLActivator::GetResourceServiceRef()->GetCurrentDevice() ); + oclLogBuildInfo(m_ClProgram, resources->GetCurrentDevice() ); + oclLogBinary(m_ClProgram, resources->GetCurrentDevice() ); m_Initialized = false; } // store the succesfully build program into the program storage provided by the resource service - OpenCLActivator::GetResourceServiceRef()->InsertProgram(m_ClProgram, m_FilterID, true); + resources->InsertProgram(m_ClProgram, m_FilterID, true); } else { MITK_ERROR("ocl.filter") << "Could not load from source"; m_Initialized = false; } } void mitk::OclFilter::SetWorkingSize(unsigned int locx, unsigned int dimx, unsigned int locy, unsigned int dimy, unsigned int locz, unsigned int dimz) { // set the local work size this->m_LocalWorkSize[0] = locx; this->m_LocalWorkSize[1] = locy; this->m_LocalWorkSize[2] = locz; // estimate the global work size this->m_GlobalWorkSize[0] = iDivUp( dimx, this->m_LocalWorkSize[0]) *this->m_LocalWorkSize[0]; this->m_GlobalWorkSize[1] = iDivUp( dimy, this->m_LocalWorkSize[1]) * this->m_LocalWorkSize[1]; if( dimz <= 1 ) this->m_GlobalWorkSize[2] = 1; else this->m_GlobalWorkSize[2] = iDivUp( dimz, this->m_LocalWorkSize[2]) * this->m_LocalWorkSize[2]; } void mitk::OclFilter::SetSourcePreambel(const char* preambel) { this->m_Preambel = preambel; } void mitk::OclFilter::SetSourcePath(const char* path) { m_ClSourcePath = path; } void mitk::OclFilter::SetCompilerFlags(const char* flags) { m_ClCompilerFlags = flags; } bool mitk::OclFilter::IsInitialized() { return m_Initialized; } diff --git a/Modules/OpenCL/mitkOclImage.cpp b/Modules/OpenCL/mitkOclImage.cpp index 4bf61e72b7..dd1a8d4e12 100644 --- a/Modules/OpenCL/mitkOclImage.cpp +++ b/Modules/OpenCL/mitkOclImage.cpp @@ -1,347 +1,354 @@ /*=================================================================== 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 "mitkOclImage.h" #include "mitkImageDataItem.h" #include "mitkCommon.h" #include "mitkLogMacros.h" #include "mitkOclUtils.h" #include mitk::OclImage::OclImage() : m_gpuImage(NULL), m_context(NULL), m_bufferSize(0), m_gpuModified(false), m_cpuModified(false), m_Image(NULL), m_dim(0), m_Dims(NULL), m_BpE(1), m_formatSupported(false) { } mitk::OclImage::~OclImage() { MITK_INFO << "OclImage Destructor"; //release GMEM Image buffer if (m_gpuImage) clReleaseMemObject(m_gpuImage); } cl_mem mitk::OclImage::CreateGPUImage(unsigned int _wi, unsigned int _he, unsigned int _de, unsigned int _bpp) { MITK_INFO << "CreateGPUImage call with: BPP=" << _bpp; this->m_Dims = new unsigned int[MAX_DIMS]; m_Dims[0] = _wi; m_Dims[1] = _he; m_Dims[2] = _de; for (unsigned int i=3; iGetContext(); + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + cl_context gpuContext = resources->GetContext(); int clErr; m_gpuImage = clCreateBuffer( gpuContext, CL_MEM_READ_WRITE, m_bufferSize * m_BpE, NULL, &clErr); CHECK_OCL_ERR(clErr); return m_gpuImage; } void mitk::OclImage::InitializeByMitkImage(mitk::Image::Pointer _image) { this->m_Image = _image; this->m_cpuModified = true; this->m_gpuModified = false; this->m_gpuImage = NULL; // compute the size of the GMEM buffer this->m_dim = this->m_Image->GetDimension(); this->m_Dims = this->m_Image->GetDimensions(); MITK_INFO << "Image: " << this->m_Dims[0] <<"x"<< this->m_Dims[1] <<"x"<< this->m_Dims[2]; // get the dimensions this->m_bufferSize = 1; for (unsigned int i=0; im_dim; i++) { this->m_bufferSize *= this->m_Dims[i]; } // multiply by sizeof(PixelType) this->m_BpE = ( this->m_Image->GetPixelType().GetBpe() / 8); } bool mitk::OclImage::IsModified(int _type) { if (_type) return m_cpuModified; else return m_gpuModified; } void mitk::OclImage::Modified(int _type) { // defines... GPU: 0, CPU: 1 m_cpuModified = _type; m_gpuModified = !_type; } int mitk::OclImage::TransferDataToGPU(cl_command_queue gpuComQueue) { cl_int clErr = 0; // check whether an image present if (!m_Image->IsInitialized()){ MITK_ERROR("ocl.Image") << "(mitk) Image not initialized!\n"; return -1; } // there is a need for copy only if RAM-Data newer then GMEM data if (m_cpuModified) { //check the buffer if(m_gpuImage == NULL) { clErr = this->AllocateGPUImage(); } if (m_Image->IsInitialized() && (clErr == CL_SUCCESS)) { const size_t origin[3] = {0, 0, 0}; const size_t region[3] = {m_Dims[0], m_Dims[1], m_Dims[2]}; if( this->m_formatSupported ) { clErr = clEnqueueWriteImage( gpuComQueue, m_gpuImage, CL_TRUE, origin, region, 0, 0, m_Image->GetData(), 0, NULL, NULL); } else { MITK_ERROR << "Selected image format currently not supported..."; } CHECK_OCL_ERR(clErr); } m_gpuModified = true; } return clErr; } cl_int mitk::OclImage::AllocateGPUImage() { cl_int clErr = 0; - cl_context gpuContext =OpenCLActivator::GetResourceServiceRef()->GetContext(); + + mitk::ServiceReference ref = GetModuleContext()->GetServiceReference(); + OclResourceService* resources = GetModuleContext()->GetService(ref); + + cl_context gpuContext = resources->GetContext(); // initialize both proposed and supported format variables to same value this->m_proposedFormat = this->ConvertPixelTypeToOCLFormat(); this->m_supportedFormat = this->m_proposedFormat; // test the current format for HW support - this->m_formatSupported = OpenCLActivator::GetResourceServiceRef()->GetIsFormatSupported( &(this->m_supportedFormat) ); + this->m_formatSupported = resources->GetIsFormatSupported( &(this->m_supportedFormat) ); // create an transfer kernel object in case the proposed format is not supported if( !(this->m_formatSupported) ) { MITK_ERROR << "Original format not supported on the installed graphics card."; return -1; } // create new buffer if( this->m_dim > 2) { //Create a 3D Image m_gpuImage = clCreateImage3D(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, *(m_Dims), *(m_Dims+1), *(m_Dims+2), 0, 0, NULL, &clErr); } else { //Create a 2D Image m_gpuImage = clCreateImage2D(gpuContext, CL_MEM_READ_ONLY, &m_supportedFormat, *(m_Dims), *(m_Dims+1), 0, NULL, &clErr); } CHECK_OCL_ERR(clErr); return clErr; } cl_mem mitk::OclImage::GetGPUImage(cl_command_queue gpuComQueue) { // clGetMemObjectInfo() cl_mem_object_type memInfo; cl_int clErr = 0; // query image object info only if already initialized if( this->m_gpuImage ) { clErr = clGetMemObjectInfo(this->m_gpuImage, CL_MEM_TYPE, sizeof(cl_mem_object_type), &memInfo, NULL ); CHECK_OCL_ERR(clErr); } MITK_INFO << "Querying info for object, recieving: " << memInfo; // test if m_gpuImage CL_MEM_IMAGE_2/3D // if not, copy buffer to image if (memInfo == CL_MEM_OBJECT_BUFFER) { MITK_WARN << " Passed oclImage is a buffer-object, creating image"; //hold a copy of the buffer gmem pointer cl_mem tempBuffer = this->m_gpuImage; const size_t origin[3] = {0, 0, 0}; size_t region[3] = {this->m_Dims[0], this->m_Dims[1], 1}; clErr = this->AllocateGPUImage(); this->m_dim = 3; //copy last data to the image data clErr = clEnqueueCopyBufferToImage( gpuComQueue, tempBuffer, m_gpuImage, 0, origin, region, 0, NULL, NULL); CHECK_OCL_ERR(clErr); //release pointer clReleaseMemObject(tempBuffer); } return m_gpuImage; } void mitk::OclImage::SetPixelType(const cl_image_format *_image) { this->m_proposedFormat.image_channel_data_type = _image->image_channel_data_type; this->m_proposedFormat.image_channel_order = _image->image_channel_order; } void* mitk::OclImage::TransferDataToCPU(cl_command_queue gpuComQueue) { cl_int clErr = 0; // if image created on GPU, needs to create mitk::Image if( m_Image.IsNull() ){ MITK_INFO << "Image not initialized, creating new one."; m_Image = mitk::Image::New(); } // check buffersize/image size char* data = new char[m_bufferSize * m_BpE]; // debug info oclPrintMemObjectInfo( m_gpuImage ); clErr = clEnqueueReadBuffer( gpuComQueue, m_gpuImage, CL_FALSE, 0, m_bufferSize * m_BpE, data ,0, NULL, NULL); CHECK_OCL_ERR(clErr); clFlush( gpuComQueue ); // the cpu data is same as gpu this->m_gpuModified = false; return (void*) data; } cl_image_format mitk::OclImage::ConvertPixelTypeToOCLFormat() { cl_image_format texFormat; //single channel Gray-Valued Images texFormat.image_channel_order = CL_R; MITK_INFO << "Class own value: " << this->m_BpE; switch ( this->m_BpE ) { case 1: texFormat.image_channel_data_type = CL_UNSIGNED_INT8; MITK_INFO<< "PixelType: UCHAR => CLFormat: [CL_UNORM_INT8, CL_R]"; break; case 2: texFormat.image_channel_data_type = CL_SIGNED_INT16; // texFormat.image_channel_order = CL_R; MITK_INFO<< "PixelType: SHORT => CLFormat: [CL_SIGNED_INT16, CL_R]"; break; case 4: texFormat.image_channel_data_type = CL_FLOAT; MITK_INFO<< "Choosing CL_FLOAT"; break; default: texFormat.image_channel_data_type = CL_UNORM_INT8; texFormat.image_channel_order = CL_RG; MITK_INFO<< "Choosing (default) short: 2-Channel UCHAR"; break; } return texFormat; } int mitk::OclImage::GetDimension(int idx) const { if (this->m_dim > idx) { return m_Dims[idx]; } else { MITK_WARN << "Trying to access non-existing dimension."; return 1; } } void mitk::OclImage::SetDimensions(unsigned int* Dims) { m_Dims = Dims; } void mitk::OclImage::SetDimension(unsigned short dim) { m_dim = dim; } float mitk::OclImage::GetSpacing(int idx) { if (this->m_dim > idx) { const float* imSpacing = m_Image->GetSlicedGeometry()->GetFloatSpacing(); return imSpacing[idx]; } else { MITK_WARN << "Trying to access non-existing dimension."; return 1; } } void mitk::OclImage::InitializeMITKImage() { this->m_Image = mitk::Image::New(); } void mitk::OclImage::GetOffset(float* _imOffset) const { itk::Vector result2; result2.Fill(0.0f); result2 = this->m_Image->GetGeometry()->GetIndexToWorldTransform()->GetOffset(); _imOffset[0] = result2[0]; _imOffset[1] = result2[1]; _imOffset[2] = result2[2]; } diff --git a/Modules/OpenCL/mitkOpenCLActivator.cpp b/Modules/OpenCL/mitkOpenCLActivator.cpp index 28e7d6fff4..29e2efb2c0 100644 --- a/Modules/OpenCL/mitkOpenCLActivator.cpp +++ b/Modules/OpenCL/mitkOpenCLActivator.cpp @@ -1,42 +1,33 @@ /*=================================================================== 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 "mitkOpenCLActivator.h" void OpenCLActivator::Load(mitk::ModuleContext *context) { // generate context m_ResourceService.reset(new OclResourceServiceImpl); mitk::ServiceProperties props; context->RegisterService(m_ResourceService.get(), props); - m_InternalResourceReference = m_ResourceService.get(); } void OpenCLActivator::Unload(mitk::ModuleContext *) { - m_InternalResourceReference = NULL; m_ResourceService.release(); } -OclResourceService* OpenCLActivator::GetResourceServiceRef() -{ - return m_InternalResourceReference; -} - -OclResourceServiceImpl* OpenCLActivator::m_InternalResourceReference = NULL; - US_EXPORT_MODULE_ACTIVATOR(MitkOcl, OpenCLActivator ) diff --git a/Modules/OpenCL/mitkOpenCLActivator.h b/Modules/OpenCL/mitkOpenCLActivator.h index fcc88a3b9f..c3132404d0 100644 --- a/Modules/OpenCL/mitkOpenCLActivator.h +++ b/Modules/OpenCL/mitkOpenCLActivator.h @@ -1,59 +1,54 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkOpenCLActivator_h #define __mitkOpenCLActivator_h #include "mitkOclResourceServiceImpl_p.h" #include #include #include #include #include #include #include /** * @class OpenCLActivator * * @brief Custom activator for the OpenCL Module in order to register * and provide the OclResourceService */ class US_ABI_LOCAL OpenCLActivator : public mitk::ModuleActivator { private: std::auto_ptr m_ResourceService; - /** Static variable for fast internal access to the ResourceService */ - static OclResourceServiceImpl* m_InternalResourceReference; - public: /** @brief Load module context */ void Load(mitk::ModuleContext *context); /** @brief Unload module context */ void Unload(mitk::ModuleContext* ); - static OclResourceService* GetResourceServiceRef(); - }; #endif // __mitkOpenCLActivator_h diff --git a/Modules/PlanarFigure/Algorithms/mitkPlanarFigureObjectFactory.cpp b/Modules/PlanarFigure/Algorithms/mitkPlanarFigureObjectFactory.cpp index c26a46ce17..dfdcaccf77 100644 --- a/Modules/PlanarFigure/Algorithms/mitkPlanarFigureObjectFactory.cpp +++ b/Modules/PlanarFigure/Algorithms/mitkPlanarFigureObjectFactory.cpp @@ -1,138 +1,139 @@ /*=================================================================== 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 "mitkPlanarFigureObjectFactory.h" #include "mitkPlanarFigureWriter.h" #include "mitkCoreObjectFactory.h" #include "mitkPlanarFigureIOFactory.h" #include "mitkPlanarFigureWriterFactory.h" #include "mitkPlanarFigure.h" #include "mitkPlanarFigureMapper2D.h" typedef std::multimap MultimapType; mitk::PlanarFigureObjectFactory::PlanarFigureObjectFactory() { static bool alreadyDone = false; if ( !alreadyDone ) { RegisterIOFactories(); itk::ObjectFactoryBase::RegisterFactory( PlanarFigureIOFactory::New() ); PlanarFigureWriterFactory::RegisterOneFactory(); m_FileWriters.push_back( PlanarFigureWriter::New().GetPointer() ); mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(this); CreateFileExtensionsMap(); alreadyDone = true; } } mitk::Mapper::Pointer mitk::PlanarFigureObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId id) { mitk::Mapper::Pointer newMapper=NULL; mitk::BaseData *data = node->GetData(); if ( id == mitk::BaseRenderer::Standard2D ) { if ( dynamic_cast(data) != NULL ) { newMapper = mitk::PlanarFigureMapper2D::New(); newMapper->SetDataNode(node); } } else if ( id == mitk::BaseRenderer::Standard3D ) { } return newMapper; } void mitk::PlanarFigureObjectFactory::SetDefaultProperties(mitk::DataNode* node) { if ( node == NULL ) { return; } mitk::DataNode::Pointer nodePointer = node; mitk::PlanarFigure::Pointer pf = dynamic_cast( node->GetData() ); if ( pf.IsNotNull() ) { mitk::PlanarFigureMapper2D::SetDefaultProperties(node); node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), NULL, true ); node->AddProperty( "opacity", mitk::FloatProperty::New(0.8), NULL, true ); } } const char* mitk::PlanarFigureObjectFactory::GetFileExtensions() { return ""; }; mitk::CoreObjectFactoryBase::MultimapType mitk::PlanarFigureObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } const char* mitk::PlanarFigureObjectFactory::GetSaveFileExtensions() { //return ";;Planar Figures (*.pf)"; // for mitk::PlanarFigure and derived classes std::string fileExtension; this->CreateFileExtensions(m_SaveFileExtensionsMap, fileExtension); return fileExtension.c_str(); }; mitk::CoreObjectFactoryBase::MultimapType mitk::PlanarFigureObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::PlanarFigureObjectFactory::CreateFileExtensionsMap() { + m_FileExtensionsMap.insert(std::pair("*.pf", "Planar Figure Files")); m_SaveFileExtensionsMap.insert(std::pair("*.pf", "Planar Figure Files")); } void mitk::PlanarFigureObjectFactory::RegisterIOFactories() { } struct RegisterPlanarFigureObjectFactory{ RegisterPlanarFigureObjectFactory() : m_Factory( mitk::PlanarFigureObjectFactory::New() ) { mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory( m_Factory ); } ~RegisterPlanarFigureObjectFactory() { mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory( m_Factory ); } mitk::PlanarFigureObjectFactory::Pointer m_Factory; }; static RegisterPlanarFigureObjectFactory registerPlanarFigureObjectFactory; diff --git a/Modules/Properties/CMakeLists.txt b/Modules/Properties/CMakeLists.txt new file mode 100644 index 0000000000..234b645486 --- /dev/null +++ b/Modules/Properties/CMakeLists.txt @@ -0,0 +1,4 @@ +MITK_CREATE_MODULE(Properties + PACKAGE_DEPENDS QT + QT_MODULE +) diff --git a/Modules/Properties/files.cmake b/Modules/Properties/files.cmake new file mode 100644 index 0000000000..5206c029e4 --- /dev/null +++ b/Modules/Properties/files.cmake @@ -0,0 +1,8 @@ +set(CPP_FILES + mitkLoadPropertiesModule.cpp + mitkPropertiesActivator.cpp + mitkPropertyAliases.cpp + mitkPropertyDescriptions.cpp + mitkPropertyFilter.cpp + mitkPropertyFilters.cpp +) diff --git a/Modules/Properties/mitkLoadPropertiesModule.cpp b/Modules/Properties/mitkLoadPropertiesModule.cpp new file mode 100644 index 0000000000..2fc831cb5d --- /dev/null +++ b/Modules/Properties/mitkLoadPropertiesModule.cpp @@ -0,0 +1,21 @@ +/*=================================================================== + +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 "mitkLoadPropertiesModule.h" + +void mitk::LoadPropertiesModule() +{ +} diff --git a/Modules/Properties/mitkLoadPropertiesModule.h b/Modules/Properties/mitkLoadPropertiesModule.h new file mode 100644 index 0000000000..0c4d77495d --- /dev/null +++ b/Modules/Properties/mitkLoadPropertiesModule.h @@ -0,0 +1,27 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkLoadPropertiesModule_h +#define mitkLoadPropertiesModule_h + +#include + +namespace mitk +{ + void Properties_EXPORT LoadPropertiesModule(); +} + +#endif diff --git a/Modules/Properties/mitkPropertiesActivator.cpp b/Modules/Properties/mitkPropertiesActivator.cpp new file mode 100644 index 0000000000..d02689236a --- /dev/null +++ b/Modules/Properties/mitkPropertiesActivator.cpp @@ -0,0 +1,303 @@ +/*=================================================================== + +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 "mitkPropertyAliases.h" +#include "mitkPropertyDescriptions.h" +#include "mitkPropertyFilters.h" +#include +#include +#include +#include + +class AliasEquals +{ +public: + AliasEquals(const std::string& alias) + : m_Alias(alias) + { + } + + bool operator()(std::pair element) + { + return element.second == m_Alias; + } + +private: + std::string m_Alias; +}; + +namespace mitk +{ + class PropertiesActivator : public ModuleActivator + { + public: + void Load(ModuleContext* context) + { + m_PropertyAliases = PropertyAliasesImpl::New(); + context->RegisterService(m_PropertyAliases); + + m_PropertyDescriptions = PropertyDescriptionsImpl::New(); + context->RegisterService(m_PropertyDescriptions); + + m_PropertyFilters = PropertyFiltersImpl::New(); + context->RegisterService(m_PropertyFilters); + } + + void Unload(ModuleContext*) + { + } + + private: + class PropertyAliasesImpl : public itk::LightObject, public PropertyAliases + { + public: + mitkClassMacro(PropertyAliasesImpl, itk::LightObject); + itkNewMacro(Self); + + bool AddAlias(const std::string& propertyName, const std::string& alias, bool overwrite); + std::string GetAlias(const std::string& propertyName) const; + std::string GetPropertyName(const std::string& alias) const; + bool HasAlias(const std::string& propertyName) const; + void RemoveAllAliases(); + void RemoveAlias(const std::string& propertyName); + + private: + std::map m_Aliases; + }; + + class PropertyDescriptionsImpl : public itk::LightObject, public PropertyDescriptions + { + public: + mitkClassMacro(PropertyDescriptionsImpl, itk::LightObject); + itkNewMacro(Self); + + bool AddDescription(const std::string& propertyName, const std::string& description, bool overwrite); + std::string GetDescription(const std::string& propertyName) const; + bool HasDescription(const std::string& propertyName) const; + void RemoveAllDescriptions(); + void RemoveDescription(const std::string& propertyName); + + private: + std::map m_Descriptions; + }; + + class PropertyFiltersImpl : public itk::LightObject, public PropertyFilters + { + public: + mitkClassMacro(PropertyFiltersImpl, itk::LightObject); + itkNewMacro(Self); + + bool AddFilter(const PropertyFilter& filter, bool overwrite); + bool AddFilter(const std::string& className, const PropertyFilter& filter, bool overwrite); + std::map ApplyFilter(const std::map& propertyMap) const; + std::map ApplyFilter(const std::string& className, const std::map& propertyMap) const; + PropertyFilter GetFilter(const std::string& className) const; + bool HasFilter(const std::string& className) const; + void RemoveAllFilters(); + void RemoveFilter(const std::string& className); + + private: + std::map m_Filters; + }; + + PropertyAliasesImpl::Pointer m_PropertyAliases; + PropertyDescriptionsImpl::Pointer m_PropertyDescriptions; + PropertyFiltersImpl::Pointer m_PropertyFilters; + }; + + bool PropertiesActivator::PropertyAliasesImpl::AddAlias(const std::string& propertyName, const std::string& alias, bool overwrite) + { + if (alias.empty()) + return false; + + std::pair::iterator, bool> ret = m_Aliases.insert(std::make_pair(propertyName, alias)); + + if (!ret.second && overwrite) + { + ret.first->second = alias; + ret.second = true; + } + + return ret.second; + } + + std::string PropertiesActivator::PropertyAliasesImpl::GetAlias(const std::string& propertyName) const + { + if (!propertyName.empty()) + { + std::map::const_iterator iter = m_Aliases.find(propertyName); + + if (iter != m_Aliases.end()) + return iter->second; + } + + return ""; + } + + std::string PropertiesActivator::PropertyAliasesImpl::GetPropertyName(const std::string& alias) const + { + if (!alias.empty()) + { + std::map::const_iterator iter = std::find_if(m_Aliases.begin(), m_Aliases.end(), AliasEquals(alias)); + + if (iter != m_Aliases.end()) + return iter->first; + } + + return ""; + } + + bool PropertiesActivator::PropertyAliasesImpl::HasAlias(const std::string& propertyName) const + { + return !propertyName.empty() + ? m_Aliases.find(propertyName) != m_Aliases.end() + : false; + } + + void PropertiesActivator::PropertyAliasesImpl::RemoveAlias(const std::string& propertyName) + { + if (!propertyName.empty()) + m_Aliases.erase(propertyName); + } + + void PropertiesActivator::PropertyAliasesImpl::RemoveAllAliases() + { + m_Aliases.clear(); + } + + bool PropertiesActivator::PropertyDescriptionsImpl::AddDescription(const std::string& propertyName, const std::string& description, bool overwrite) + { + if (!propertyName.empty()) + { + std::pair::iterator, bool> ret = m_Descriptions.insert(std::make_pair(propertyName, description)); + + if (!ret.second && overwrite) + { + ret.first->second = description; + ret.second = true; + } + + return ret.second; + } + + return false; + } + + std::string PropertiesActivator::PropertyDescriptionsImpl::GetDescription(const std::string& propertyName) const + { + if (!propertyName.empty()) + { + std::map::const_iterator iter = m_Descriptions.find(propertyName); + + if (iter != m_Descriptions.end()) + return iter->second; + } + + return ""; + } + + bool PropertiesActivator::PropertyDescriptionsImpl::HasDescription(const std::string& propertyName) const + { + return !propertyName.empty() + ? m_Descriptions.find(propertyName) != m_Descriptions.end() + : false; + } + + void PropertiesActivator::PropertyDescriptionsImpl::RemoveAllDescriptions() + { + m_Descriptions.clear(); + } + + void PropertiesActivator::PropertyDescriptionsImpl::RemoveDescription(const std::string& propertyName) + { + if (!propertyName.empty()) + m_Descriptions.erase(propertyName); + } + + bool PropertiesActivator::PropertyFiltersImpl::AddFilter(const PropertyFilter& filter, bool overwrite) + { + return this->AddFilter("", filter, overwrite); + } + + bool PropertiesActivator::PropertyFiltersImpl::AddFilter(const std::string& className, const PropertyFilter& filter, bool overwrite) + { + if (!filter.IsEmpty()) + { + std::pair::iterator, bool> ret = m_Filters.insert(std::make_pair(className, filter)); + + if (!ret.second && overwrite) + { + ret.first->second = filter; + ret.second = true; + } + + return ret.second; + } + + return false; + } + + std::map PropertiesActivator::PropertyFiltersImpl::ApplyFilter(const std::map& propertyMap) const + { + return this->ApplyFilter("", propertyMap); + } + + std::map PropertiesActivator::PropertyFiltersImpl::ApplyFilter(const std::string& className, const std::map& propertyMap) const + { + std::map ret = propertyMap; + PropertyFilter filter = this->GetFilter(""); + + if (!filter.IsEmpty()) + ret = filter.Apply(ret); + + if (!className.empty()) + { + filter = this->GetFilter(className); + + if (!filter.IsEmpty()) + ret = filter.Apply(ret); + } + + return ret; + } + + PropertyFilter PropertiesActivator::PropertyFiltersImpl::GetFilter(const std::string& className) const + { + std::map::const_iterator iter = m_Filters.find(className); + + if (iter != m_Filters.end()) + return iter->second; + + return PropertyFilter(); + } + + bool PropertiesActivator::PropertyFiltersImpl::HasFilter(const std::string& className) const + { + return m_Filters.find(className) != m_Filters.end(); + } + + void PropertiesActivator::PropertyFiltersImpl::RemoveAllFilters() + { + m_Filters.clear(); + } + + void PropertiesActivator::PropertyFiltersImpl::RemoveFilter(const std::string& className) + { + m_Filters.erase(className); + } +} + +US_EXPORT_MODULE_ACTIVATOR(Properties, mitk::PropertiesActivator) diff --git a/Modules/Properties/mitkPropertyAliases.cpp b/Modules/Properties/mitkPropertyAliases.cpp new file mode 100644 index 0000000000..ddf52e2b67 --- /dev/null +++ b/Modules/Properties/mitkPropertyAliases.cpp @@ -0,0 +1,21 @@ +/*=================================================================== + +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 "mitkPropertyAliases.h" + +mitk::PropertyAliases::~PropertyAliases() +{ +} diff --git a/Modules/Properties/mitkPropertyAliases.h b/Modules/Properties/mitkPropertyAliases.h new file mode 100644 index 0000000000..cded00c7be --- /dev/null +++ b/Modules/Properties/mitkPropertyAliases.h @@ -0,0 +1,42 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPropertyAliases_h +#define mitkPropertyAliases_h + +#include +#include +#include + +namespace mitk +{ + class Properties_EXPORT PropertyAliases + { + public: + virtual ~PropertyAliases(); + + virtual bool AddAlias(const std::string& propertyName, const std::string& alias, bool overwrite = false) = 0; + virtual std::string GetAlias(const std::string& propertyName) const = 0; + virtual std::string GetPropertyName(const std::string& alias) const = 0; + virtual bool HasAlias(const std::string& propertyName) const = 0; + virtual void RemoveAlias(const std::string& propertyName) = 0; + virtual void RemoveAllAliases() = 0; + }; +} + +US_DECLARE_SERVICE_INTERFACE(mitk::PropertyAliases, "org.mitk.services.PropertyAliases") + +#endif diff --git a/Modules/Properties/mitkPropertyDescriptions.cpp b/Modules/Properties/mitkPropertyDescriptions.cpp new file mode 100644 index 0000000000..069bdb765a --- /dev/null +++ b/Modules/Properties/mitkPropertyDescriptions.cpp @@ -0,0 +1,21 @@ +/*=================================================================== + +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 "mitkPropertyDescriptions.h" + +mitk::PropertyDescriptions::~PropertyDescriptions() +{ +} diff --git a/Modules/Properties/mitkPropertyDescriptions.h b/Modules/Properties/mitkPropertyDescriptions.h new file mode 100644 index 0000000000..c22c8da822 --- /dev/null +++ b/Modules/Properties/mitkPropertyDescriptions.h @@ -0,0 +1,41 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPropertyDescriptions_h +#define mitkPropertyDescriptions_h + +#include +#include +#include + +namespace mitk +{ + class Properties_EXPORT PropertyDescriptions + { + public: + virtual ~PropertyDescriptions(); + + virtual bool AddDescription(const std::string& propertyName, const std::string& description, bool overwrite = false) = 0; + virtual std::string GetDescription(const std::string& propertyName) const = 0; + virtual bool HasDescription(const std::string& propertyName) const = 0; + virtual void RemoveAllDescriptions() = 0; + virtual void RemoveDescription(const std::string& propertyName) = 0; + }; +} + +US_DECLARE_SERVICE_INTERFACE(mitk::PropertyDescriptions, "org.mitk.services.PropertyDescriptions") + +#endif diff --git a/Modules/Properties/mitkPropertyFilter.cpp b/Modules/Properties/mitkPropertyFilter.cpp new file mode 100644 index 0000000000..3250246329 --- /dev/null +++ b/Modules/Properties/mitkPropertyFilter.cpp @@ -0,0 +1,192 @@ +/*=================================================================== + +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 "mitkPropertyFilter.h" +#include + +namespace mitk +{ + class PropertyFilter::Impl + { + public: + Impl(); + ~Impl(); + + void AddEntry(const std::string& propertyName, PropertyFilter::List list); + std::map Apply(const std::map& propertyMap) const; + bool HasEntry(const std::string& propertyName, PropertyFilter::List list) const; + bool IsEmpty() const; + void RemoveAllEntries(PropertyFilter::List list); + void RemoveEntry(const std::string& propertyName, PropertyFilter::List list); + + private: + void AddEntry(const std::string& propertyName, std::vector& list); + bool HasEntry(const std::string& propertyName, const std::vector& list) const; + void RemoveAllEntries(std::vector& list); + void RemoveEntry(const std::string& propertyName, std::vector& list); + + std::vector > m_Lists; + }; + + PropertyFilter::Impl::Impl() + : m_Lists(2) + { + } + + PropertyFilter::Impl::~Impl() + { + } + + void mitk::PropertyFilter::Impl::AddEntry(const std::string& propertyName, List list) + { + this->AddEntry(propertyName, m_Lists.at(list)); + } + + void PropertyFilter::Impl::AddEntry(const std::string& propertyName, std::vector& list) + { + if (std::find(list.begin(), list.end(), propertyName) == list.end()) + list.push_back(propertyName); + } + + std::map PropertyFilter::Impl::Apply(const std::map& propertyMap) const + { + std::map ret = !m_Lists[Whitelist].empty() + ? std::map() + : propertyMap; + + if (!m_Lists[Whitelist].empty()) + { + std::map::const_iterator end = propertyMap.end(); + + for (std::map::const_iterator iter = propertyMap.begin(); iter != end; ++iter) + { + if(std::find(m_Lists[Whitelist].begin(), m_Lists[Whitelist].end(), iter->first) != m_Lists[Whitelist].end()) + ret.insert(*iter); + } + } + + if (!m_Lists[Blacklist].empty()) + { + std::vector::const_iterator end = m_Lists[Blacklist].end(); + + for (std::vector::const_iterator iter = m_Lists[Blacklist].begin(); iter != end; ++iter) + ret.erase(*iter); + } + + return ret; + } + + bool mitk::PropertyFilter::Impl::HasEntry(const std::string& propertyName, List list) const + { + return this->HasEntry(propertyName, m_Lists.at(list)); + } + + bool PropertyFilter::Impl::HasEntry(const std::string& propertyName, const std::vector& list) const + { + return std::find(list.begin(), list.end(), propertyName) != list.end(); + } + + bool PropertyFilter::Impl::IsEmpty() const + { + std::vector >::const_iterator end = m_Lists.end(); + + for (std::vector >::const_iterator iter = m_Lists.begin(); iter != end; ++iter) + { + if (!iter->empty()) + return false; + } + + return true; + } + + void mitk::PropertyFilter::Impl::RemoveAllEntries(List list) + { + this->RemoveAllEntries(m_Lists.at(list)); + } + + void PropertyFilter::Impl::RemoveAllEntries(std::vector& list) + { + list.clear(); + } + + void mitk::PropertyFilter::Impl::RemoveEntry(const std::string& propertyName, List list) + { + this->RemoveEntry(propertyName, m_Lists.at(list)); + } + + void PropertyFilter::Impl::RemoveEntry(const std::string& propertyName, std::vector& list) + { + std::vector::iterator iter = std::find(list.begin(), list.end(), propertyName); + + if (iter != list.end()) + list.erase(iter); + } +} + +mitk::PropertyFilter::PropertyFilter() + : m_Impl(new Impl) +{ +} + +mitk::PropertyFilter::~PropertyFilter() +{ + delete m_Impl; +} + +mitk::PropertyFilter::PropertyFilter(const mitk::PropertyFilter& other) + : m_Impl(new Impl(*other.m_Impl)) +{ +} + +mitk::PropertyFilter& mitk::PropertyFilter::operator=(mitk::PropertyFilter other) +{ + std::swap(this->m_Impl, other.m_Impl); + return *this; +} + +void mitk::PropertyFilter::AddEntry(const std::string& propertyName, List list) +{ + if (!propertyName.empty()) + m_Impl->AddEntry(propertyName, list); +} + +std::map mitk::PropertyFilter::Apply(const std::map& propertyMap) const +{ + return m_Impl->Apply(propertyMap); +} + +bool mitk::PropertyFilter::HasEntry(const std::string& propertyName, List list) const +{ + return !propertyName.empty() + ? m_Impl->HasEntry(propertyName, list) + : false; +} + +bool mitk::PropertyFilter::IsEmpty() const +{ + return m_Impl->IsEmpty(); +} + +void mitk::PropertyFilter::RemoveAllEntries(List list) +{ + m_Impl->RemoveAllEntries(list); +} + +void mitk::PropertyFilter::RemoveEntry(const std::string& propertyName, List list) +{ + if (!propertyName.empty()) + m_Impl->RemoveEntry(propertyName, list); +} diff --git a/Modules/Properties/mitkPropertyFilter.h b/Modules/Properties/mitkPropertyFilter.h new file mode 100644 index 0000000000..fffd08f3ec --- /dev/null +++ b/Modules/Properties/mitkPropertyFilter.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPropertyFilter_h +#define mitkPropertyFilter_h + +#include +#include + +namespace mitk +{ + class Properties_EXPORT PropertyFilter + { + public: + enum List + { + Blacklist, + Whitelist + }; + + PropertyFilter(); + ~PropertyFilter(); + PropertyFilter(const PropertyFilter& other); + PropertyFilter& operator=(PropertyFilter other); + + void AddEntry(const std::string& propertyName, List list); + std::map Apply(const std::map& propertyMap) const; + bool HasEntry(const std::string& propertyName, List list) const; + bool IsEmpty() const; + void RemoveAllEntries(List list); + void RemoveEntry(const std::string& propertyName, List list); + + private: + class Impl; + Impl* m_Impl; + }; +} + +#endif diff --git a/Modules/Properties/mitkPropertyFilters.cpp b/Modules/Properties/mitkPropertyFilters.cpp new file mode 100644 index 0000000000..8f1b438f11 --- /dev/null +++ b/Modules/Properties/mitkPropertyFilters.cpp @@ -0,0 +1,21 @@ +/*=================================================================== + +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 "mitkPropertyFilters.h" + +mitk::PropertyFilters::~PropertyFilters() +{ +} diff --git a/Modules/Properties/mitkPropertyFilters.h b/Modules/Properties/mitkPropertyFilters.h new file mode 100644 index 0000000000..a360632615 --- /dev/null +++ b/Modules/Properties/mitkPropertyFilters.h @@ -0,0 +1,45 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkPropertyFilters_h +#define mitkPropertyFilters_h + +#include "mitkPropertyFilter.h" +#include +#include +#include + +namespace mitk +{ + class Properties_EXPORT PropertyFilters + { + public: + virtual ~PropertyFilters(); + + virtual bool AddFilter(const PropertyFilter& filter, bool overwrite = false) = 0; + virtual bool AddFilter(const std::string& className, const PropertyFilter& filter, bool overwrite = false) = 0; + virtual std::map ApplyFilter(const std::map& propertyMap) const = 0; + virtual std::map ApplyFilter(const std::string& className, const std::map& propertyMap) const = 0; + virtual PropertyFilter GetFilter(const std::string& className = "") const = 0; + virtual bool HasFilter(const std::string& className = "") const = 0; + virtual void RemoveAllFilters() = 0; + virtual void RemoveFilter(const std::string& className = "") = 0; + }; +} + +US_DECLARE_SERVICE_INTERFACE(mitk::PropertyFilters, "org.mitk.services.PropertyFilters") + +#endif diff --git a/Modules/Qmitk/QmitkDataStorageComboBox.cpp b/Modules/Qmitk/QmitkDataStorageComboBox.cpp index a3e85a755e..30948c09e0 100644 --- a/Modules/Qmitk/QmitkDataStorageComboBox.cpp +++ b/Modules/Qmitk/QmitkDataStorageComboBox.cpp @@ -1,415 +1,415 @@ /*=================================================================== 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 "QmitkDataStorageComboBox.h" #include //#CTORS/DTOR QmitkDataStorageComboBox::QmitkDataStorageComboBox( QWidget* parent, bool _AutoSelectNewNodes ) : QComboBox(parent) , m_DataStorage(0) , m_Predicate(0) , m_BlockEvents(false) , m_AutoSelectNewNodes(_AutoSelectNewNodes) { this->Init(); } QmitkDataStorageComboBox::QmitkDataStorageComboBox( mitk::DataStorage* _DataStorage, const mitk::NodePredicateBase* _Predicate, QWidget* parent, bool _AutoSelectNewNodes ) : QComboBox(parent) , m_DataStorage(0) , m_Predicate(_Predicate) , m_BlockEvents(false) , m_AutoSelectNewNodes(_AutoSelectNewNodes) { // make connections, fill combobox this->Init(); this->SetDataStorage(_DataStorage); } QmitkDataStorageComboBox::~QmitkDataStorageComboBox() { // if there was an old storage, remove listeners if(m_DataStorage.IsNotNull()) { this->m_DataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::AddNode ) ); this->m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::RemoveNode ) ); } //we have lots of observers to nodes and their name properties, this get's ugly if nodes live longer than the box while(m_Nodes.size() > 0) RemoveNode(0); } //#PUBLIC GETTER mitk::DataStorage::Pointer QmitkDataStorageComboBox::GetDataStorage() const { return m_DataStorage.GetPointer(); } const mitk::NodePredicateBase::ConstPointer QmitkDataStorageComboBox::GetPredicate() const { return m_Predicate.GetPointer(); } mitk::DataNode::Pointer QmitkDataStorageComboBox::GetNode( int index ) const { return (this->HasIndex(index))? m_Nodes.at(index): 0; } mitk::DataNode::Pointer QmitkDataStorageComboBox::GetSelectedNode() const { int _CurrentIndex = this->currentIndex(); return (_CurrentIndex >= 0)? this->GetNode(_CurrentIndex): 0; } mitk::DataStorage::SetOfObjects::ConstPointer QmitkDataStorageComboBox::GetNodes() const { mitk::DataStorage::SetOfObjects::Pointer _SetOfObjects = mitk::DataStorage::SetOfObjects::New(); for (std::vector::const_iterator it = m_Nodes.begin(); it != m_Nodes.end(); ++it) { _SetOfObjects->push_back(*it); } return _SetOfObjects.GetPointer(); } bool QmitkDataStorageComboBox::GetAutoSelectNewItems() { return m_AutoSelectNewNodes; } //#PUBLIC SETTER void QmitkDataStorageComboBox::SetDataStorage(mitk::DataStorage* _DataStorage) { // reset only if datastorage really changed if(m_DataStorage.GetPointer() != _DataStorage) { // if there was an old storage, remove listeners if(m_DataStorage.IsNotNull()) { this->m_DataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::AddNode ) ); this->m_DataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::RemoveNode ) ); } // set new storage m_DataStorage = _DataStorage; // if there is a new storage, add listeners if(m_DataStorage.IsNotNull()) { this->m_DataStorage->AddNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::AddNode ) ); this->m_DataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageComboBox::RemoveNode ) ); } // reset predicate to reset the combobox this->Reset(); } } void QmitkDataStorageComboBox::SetPredicate(const mitk::NodePredicateBase* _Predicate) { if(m_Predicate != _Predicate) { m_Predicate = _Predicate; this->Reset(); } } void QmitkDataStorageComboBox::AddNode( const mitk::DataNode* _DataNode ) { // this is an event function, make sure that we didnt call ourself if(!m_BlockEvents) { m_BlockEvents = true; // pass a -1 to the InsertNode function in order to append the datatreenode to the end this->InsertNode(-1, _DataNode); m_BlockEvents = false; } } void QmitkDataStorageComboBox::RemoveNode( int index ) { if(this->HasIndex(index)) { //# remove itk::Event observer mitk::DataNode* _DataNode = m_Nodes.at(index); // get name property first mitk::BaseProperty* nameProperty = _DataNode->GetProperty("name"); // if prop exists remove modified listener if(nameProperty) { nameProperty->RemoveObserver(m_NodesModifiedObserverTags[index]); // remove name property map m_PropertyToNode.erase(_DataNode); } // then remove delete listener on the node itself _DataNode->RemoveObserver(m_NodesDeleteObserverTags[index]); // remove observer tags from lists m_NodesModifiedObserverTags.erase(m_NodesModifiedObserverTags.begin()+index); m_NodesDeleteObserverTags.erase(m_NodesDeleteObserverTags.begin()+index); - // remove node name from combobox - this->removeItem(index); // remove node from node vector m_Nodes.erase(m_Nodes.begin()+index); + // remove node name from combobox + this->removeItem(index); } } void QmitkDataStorageComboBox::RemoveNode( const mitk::DataNode* _DataNode ) { // this is an event function, make sure that we didnt call ourself if(!m_BlockEvents) { m_BlockEvents = true; this->RemoveNode( this->Find(_DataNode) ); m_BlockEvents = false; } } void QmitkDataStorageComboBox::SetNode(int index, const mitk::DataNode* _DataNode) { if(this->HasIndex(index)) { this->InsertNode(index, _DataNode); } } void QmitkDataStorageComboBox::SetNode( const mitk::DataNode* _DataNode, const mitk::DataNode* _OtherDataNode) { this->SetNode( this->Find(_DataNode), _OtherDataNode); } void QmitkDataStorageComboBox::SetAutoSelectNewItems( bool _AutoSelectNewItems ) { m_AutoSelectNewNodes = _AutoSelectNewItems; } void QmitkDataStorageComboBox::OnDataNodeDeleteOrModified(const itk::Object *caller, const itk::EventObject &event) { if(!m_BlockEvents) { m_BlockEvents = true; // check if we have a modified event (if not it is a delete event) const itk::ModifiedEvent* modifiedEvent = dynamic_cast(&event); // when node was modified reset text if(modifiedEvent) { const mitk::BaseProperty* _NameProperty = dynamic_cast(caller); // node name changed, set it // but first of all find associated node for(std::map::iterator it=m_PropertyToNode.begin() ; it!=m_PropertyToNode.end() ; ++it) { // property is found take node if(it->second == _NameProperty) { // looks strange but when calling setnode with the same node, that means the node gets updated this->SetNode(it->first, it->first); break; } } } else { const mitk::DataNode* _ConstDataNode = dynamic_cast(caller); if(_ConstDataNode) // node will be deleted, remove it this->RemoveNode(_ConstDataNode); } m_BlockEvents = false; } } void QmitkDataStorageComboBox::SetSelectedNode(mitk::DataNode::Pointer item) { int index = this->Find(item); if (index == -1) { MITK_INFO << "QmitkDataStorageComboBox: item not available"; } else { this->setCurrentIndex(index); } } //#PROTECTED GETTER bool QmitkDataStorageComboBox::HasIndex(unsigned int index) const { return (m_Nodes.size() > 0 && index < m_Nodes.size()); } int QmitkDataStorageComboBox::Find( const mitk::DataNode* _DataNode ) const { int index = -1; std::vector::const_iterator nodeIt = std::find(m_Nodes.begin(), m_Nodes.end(), _DataNode); if(nodeIt != m_Nodes.end()) index = std::distance(m_Nodes.begin(), nodeIt); return index; } //#PROTECTED SETTER void QmitkDataStorageComboBox::OnCurrentIndexChanged(int index) { if(index >= 0 && index < this->count()) emit OnSelectionChanged(this->GetSelectedNode()); if(index == -1) emit OnSelectionChanged(NULL); } void QmitkDataStorageComboBox::InsertNode(int index, const mitk::DataNode* _DataNode) { // check new or updated node first if(m_Predicate.IsNotNull() && !m_Predicate->CheckNode(_DataNode)) return; bool addNewNode = false; bool insertNewNode = false; bool changedNode = false; // if this->HasIndex(index), then a node shall be updated if(this->HasIndex(index)) { // if we really have another node at this position then ... if(_DataNode != m_Nodes.at(index)) { // ... remove node, then proceed as usual this->RemoveNode(index); insertNewNode = true; } else changedNode = true; } // otherwise a new node shall be added, let index point to the element after the last element else { index = m_Nodes.size(); addNewNode = true; } // const cast because we need non const nodes mitk::DataNode* _NonConstDataNode = const_cast(_DataNode); mitk::BaseProperty* nameProperty = _NonConstDataNode->GetProperty("name"); if(!changedNode) { // break on duplicated nodes (that doesnt make sense to have duplicates in the combobox) if(this->Find(_DataNode) != -1) return; // add modified observer itk::MemberCommand::Pointer modifiedCommand = itk::MemberCommand::New(); modifiedCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnDataNodeDeleteOrModified); // !!!! add modified observer for the name /// property of the node because this is the only thing we are interested in !!!!! if(nameProperty) { m_NodesModifiedObserverTags.push_back( nameProperty->AddObserver(itk::ModifiedEvent(), modifiedCommand) ); m_PropertyToNode[_NonConstDataNode] = nameProperty; } // if there is no name node save an invalid value for the observer tag (-1) else m_NodesModifiedObserverTags.push_back( -1 ); // add delete observer itk::MemberCommand::Pointer deleteCommand = itk::MemberCommand::New(); deleteCommand->SetCallbackFunction(this, &QmitkDataStorageComboBox::OnDataNodeDeleteOrModified); m_NodesDeleteObserverTags.push_back( _NonConstDataNode->AddObserver(itk::DeleteEvent(), modifiedCommand) ); } // add node to the vector if(addNewNode) m_Nodes.push_back( _NonConstDataNode ); else if(insertNewNode) m_Nodes.insert( m_Nodes.begin()+index, _NonConstDataNode ); // ... and to the combobox std::string _NonConstDataNodeName = "unnamed node"; // _NonConstDataNodeName is "unnamed node" so far, change it if there is a name property in the node if(nameProperty) _NonConstDataNodeName = nameProperty->GetValueAsString(); if(addNewNode) { this->addItem(QString::fromStdString(_NonConstDataNodeName)); // select new node if m_AutoSelectNewNodes is true or if we have just added the first node if(m_AutoSelectNewNodes || m_Nodes.size() == 1) this->setCurrentIndex(index); } else { // update text in combobox this->setItemText( index, QString::fromStdString(_NonConstDataNodeName)); } } void QmitkDataStorageComboBox::Init() { connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(OnCurrentIndexChanged(int))); } void QmitkDataStorageComboBox::Reset() { // remove all nodes first while( !m_Nodes.empty() ) { // remove last node this->RemoveNode( m_Nodes.size() - 1 ); } // clear combobox this->clear(); if(m_DataStorage.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer setOfObjects; // select all if predicate == NULL if (m_Predicate.IsNotNull()) setOfObjects = m_DataStorage->GetSubset(m_Predicate); else setOfObjects = m_DataStorage->GetAll(); // add all found nodes for (mitk::DataStorage::SetOfObjects::ConstIterator nodeIt = setOfObjects->Begin() ; nodeIt != setOfObjects->End(); ++nodeIt) // for each _DataNode { // add node to the node vector and to the combobox this->AddNode( nodeIt.Value().GetPointer() ); } } } diff --git a/Modules/QmitkExt/QmitkLineEdit.cpp b/Modules/QmitkExt/QmitkLineEdit.cpp new file mode 100644 index 0000000000..c3a667d038 --- /dev/null +++ b/Modules/QmitkExt/QmitkLineEdit.cpp @@ -0,0 +1,105 @@ +/*=================================================================== + +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 "QmitkLineEdit.h" +#include + +QmitkLineEdit::QmitkLineEdit(QWidget* parent) + : QLineEdit(parent) +{ + this->Initialize(); +} + +QmitkLineEdit::QmitkLineEdit(const QString& defaultText, QWidget* parent) + : QLineEdit(parent), + m_DefaultText(defaultText) +{ + this->Initialize(); +} + +QmitkLineEdit::~QmitkLineEdit() +{ +} + +void QmitkLineEdit::focusInEvent(QFocusEvent* event) +{ + QLineEdit::focusInEvent(event); + emit this->FocusChanged(true); +} + +void QmitkLineEdit::focusOutEvent(QFocusEvent* event) +{ + QLineEdit::focusOutEvent(event); + emit this->FocusChanged(false); +} + +QString QmitkLineEdit::GetDefaultText() const +{ + return m_DefaultText; +} + +void QmitkLineEdit::Initialize() +{ + m_DefaultPalette.setColor(QPalette::Text, QApplication::palette().color(QPalette::Disabled, QPalette::Text)); + + this->ShowDefaultText(true); + + connect(this, SIGNAL(FocusChanged(bool)), this, SLOT(OnFocusChanged(bool))); + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(OnTextChanged(const QString&))); +} + +void QmitkLineEdit::OnFocusChanged(bool hasFocus) +{ + if (hasFocus) + { + if (this->text() == m_DefaultText && this->palette() == m_DefaultPalette) + this->ShowDefaultText(false); + } + else + { + if (this->text().isEmpty()) + this->ShowDefaultText(true); + } +} + +void QmitkLineEdit::OnTextChanged(const QString& text) +{ + if (this->palette() == m_DefaultPalette) + this->setPalette(QPalette()); +} + +void QmitkLineEdit::SetDefaultText(const QString& defaultText) +{ + m_DefaultText = defaultText; +} + +void QmitkLineEdit::ShowDefaultText(bool show) +{ + this->blockSignals(true); + + if (show) + { + this->setPalette(m_DefaultPalette); + this->setText(m_DefaultText); + } + else + { + this->setPalette(QPalette()); + this->clear(); + } + + this->blockSignals(false); +} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.h b/Modules/QmitkExt/QmitkLineEdit.h similarity index 50% rename from Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.h rename to Modules/QmitkExt/QmitkLineEdit.h index 599db72b2e..b0e1f3756a 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.h +++ b/Modules/QmitkExt/QmitkLineEdit.h @@ -1,56 +1,56 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKLINEEDIT_H -#define QMITKLINEEDIT_H +#ifndef QmitkLineEdit_h +#define QmitkLineEdit_h +#include #include -class QmitkLineEdit : public QLineEdit +class QmitkExt_EXPORT QmitkLineEdit : public QLineEdit { Q_OBJECT - - Q_PROPERTY(QString defaultText READ defaultText WRITE setDefaultText) + Q_PROPERTY(QString DefaultText READ GetDefaultText WRITE SetDefaultText FINAL) public: - explicit QmitkLineEdit(QWidget *parent = NULL); - explicit QmitkLineEdit(const QString &defaultText, QWidget *parent = NULL); + explicit QmitkLineEdit(QWidget* parent = NULL); + explicit QmitkLineEdit(const QString& defaultText, QWidget* parent = NULL); ~QmitkLineEdit(); - QString defaultText() const; - void setDefaultText(const QString &defaultText); - -signals: - void focusChanged(bool hasFocus); + QString GetDefaultText() const; + void SetDefaultText(const QString& defaultText); protected: - void focusInEvent(QFocusEvent *event); - void focusOutEvent(QFocusEvent *event); + void focusInEvent(QFocusEvent* event); + void focusOutEvent(QFocusEvent* event); + +private: + void Initialize(); + void ShowDefaultText(bool show); + +signals: + void FocusChanged(bool hasFocus); private slots: - void onFocusChanged(bool hasFocus); - void onTextChanged(const QString &text); + void OnFocusChanged(bool hasFocus); + void OnTextChanged(const QString& text); private: - void initialize(); - void showDefaultText(bool show); - QString m_DefaultText; - QPalette m_Palette; QPalette m_DefaultPalette; }; #endif diff --git a/Modules/QmitkExt/files.cmake b/Modules/QmitkExt/files.cmake index 48eefa8b88..87f13f6fda 100644 --- a/Modules/QmitkExt/files.cmake +++ b/Modules/QmitkExt/files.cmake @@ -1,267 +1,271 @@ set(CPP_FILES QmitkApplicationBase/QmitkCommonFunctionality.cpp QmitkApplicationBase/QmitkIOUtil.cpp #QmitkModels/QmitkDataStorageListModel.cpp #QmitkModels/QmitkPropertiesTableModel.cpp #QmitkModels/QmitkDataStorageTreeModel.cpp #QmitkModels/QmitkDataStorageTableModel.cpp #QmitkModels/QmitkPropertyDelegate.cpp #QmitkModels/QmitkPointListModel.cpp #QmitkAlgorithmFunctionalityComponent.cpp #QmitkBaseAlgorithmComponent.cpp QmitkAboutDialog/QmitkAboutDialog.cpp #QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.cpp #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.cpp #QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.cpp #QmitkFunctionalityComponents/QmitkImageCropperComponent.cpp #QmitkFunctionalityComponents/QmitkSeedPointSetComponent.cpp #QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.cpp QmitkPropertyObservers/QmitkBasePropertyView.cpp QmitkPropertyObservers/QmitkBoolPropertyWidget.cpp QmitkPropertyObservers/QmitkColorPropertyEditor.cpp QmitkPropertyObservers/QmitkColorPropertyView.cpp QmitkPropertyObservers/QmitkEnumerationPropertyWidget.cpp QmitkPropertyObservers/QmitkNumberPropertyEditor.cpp QmitkPropertyObservers/QmitkNumberPropertyView.cpp QmitkPropertyObservers/QmitkPropertyViewFactory.cpp QmitkPropertyObservers/QmitkStringPropertyEditor.cpp QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.cpp QmitkPropertyObservers/QmitkStringPropertyView.cpp QmitkPropertyObservers/QmitkNumberPropertySlider.cpp QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.cpp qclickablelabel.cpp #QmitkAbortEventFilter.cpp # QmitkApplicationCursor.cpp QmitkCallbackFromGUIThread.cpp QmitkEditPointDialog.cpp QmitkExtRegisterClasses.cpp QmitkFileChooser.cpp # QmitkRenderingManager.cpp # QmitkRenderingManagerFactory.cpp # QmitkRenderWindow.cpp # QmitkEventAdapter.cpp QmitkFloatingPointSpanSlider.cpp QmitkColorTransferFunctionCanvas.cpp QmitkSlicesInterpolator.cpp QmitkStandardViews.cpp QmitkStepperAdapter.cpp # QmitkLineEditLevelWindowWidget.cpp # mitkSliderLevelWindowWidget.cpp # QmitkLevelWindowWidget.cpp # QmitkPointListWidget.cpp # QmitkPointListView.cpp QmitkPiecewiseFunctionCanvas.cpp QmitkSliderNavigatorWidget.cpp QmitkTransferFunctionCanvas.cpp QmitkCrossWidget.cpp #QmitkLevelWindowRangeChangeDialog.cpp #QmitkLevelWindowPresetDefinitionDialog.cpp # QmitkLevelWindowWidgetContextMenu.cpp QmitkSliceWidget.cpp # QmitkStdMultiWidget.cpp QmitkTransferFunctionWidget.cpp QmitkTransferFunctionGeneratorWidget.cpp QmitkSelectableGLWidget.cpp QmitkToolReferenceDataSelectionBox.cpp QmitkToolWorkingDataSelectionBox.cpp QmitkToolGUIArea.cpp QmitkToolSelectionBox.cpp # QmitkPropertyListPopup.cpp QmitkToolGUI.cpp QmitkNewSegmentationDialog.cpp QmitkPaintbrushToolGUI.cpp QmitkDrawPaintbrushToolGUI.cpp QmitkErasePaintbrushToolGUI.cpp QmitkBinaryThresholdToolGUI.cpp QmitkCalculateGrayValueStatisticsToolGUI.cpp QmitkCopyToClipBoardDialog.cpp # QmitkMaterialEditor.cpp # QmitkMaterialShowcase.cpp # QmitkPropertiesTableEditor.cpp QmitkPrimitiveMovieNavigatorWidget.cpp # QmitkDataStorageComboBox.cpp QmitkHistogram.cpp QmitkHistogramWidget.cpp QmitkPlotWidget.cpp QmitkPlotDialog.cpp QmitkPointListModel.cpp QmitkPointListView.cpp QmitkPointListWidget.cpp QmitkPointListViewWidget.cpp QmitkCorrespondingPointSetsView.cpp QmitkCorrespondingPointSetsModel.cpp QmitkCorrespondingPointSetsWidget.cpp QmitkVideoBackground.cpp QmitkHotkeyLineEdit.cpp QmitkErodeToolGUI.cpp QmitkDilateToolGUI.cpp QmitkMorphologicToolGUI.cpp QmitkOpeningToolGUI.cpp QmitkClosingToolGUI.cpp QmitkBinaryThresholdULToolGUI.cpp QmitkPixelManipulationToolGUI.cpp QmitkRegionGrow3DToolGUI.cpp QmitkToolRoiDataSelectionBox.cpp QmitkBoundingObjectWidget.cpp QmitkAdaptiveRegionGrowingWidget.cpp QmitkModuleTableModel.cpp QmitkModulesDialog.cpp QmitkHistogramJSWidget.cpp + + QmitkLineEdit.cpp ) if( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) set(CPP_FILES ${CPP_FILES} QmitkVtkHistogramWidget.cpp QmitkVtkLineProfileWidget.cpp ) endif() if(NOT APPLE) set(CPP_FILES ${CPP_FILES} QmitkBaseComponent.cpp QmitkBaseFunctionalityComponent.cpp QmitkFunctionalityComponentContainer.cpp QmitkFunctionalityComponents/QmitkThresholdComponent.cpp ) endif() QT4_ADD_RESOURCES(CPP_FILES resources/QmitkResources.qrc) set(MOC_H_FILES QmitkPropertyObservers/QmitkBasePropertyView.h QmitkPropertyObservers/QmitkBoolPropertyWidget.h QmitkPropertyObservers/QmitkColorPropertyEditor.h QmitkPropertyObservers/QmitkColorPropertyView.h QmitkPropertyObservers/QmitkEnumerationPropertyWidget.h QmitkPropertyObservers/QmitkNumberPropertyEditor.h QmitkPropertyObservers/QmitkNumberPropertyView.h QmitkPropertyObservers/QmitkStringPropertyEditor.h QmitkPropertyObservers/QmitkStringPropertyOnDemandEdit.h QmitkPropertyObservers/QmitkStringPropertyView.h QmitkPropertyObservers/QmitkNumberPropertySlider.h QmitkPropertyObservers/QmitkUGCombinedRepresentationPropertyWidget.h # QmitkFunctionalityComponents/QmitkSurfaceCreatorComponent.h #QmitkFunctionalityComponents/QmitkPixelGreyValueManipulatorComponent.h # QmitkFunctionalityComponents/QmitkConnectivityFilterComponent.h # QmitkFunctionalityComponents/QmitkImageCropperComponent.h # QmitkFunctionalityComponents/QmitkSeedPointSetComponent.h # QmitkFunctionalityComponents/QmitkSurfaceTransformerComponent.h qclickablelabel.h QmitkCallbackFromGUIThread.h QmitkEditPointDialog.h #QmitkAlgorithmFunctionalityComponent.h #QmitkBaseAlgorithmComponent.h QmitkStandardViews.h QmitkStepperAdapter.h QmitkSliderNavigatorWidget.h QmitkSliceWidget.h QmitkSlicesInterpolator.h QmitkColorTransferFunctionCanvas.h QmitkPiecewiseFunctionCanvas.h QmitkTransferFunctionCanvas.h QmitkFloatingPointSpanSlider.h QmitkCrossWidget.h QmitkTransferFunctionWidget.h QmitkTransferFunctionGeneratorWidget.h QmitkToolGUIArea.h QmitkToolGUI.h QmitkToolReferenceDataSelectionBox.h QmitkToolWorkingDataSelectionBox.h QmitkToolSelectionBox.h # QmitkPropertyListPopup.h #QmitkSelectableGLWidget.h QmitkNewSegmentationDialog.h QmitkPaintbrushToolGUI.h QmitkDrawPaintbrushToolGUI.h QmitkErasePaintbrushToolGUI.h QmitkBinaryThresholdToolGUI.h QmitkCalculateGrayValueStatisticsToolGUI.h QmitkCopyToClipBoardDialog.h QmitkPrimitiveMovieNavigatorWidget.h QmitkPlotWidget.h QmitkPointListModel.h QmitkPointListView.h QmitkPointListWidget.h QmitkPointListViewWidget.h QmitkCorrespondingPointSetsView.h QmitkCorrespondingPointSetsModel.h QmitkCorrespondingPointSetsWidget.h QmitkHistogramWidget.h QmitkVideoBackground.h QmitkFileChooser.h QmitkHotkeyLineEdit.h QmitkAboutDialog/QmitkAboutDialog.h QmitkErodeToolGUI.h QmitkDilateToolGUI.h QmitkMorphologicToolGUI.h QmitkOpeningToolGUI.h QmitkClosingToolGUI.h QmitkBinaryThresholdULToolGUI.h QmitkPixelManipulationToolGUI.h QmitkRegionGrow3DToolGUI.h QmitkToolRoiDataSelectionBox.h QmitkBoundingObjectWidget.h QmitkPlotWidget.h QmitkAdaptiveRegionGrowingWidget.h QmitkHistogramJSWidget.h + + QmitkLineEdit.h ) if( NOT ${VTK_MAJOR_VERSION}.${VTK_MINOR_VERSION}.${VTK_BUILD_VERSION} VERSION_LESS 5.4.0 ) set(MOC_H_FILES ${MOC_H_FILES} QmitkVtkHistogramWidget.h QmitkVtkLineProfileWidget.h ) endif() if(NOT APPLE) set(MOC_H_FILES ${MOC_H_FILES} QmitkBaseComponent.h QmitkBaseFunctionalityComponent.h QmitkFunctionalityComponentContainer.h QmitkFunctionalityComponents/QmitkThresholdComponent.h ) endif() set(UI_FILES QmitkSliderNavigator.ui # QmitkLevelWindowRangeChange.ui # QmitkLevelWindowPresetDefinition.ui # QmitkLevelWindowWidget.ui QmitkSliceWidget.ui QmitkTransferFunctionWidget.ui QmitkTransferFunctionGeneratorWidget.ui QmitkSelectableGLWidget.ui QmitkPrimitiveMovieNavigatorWidget.ui QmitkFunctionalityComponentContainerControls.ui QmitkFunctionalityComponents/QmitkThresholdComponentControls.ui QmitkAboutDialog/QmitkAboutDialogGUI.ui QmitkAdaptiveRegionGrowingWidgetControls.ui ) set(QRC_FILES QmitkExt.qrc ) diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp new file mode 100644 index 0000000000..69094bfa56 --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.cpp @@ -0,0 +1,416 @@ +/*=================================================================== + +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 "mitkImageLiveWireContourModelFilter.h" + + +#include +#include +#include + + +mitk::ImageLiveWireContourModelFilter::ImageLiveWireContourModelFilter() +{ + OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() ); + this->SetNumberOfRequiredInputs(1); + this->SetNumberOfOutputs( 1 ); + this->SetNthOutput(0, output.GetPointer()); + m_CostFunction = ImageLiveWireContourModelFilter::CostFunctionType::New(); + m_ShortestPathFilter = ShortestPathImageFilterType::New(); + m_ShortestPathFilter->SetCostFunction(m_CostFunction); + m_UseDynamicCostMap = false; + m_ImageModified = false; + m_Timestep = 0; +} + +mitk::ImageLiveWireContourModelFilter::~ImageLiveWireContourModelFilter() +{ + +} + + +mitk::ImageLiveWireContourModelFilter::OutputType* mitk::ImageLiveWireContourModelFilter::GetOutput() +{ + return Superclass::GetOutput(); +} + +void mitk::ImageLiveWireContourModelFilter::SetInput ( const mitk::ImageLiveWireContourModelFilter::InputType* input ) +{ + this->SetInput( 0, input ); +} + +void mitk::ImageLiveWireContourModelFilter::SetInput ( unsigned int idx, const mitk::ImageLiveWireContourModelFilter::InputType* input ) +{ + if ( idx + 1 > this->GetNumberOfInputs() ) + { + this->SetNumberOfRequiredInputs(idx + 1); + } + if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) ) + { + this->ProcessObject::SetNthInput ( idx, const_cast ( input ) ); + this->Modified(); + this->m_ImageModified = true; + m_ShortestPathFilter = ShortestPathImageFilterType::New(); + m_ShortestPathFilter->SetCostFunction(m_CostFunction); + } +} + + + +const mitk::ImageLiveWireContourModelFilter::InputType* mitk::ImageLiveWireContourModelFilter::GetInput( void ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(0)); +} + + +const mitk::ImageLiveWireContourModelFilter::InputType* mitk::ImageLiveWireContourModelFilter::GetInput( unsigned int idx ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(idx)); +} + + +void mitk::ImageLiveWireContourModelFilter::GenerateData() +{ + mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + + if(!input) + { + MITK_ERROR << "No input available."; + itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!"); + return; + } + + if( input->GetDimension() != 2 ) + { + MITK_ERROR << "Filter is only working on 2D images."; + itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that the input is 2D!"); + return; + } + + + input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex); + input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex); + + //only start calculating if both indices are inside image geometry + if( input->GetGeometry()->IsIndexInside(this->m_StartPointInIndex) && input->GetGeometry()->IsIndexInside(this->m_EndPointInIndex) ) + { + AccessFixedDimensionByItk(input, ItkProcessImage, 2); + m_ImageModified = false; + } +} + + + +template +void mitk::ImageLiveWireContourModelFilter::ItkProcessImage (itk::Image* inputImage) +{ + typedef itk::Image< TPixel, VImageDimension > InputImageType; + typedef typename InputImageType::IndexType IndexType; + + + /* compute the requested region for itk filters */ + + IndexType startPoint, endPoint; + + startPoint[0] = m_StartPointInIndex[0]; + startPoint[1] = m_StartPointInIndex[1]; + + endPoint[0] = m_EndPointInIndex[0]; + endPoint[1] = m_EndPointInIndex[1]; + + //minimum value in each direction for startRegion + IndexType startRegion; + startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0]; + startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1]; + + //maximum value in each direction for size + typename InputImageType::SizeType size; + size[0] = abs( startPoint[0] - endPoint[0] ); + size[1] = abs( startPoint[1] - endPoint[1] ); + + + typename CostFunctionType::RegionType region; + region.SetSize( size ); + region.SetIndex( startRegion ); + /*---------------------------------------------*/ + + //inputImage->SetRequestedRegion(region); + + typedef itk::CastImageFilter< InputImageType, FloatImageType > CastFilterType; + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + castFilter->SetInput(inputImage); + castFilter->Update(); + /* extracts features from image and calculates costs */ + if( m_ImageModified ) + m_CostFunction->SetImage(castFilter->GetOutput()); + m_CostFunction->SetStartIndex(startPoint); + m_CostFunction->SetEndIndex(endPoint); + m_CostFunction->SetRequestedRegion(region); + m_CostFunction->SetUseCostMap(m_UseDynamicCostMap); + /*---------------------------------------------*/ + + + /* calculate shortest path between start and end point */ + m_ShortestPathFilter->SetFullNeighborsMode(true); + m_ShortestPathFilter->SetInput(castFilter->GetOutput()); + m_ShortestPathFilter->SetMakeOutputImage(false); + + //m_ShortestPathFilter->SetCalcAllDistances(true); + m_ShortestPathFilter->SetStartIndex(startPoint); + m_ShortestPathFilter->SetEndIndex(endPoint); + + + m_ShortestPathFilter->Update(); + + /*---------------------------------------------*/ + + + /* construct contour from path image */ + //get the shortest path as vector + typename std::vector< ShortestPathImageFilterType::IndexType> shortestPath = m_ShortestPathFilter->GetVectorPath(); + + //fill the output contour with controll points from the path + OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() ); + this->SetNthOutput(0, output.GetPointer()); + + output->Expand(m_Timestep+1); + + mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + + typename std::vector< ShortestPathImageFilterType::IndexType>::iterator pathIterator = shortestPath.begin(); + + while(pathIterator != shortestPath.end()) + { + mitk::Point3D currentPoint; + currentPoint[0] = (*pathIterator)[0]; + currentPoint[1] = (*pathIterator)[1]; + currentPoint[2] = 0; + + + input->GetGeometry()->IndexToWorld(currentPoint, currentPoint); + output->AddVertex(currentPoint, false, m_Timestep); + + pathIterator++; + } + /*---------------------------------------------*/ +} + +bool mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMap(mitk::ContourModel* path) +{ + mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + if(input) + { + AccessFixedDimensionByItk_1(input,CreateDynamicCostMapByITK, 2, path); + return true; + } + else + { + return false; + } +} + + + +template +void mitk::ImageLiveWireContourModelFilter::CreateDynamicCostMapByITK( itk::Image* inputImage, mitk::ContourModel* path ) +{ + /*++++++++++ create dynamic cost transfer map ++++++++++*/ + + /* Compute the costs of the gradient magnitude dynamically. + * using a map of the histogram of gradient magnitude image. + * Use the histogram gradient map to interpolate the costs + * with gaussing function including next two bins right and left + * to current position x. With the histogram gradient costs are interpolated + * with a gaussing function summation of next two bins right and left + * to current position x. + */ + std::vector< itk::Index > shortestPath; + + mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + if(path == NULL) + { + OutputType::Pointer output = this->GetOutput(); + mitk::ContourModel::VertexIterator it = output->IteratorBegin(); + while( it != output->IteratorEnd() ) + { + itk::Index cur; + mitk::Point3D c = (*it)->Coordinates; + input->GetGeometry()->WorldToIndex(c, c); + cur[0] = c[0]; + cur[1] = c[1]; + + shortestPath.push_back( cur); + it++; + } + } + else + { + + mitk::ContourModel::VertexIterator it = path->IteratorBegin(); + while( it != path->IteratorEnd() ) + { + itk::Index cur; + mitk::Point3D c = (*it)->Coordinates; + input->GetGeometry()->WorldToIndex(c, c); + cur[0] = c[0]; + cur[1] = c[1]; + + shortestPath.push_back( cur); + it++; + } + + } + + + /*+++ filter image gradient magnitude +++*/ + typedef itk::GradientMagnitudeImageFilter< itk::Image, itk::Image > GradientMagnitudeFilterType; + typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); + gradientFilter->SetInput(inputImage); + gradientFilter->Update(); + typename itk::Image::Pointer gradientMagnImage = gradientFilter->GetOutput(); + + //get the path + + + //iterator of path + typename std::vector< itk::Index >::iterator pathIterator = shortestPath.begin(); + + std::map< int, int > histogram; + + //create histogram within path + while(pathIterator != shortestPath.end()) + { + //count pixel values + //use scale factor to avoid mapping gradients between 0.0 and 1.0 to same bin + histogram[ static_cast( gradientMagnImage->GetPixel((*pathIterator)) * ImageLiveWireContourModelFilter::CostFunctionType::MAPSCALEFACTOR ) ] += 1; + + pathIterator++; + } + + double max = 1.0; + + if( !histogram.empty() ) + { + + std::map< int, int >::iterator itMAX; + + //get max of histogramm + int currentMaxValue = 0; + std::map< int, int >::iterator it = histogram.begin(); + while( it != histogram.end()) + { + if((*it).second > currentMaxValue) + { + itMAX = it; + currentMaxValue = (*it).second; + } + it++; + } + + + std::map< int, int >::key_type keyOfMax = itMAX->first; + + + /*+++++++++++++++++++++++++ compute the to max of gaussian summation ++++++++++++++++++++++++*/ + std::map< int, int >::iterator end = histogram.end(); + std::map< int, int >::iterator last = --(histogram.end()); + + std::map< int, int >::iterator left2; + std::map< int, int >::iterator left1; + std::map< int, int >::iterator right1; + std::map< int, int >::iterator right2; + + right1 = itMAX; + + + if(right1 == end || right1 == last ) + { + right2 = end; + } + else//( right1 <= last ) + { + std::map< int, int >::iterator temp = right1; + right2 = ++right1;//rght1 + 1 + right1 = temp; + } + + + if( right1 == histogram.begin() ) + { + left1 = end; + left2 = end; + } + else if( right1 == (++(histogram.begin())) ) + { + std::map< int, int >::iterator temp = right1; + left1 = --right1;//rght1 - 1 + right1 = temp; + left2 = end; + } + else + { + std::map< int, int >::iterator temp = right1; + left1 = --right1;//rght1 - 1 + left2 = --right1;//rght1 - 2 + right1 = temp; + } + + double partRight1, partRight2, partLeft1, partLeft2; + partRight1 = partRight2 = partLeft1 = partLeft2 = 0.0; + + + /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + f(x) = v(bin) * e^ ( -1/2 * (|x-k(bin)| / sigma)^2 ) + + gaussian approximation + + where + v(bin) is the value in the map + k(bin) is the key + */ + if( left2 != end ) + { + partLeft2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left2->first, left2->second); + } + + if( left1 != end ) + { + partLeft1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, left1->first, left1->second); + } + + if( right1 != end ) + { + partRight1 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right1->first, right1->second); + } + + if( right2 != end ) + { + partRight2 = ImageLiveWireContourModelFilter::CostFunctionType::Gaussian(keyOfMax, right2->first, right2->second); + } + /*----------------------------------------------------------------------------*/ + + max = (partRight1 + partRight2 + partLeft1 + partLeft2); + + } + + this->m_CostFunction->SetDynamicCostMap(histogram); + this->m_CostFunction->SetCostMapMaximum(max); + +} diff --git a/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h new file mode 100644 index 0000000000..74ff4fa4e8 --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageLiveWireContourModelFilter.h @@ -0,0 +1,153 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _mitkImageLiveWireContourModelFilter_h__ +#define _mitkImageLiveWireContourModelFilter_h__ + +#include "mitkCommon.h" +#include "SegmentationExports.h" +#include "mitkContourModel.h" +#include "mitkContourModelSource.h" + +#include +#include +#include + +#include +#include + + +namespace mitk { + + /** + + \brief Calculates a LiveWire contour between two points in an image. + + For defining costs between two pixels specific features are extraced from the image and tranformed into a single cost value. + \sa ShortestPathCostFunctionLiveWire + + The filter is able to create dynamic cost tranfer map and thus use on the fly training. + \Note On the fly training will only be used for next update. + The computation uses the last calculated segment to map cost according to features in the area of the segment. + + For time resolved purposes use ImageLiveWireContourModelFilter::SetTimestep( unsigned int ) to create the LiveWire contour + at a specific timestep. + + \ingroup ContourModelFilters + \ingroup Process + */ + class Segmentation_EXPORT ImageLiveWireContourModelFilter : public ContourModelSource + { + + public: + + mitkClassMacro(ImageLiveWireContourModelFilter, ContourModelSource); + itkNewMacro(Self); + + + typedef ContourModel OutputType; + typedef OutputType::Pointer OutputTypePointer; + typedef mitk::Image InputType; + + typedef itk::Image< float, 2 > FloatImageType; + typedef itk::ShortestPathImageFilter< FloatImageType, FloatImageType > ShortestPathImageFilterType; + typedef itk::ShortestPathCostFunctionLiveWire< FloatImageType > CostFunctionType; + + + /** \brief start point in worldcoordinates*/ + itkSetMacro(StartPoint, mitk::Point3D); + itkGetMacro(StartPoint, mitk::Point3D); + + /** \brief end point in woorldcoordinates*/ + itkSetMacro(EndPoint, mitk::Point3D); + itkGetMacro(EndPoint, mitk::Point3D); + + /** \brief Create dynamic cost tranfer map - use on the fly training. + \Note On the fly training will be used for next update only. + The computation uses the last calculated segment to map cost according to features in the area of the segment. + */ + itkSetMacro(UseDynamicCostMap, bool); + itkGetMacro(UseDynamicCostMap, bool); + + + virtual void SetInput( const InputType *input); + + virtual void SetInput( unsigned int idx, const InputType * input); + + const InputType* GetInput(void); + + const InputType* GetInput(unsigned int idx); + + virtual OutputType* GetOutput(); + + + /** \brief Create dynamic cost tranfer map - on the fly training*/ + bool CreateDynamicCostMap(mitk::ContourModel* path=NULL); + + void SetTimestep( unsigned int timestep ) + { + m_Timestep = timestep; + } + + unsigned int GetTimestep() + { + return m_Timestep; + } + + protected: + ImageLiveWireContourModelFilter(); + + virtual ~ImageLiveWireContourModelFilter(); + + void GenerateOutputInformation() {}; + + void GenerateData(); + + /** \brief start point in worldcoordinates*/ + mitk::Point3D m_StartPoint; + + /** \brief end point in woorldcoordinates*/ + mitk::Point3D m_EndPoint; + + /** \brief Start point in index*/ + mitk::Point3D m_StartPointInIndex; + + /** \brief End point in index*/ + mitk::Point3D m_EndPointInIndex; + + /** \brief The cost function to compute costs between two pixels*/ + CostFunctionType::Pointer m_CostFunction; + + /** \brief Shortest path filter according to cost function m_CostFunction*/ + ShortestPathImageFilterType::Pointer m_ShortestPathFilter; + + /** \brief Flag to use a dynmic cost map or not*/ + bool m_UseDynamicCostMap; + + bool m_ImageModified; + + unsigned int m_Timestep; + + template + void ItkProcessImage (itk::Image* inputImage); + + template + void CreateDynamicCostMapByITK(itk::Image* inputImage, mitk::ContourModel* path=NULL); + }; + +} + +#endif diff --git a/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.cpp new file mode 100644 index 0000000000..5468ca98c7 --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.cpp @@ -0,0 +1,76 @@ +/*=================================================================== + +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 "mitkImageToContourModelFilter.h" + + + +mitk::ImageToContourModelFilter::ImageToContourModelFilter() +{ +} + + + +mitk::ImageToContourModelFilter::~ImageToContourModelFilter() +{ + +} + + + +void mitk::ImageToContourModelFilter::SetInput ( const mitk::ImageToContourModelFilter::InputType* input ) +{ + this->SetInput( 0, input ); +} + + + +void mitk::ImageToContourModelFilter::SetInput ( unsigned int idx, const mitk::ImageToContourModelFilter::InputType* input ) +{ + if ( idx + 1 > this->GetNumberOfInputs() ) + { + this->SetNumberOfRequiredInputs(idx + 1); + } + if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) ) + { + this->ProcessObject::SetNthInput ( idx, const_cast ( input ) ); + this->Modified(); + } +} + + + +const mitk::ImageToContourModelFilter::InputType* mitk::ImageToContourModelFilter::GetInput( void ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(0)); +} + + + +const mitk::ImageToContourModelFilter::InputType* mitk::ImageToContourModelFilter::GetInput( unsigned int idx ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(idx)); +} + + +void mitk::ImageToContourModelFilter::GenerateData() +{ + +} diff --git a/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.h b/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.h new file mode 100644 index 0000000000..40fc5d9a4f --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageToContourModelFilter.h @@ -0,0 +1,66 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _mitkImageToContourModelFilter_h__ +#define _mitkImageToContourModelFilter_h__ + +#include "mitkCommon.h" +#include "SegmentationExports.h" +#include "mitkContourModel.h" +#include "mitkContourModelSource.h" +#include + + +namespace mitk { + + /** + * + * \brief Base class for all filters with mitk::Image as input and mitk::ContourModel + * + * \ingroup ContourModelFilters + * \ingroup Process + */ + class Segmentation_EXPORT ImageToContourModelFilter : public ContourModelSource + { + + public: + + mitkClassMacro(ImageToContourModelFilter, ContourModelSource); + itkNewMacro(Self); + + typedef mitk::Image InputType; + + + virtual void SetInput( const InputType *input); + + virtual void SetInput( unsigned int idx, const InputType * input); + + const InputType* GetInput(void); + + const InputType* GetInput(unsigned int idx); + + protected: + ImageToContourModelFilter(); + + virtual ~ImageToContourModelFilter(); + + void GenerateData(); + + }; + +} + +#endif diff --git a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.cpp new file mode 100644 index 0000000000..a9b7a18f0d --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.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 "mitkImageToLiveWireContourFilter.h" + + +#include +#include +#include + + + +mitk::ImageToLiveWireContourFilter::ImageToLiveWireContourFilter() +{ + OutputType::Pointer output = dynamic_cast ( this->MakeOutput( 0 ).GetPointer() ); + this->SetNumberOfRequiredInputs(1); + this->SetNumberOfOutputs( 1 ); + this->SetNthOutput(0, output.GetPointer()); +} + + + +mitk::ImageToLiveWireContourFilter::~ImageToLiveWireContourFilter() +{ + +} + + + +void mitk::ImageToLiveWireContourFilter::SetInput ( const mitk::ImageToLiveWireContourFilter::InputType* input ) +{ + this->SetInput( 0, input ); +} + +void mitk::ImageToLiveWireContourFilter::SetInput ( unsigned int idx, const mitk::ImageToLiveWireContourFilter::InputType* input ) +{ + if ( idx + 1 > this->GetNumberOfInputs() ) + { + this->SetNumberOfRequiredInputs(idx + 1); + } + if ( input != static_cast ( this->ProcessObject::GetInput ( idx ) ) ) + { + this->ProcessObject::SetNthInput ( idx, const_cast ( input ) ); + this->Modified(); + } +} + + + +const mitk::ImageToLiveWireContourFilter::InputType* mitk::ImageToLiveWireContourFilter::GetInput( void ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(0)); +} + + +const mitk::ImageToLiveWireContourFilter::InputType* mitk::ImageToLiveWireContourFilter::GetInput( unsigned int idx ) +{ + if (this->GetNumberOfInputs() < 1) + return NULL; + return static_cast(this->ProcessObject::GetInput(idx)); +} + + + +void mitk::ImageToLiveWireContourFilter::GenerateData() +{ + mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + + if(!input) + { + MITK_ERROR << "No input available."; + itkExceptionMacro("mitk::ImageToLiveWireContourFilter: No input available. Please set the input!"); + return; + } + + if( input->GetDimension() != 2 ) + { + MITK_ERROR << "Filter is only working on 2D images."; + itkExceptionMacro("mitk::ImageToLiveWireContourFilter: Filter is only working on 2D images.. Please make sure that the input is 2D!"); + return; + } + + + input->GetGeometry()->WorldToIndex(m_StartPoint, m_StartPointInIndex); + input->GetGeometry()->WorldToIndex(m_EndPoint, m_EndPointInIndex); + + + AccessFixedDimensionByItk(input, ItkProcessImage, 2); +} + + + +template +void mitk::ImageToLiveWireContourFilter::ItkProcessImage (itk::Image* inputImage) +{ + //typedef itk::Image< TPixel, VImageDimension > InputImageType; + //typedef itk::Image< float, 2 > FloatImageType; + + //typedef typename itk::ShortestPathImageFilter< InputImageType, InputImageType > ShortestPathImageFilterType; + //typedef typename itk::ShortestPathCostFunctionLiveWire< InputImageType > CostFunctionType; + + //typedef InputImageType::IndexType IndexType; + + + ///* compute the requested region for itk filters */ + + //typename IndexType startPoint, endPoint; + // + //startPoint[0] = m_StartPointInIndex[0]; + //startPoint[1] = m_StartPointInIndex[1]; + + //endPoint[0] = m_EndPointInIndex[0]; + //endPoint[1] = m_EndPointInIndex[1]; + + ////minimum value in each direction for startRegion + //typename IndexType startRegion; + //startRegion[0] = startPoint[0] < endPoint[0] ? startPoint[0] : endPoint[0]; + //startRegion[1] = startPoint[1] < endPoint[1] ? startPoint[1] : endPoint[1]; + + ////maximum value in each direction for size + //typename InputImageType::SizeType size; + //size[0] = startPoint[0] > endPoint[0] ? startPoint[0] : endPoint[0]; + //size[1] = startPoint[1] > endPoint[1] ? startPoint[1] : endPoint[1]; + + + //typename InputImageType::RegionType region; + //region.SetSize( size ); + //region.SetIndex( startRegion ); + ///*---------------------------------------------*/ + + + ///* extracts features from image and calculates costs */ + //typename CostFunctionType::Pointer costFunction = CostFunctionType::New(); + //costFunction->SetImage(inputImage); + //costFunction->SetStartIndex(startPoint); + //costFunction->SetEndIndex(endPoint); + //costFunction->SetRequestedRegion(region); + ///*---------------------------------------------*/ + + + ///* calculate shortest path between start and end point */ + //ShortestPathImageFilterType::Pointer shortestPathFilter = ShortestPathImageFilterType::New(); + //shortestPathFilter->SetFullNeighborsMode(true); + //shortestPathFilter->SetInput(inputImage); + //shortestPathFilter->SetMakeOutputImage(true); + //shortestPathFilter->SetStoreVectorOrder(false); + ////shortestPathFilter->SetActivateTimeOut(true); + //shortestPathFilter->SetStartIndex(startPoint); + //shortestPathFilter->SetEndIndex(endPoint); + + //shortestPathFilter->Update(); + + ///*---------------------------------------------*/ + + + ///* construct contour from path image */ + ////get the shortest path as vector + //std::vector< itk::Index<3> > shortestPath = shortestPathFilter->GetVectorPath(); + + ////fill the output contour with controll points from the path + //OutputType::Pointer outputContour = this->GetOutput(); + //mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); + + //std::vector< itk::Index<3> >::iterator pathIterator = shortestPath.begin(); + + //while(pathIterator != shortestPath.end()) + //{ + // mitk::Point3D currentPoint; + // currentPoint[0] = (*pathIterator)[0]; + // currentPoint[1] = (*pathIterator)[1]; + + // input->GetGeometry(0)->IndexToWorld(currentPoint, currentPoint); + // outputContour->AddVertex(currentPoint); + // + // pathIterator++; + //} + /*---------------------------------------------*/ + +} diff --git a/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h new file mode 100644 index 0000000000..eebf622d6b --- /dev/null +++ b/Modules/Segmentation/Algorithms/mitkImageToLiveWireContourFilter.h @@ -0,0 +1,92 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _mitkImageToLiveWireContourFilter_h__ +#define _mitkImageToLiveWireContourFilter_h__ + +#include "mitkCommon.h" +#include "SegmentationExports.h" +#include "mitkContourModel.h" +#include "mitkContourModelSource.h" + +#include +#include +#include + + + + +namespace mitk { + + /** + * + * \brief + * + * \ingroup ContourModelFilters + * \ingroup Process + */ + class Segmentation_EXPORT ImageToLiveWireContourFilter : public ContourModelSource + { + + public: + + mitkClassMacro(ImageToLiveWireContourFilter, ContourModelSource); + itkNewMacro(Self); + + typedef ContourModel OutputType; + typedef OutputType::Pointer OutputTypePointer; + typedef mitk::Image InputType; + + itkSetMacro(StartPoint, mitk::Point3D); + itkGetMacro(StartPoint, mitk::Point3D); + + itkSetMacro(EndPoint, mitk::Point3D); + itkGetMacro(EndPoint, mitk::Point3D); + + + virtual void SetInput( const InputType *input); + + virtual void SetInput( unsigned int idx, const InputType * input); + + const InputType* GetInput(void); + + const InputType* GetInput(unsigned int idx); + + protected: + ImageToLiveWireContourFilter(); + + virtual ~ImageToLiveWireContourFilter(); + + void GenerateData(); + + void GenerateOutputInformation() {}; + + mitk::Point3D m_StartPoint; + mitk::Point3D m_EndPoint; + + mitk::Point3D m_StartPointInIndex; + mitk::Point3D m_EndPointInIndex; + + private: + + template + void ItkProcessImage (itk::Image* inputImage); + + + }; + +} +#endif diff --git a/Modules/Segmentation/CMakeLists.txt b/Modules/Segmentation/CMakeLists.txt index 133b39a60c..f156909325 100644 --- a/Modules/Segmentation/CMakeLists.txt +++ b/Modules/Segmentation/CMakeLists.txt @@ -1,10 +1,10 @@ #configure_file(${PROJECT_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in $#{PROJECT_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) #configure_file(${PROJECT_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in $#{PROJECT_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) #configure_file(${PROJECT_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in $#{PROJECT_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) MITK_CREATE_MODULE( Segmentation INCLUDE_DIRS Algorithms Controllers DataManagement Interactions IO Rendering - DEPENDS Mitk ipSegmentation mitkIpFunc MitkExt + DEPENDS Mitk ipSegmentation mitkIpFunc MitkExt MitkGraphAlgorithms ) add_subdirectory(Testing) \ No newline at end of file diff --git a/Modules/Segmentation/DataManagement/mitkContourElement.cpp b/Modules/Segmentation/DataManagement/mitkContourElement.cpp index 02357705ba..747103e930 100644 --- a/Modules/Segmentation/DataManagement/mitkContourElement.cpp +++ b/Modules/Segmentation/DataManagement/mitkContourElement.cpp @@ -1,351 +1,345 @@ /*=================================================================== 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 mitk::ContourElement::ContourElement() { this->m_Vertices = new VertexListType(); this->m_IsClosed = false; } mitk::ContourElement::ContourElement(const mitk::ContourElement &other) : m_Vertices(other.m_Vertices), m_IsClosed(other.m_IsClosed) { } mitk::ContourElement::~ContourElement() { delete this->m_Vertices; } void mitk::ContourElement::AddVertex(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_back(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertex(VertexType &vertex) { this->m_Vertices->push_back(&vertex); } void mitk::ContourElement::AddVertexAtFront(mitk::Point3D &vertex, bool isControlPoint) { this->m_Vertices->push_front(new VertexType(vertex, isControlPoint)); } void mitk::ContourElement::AddVertexAtFront(VertexType &vertex) { this->m_Vertices->push_front(&vertex); } void mitk::ContourElement::InsertVertexAtIndex(mitk::Point3D &vertex, bool isControlPoint, int index) { if(index > 0 && this->GetSize() > index) { VertexIterator _where = this->m_Vertices->begin(); _where += index; this->m_Vertices->insert(_where, new VertexType(vertex, isControlPoint)); } } mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(int index) { return this->m_Vertices->at(index); } mitk::ContourElement::VertexType* mitk::ContourElement::GetVertexAt(const mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should some kind of an octree with spatial query*/ if(eps > 0) { - if(true ) //currently no method with better performance is available - { - return BruteForceGetVertexAt(point, eps); - } - else - { - return OptimizedGetVertexAt(point, eps); - } + //currently no method with better performance is available + return BruteForceGetVertexAt(point, eps); }//if eps < 0 return NULL; } mitk::ContourElement::VertexType* mitk::ContourElement::BruteForceGetVertexAt(const mitk::Point3D &point, float eps) { if(eps > 0) { std::deque< std::pair > nearestlist; ConstVertexIterator it = this->m_Vertices->begin(); ConstVertexIterator end = this->m_Vertices->end(); while(it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; double distance = currentPoint.EuclideanDistanceTo(point); if(distance < eps) { //if list is emtpy, add point to list if(nearestlist.size() < 1) { nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) )); } //found an approximate point - check if current is closer then first in nearestlist else if( distance < nearestlist.front().first ) { //found even closer vertex nearestlist.push_front(std::pair( (*it)->Coordinates.EuclideanDistanceTo(point), (*it) )); } }//if distance > eps it++; }//while if(nearestlist.size() > 0) { /*++++++++++++++++++++ return the nearest active point if one was found++++++++++++++++++*/ std::deque< std::pair >::iterator it = nearestlist.begin(); std::deque< std::pair >::iterator end = nearestlist.end(); while(it != end) { if( (*it).second->IsControlPoint ) { return (*it).second; } it++; } /*---------------------------------------------------------------------------------------*/ //return closest point return nearestlist.front().second; } } return NULL; } mitk::ContourElement::VertexType* mitk::ContourElement::OptimizedGetVertexAt(const mitk::Point3D &point, float eps) { if( (eps > 0) && (this->m_Vertices->size()>0) ) { int k = 1; int dim = 3; int nPoints = this->m_Vertices->size(); ANNpointArray pointsArray; ANNpoint queryPoint; ANNidxArray indexArray; ANNdistArray distanceArray; ANNkd_tree* kdTree; queryPoint = annAllocPt(dim); pointsArray = annAllocPts(nPoints, dim); indexArray = new ANNidx[k]; distanceArray = new ANNdist[k]; int i = 0; //fill points array with our control points for(VertexIterator it = this->m_Vertices->begin(); it != this->m_Vertices->end(); it++, i++) { mitk::Point3D cur = (*it)->Coordinates; pointsArray[i][0]= cur[0]; pointsArray[i][1]= cur[1]; pointsArray[i][2]= cur[2]; } //create the kd tree kdTree = new ANNkd_tree(pointsArray,nPoints, dim); //fill mitk::Point3D into ANN query point queryPoint[0] = point[0]; queryPoint[1] = point[1]; queryPoint[2] = point[2]; //k nearest neighbour search kdTree->annkSearch(queryPoint, k, indexArray, distanceArray, eps); VertexType* ret = NULL; try { ret = this->m_Vertices->at(indexArray[0]); } catch(std::out_of_range ex) { //ret stays NULL return ret; } //clean up ANN delete [] indexArray; delete [] distanceArray; delete kdTree; annClose(); return ret; } return NULL; } mitk::ContourElement::VertexListType* mitk::ContourElement::GetVertexList() { return this->m_Vertices; } bool mitk::ContourElement::IsClosed() { return this->m_IsClosed; } void mitk::ContourElement::Close() { this->m_IsClosed = true; } void mitk::ContourElement::Open() { this->m_IsClosed = false; } void mitk::ContourElement::SetIsClosed( bool isClosed) { isClosed ? this->Close() : this->Open(); } void mitk::ContourElement::Concatenate(mitk::ContourElement* other) { if( other->GetSize() > 0) { ConstVertexIterator it = other->m_Vertices->begin(); ConstVertexIterator end = other->m_Vertices->end(); //add all vertices of other after last vertex while(it != end) { this->m_Vertices->push_back(*it); it++; } } } bool mitk::ContourElement::RemoveVertex(mitk::ContourElement::VertexType* vertex) { VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); //search for vertex and remove it if exists while(it != end) { if((*it) == vertex) { this->m_Vertices->erase(it); return true; } it++; } return false; } bool mitk::ContourElement::RemoveVertexAt(int index) { if( index >= 0 && index < this->m_Vertices->size() ) { this->m_Vertices->erase(this->m_Vertices->begin()+index); return true; } else { return false; } } bool mitk::ContourElement::RemoveVertexAt(mitk::Point3D &point, float eps) { /* current version iterates over the whole deque - should be some kind of an octree with spatial query*/ if(eps > 0){ VertexIterator it = this->m_Vertices->begin(); VertexIterator end = this->m_Vertices->end(); while(it != end) { mitk::Point3D currentPoint = (*it)->Coordinates; if(currentPoint.EuclideanDistanceTo(point) < eps) { //approximate point found //now erase it this->m_Vertices->erase(it); return true; } it++; } } return false; } void mitk::ContourElement::Clear() { this->m_Vertices->clear(); } diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp new file mode 100644 index 0000000000..71fdceeff9 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.cpp @@ -0,0 +1,349 @@ +/*=================================================================== + +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 "mitkContourModelLiveWireInteractor.h" + +#include "mitkToolManager.h" + +#include "mitkBaseRenderer.h" +#include "mitkRenderingManager.h" + +#include +#include + +#include + + +mitk::ContourModelLiveWireInteractor::ContourModelLiveWireInteractor(DataNode* dataNode) +:ContourModelInteractor(dataNode) +{ + m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New(); + + mitk::ContourModel::Pointer m_ContourLeft = mitk::ContourModel::New(); + mitk::ContourModel::Pointer m_ContourRight = mitk::ContourModel::New(); + m_NextActiveVertexDown.Fill(0); + m_NextActiveVertexUp.Fill(0); +} + + +mitk::ContourModelLiveWireInteractor::~ContourModelLiveWireInteractor() +{ +} + + + +bool mitk::ContourModelLiveWireInteractor::OnCheckPointClick( Action* action, const StateEvent* stateEvent) +{ + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) { + this->HandleEvent( new mitk::StateEvent(EIDNO, stateEvent->GetEvent()) ); + return false; + } + + + + mitk::StateEvent* newStateEvent = NULL; + + int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); + + mitk::ContourModel *contour = dynamic_cast( + m_DataNode->GetData() ); + + + contour->Deselect(); + + /* + * Check distance to any vertex. + * Transition YES if click close to a vertex + */ + mitk::Point3D click = positionEvent->GetWorldPosition(); + + + if (contour->SelectVertexAt(click, 1.5, timestep) ) + { + contour->SetSelectedVertexAsControlPoint(); + + assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent()); + m_lastMousePosition = click; + + + mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); + + // + m_ContourLeft = mitk::ContourModel::New(); + + //get coordinates of next active vertex downwards from selected vertex + int downIndex = SplitContourFromSelectedVertex( contour, m_ContourLeft, false, timestep); + + mitk::ContourModel::VertexIterator itDown = contour->IteratorBegin() + downIndex; + m_NextActiveVertexDown = (*itDown)->Coordinates; + + + // + m_ContourRight = mitk::ContourModel::New(); + + //get coordinates of next active vertex upwards from selected vertex + int upIndex = SplitContourFromSelectedVertex( contour, m_ContourRight, true, timestep); + + mitk::ContourModel::VertexIterator itUp = contour->IteratorBegin() + upIndex; + m_NextActiveVertexUp = (*itUp)->Coordinates; + + } + else + { + newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); + } + + this->HandleEvent( newStateEvent ); + + return true; +} + + + +bool mitk::ContourModelLiveWireInteractor::OnDeletePoint( Action* action, const StateEvent* stateEvent) +{ + + int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); + + mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); + + if(contour->GetSelectedVertex()) + { + + mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); + newContour->Expand(contour->GetTimeSteps()); + newContour->Concatenate( m_ContourLeft, timestep ); + + + //recompute contour between neighbored two active control points + this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown ); + this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp ); + this->m_LiveWireFilter->Update(); + + mitk::ContourModel::Pointer liveWireContour = mitk::ContourModel::New(); + liveWireContour = this->m_LiveWireFilter->GetOutput(); + + + //insert new liveWire computed points + newContour->Concatenate( liveWireContour, timestep ); + + newContour->Concatenate( m_ContourRight, timestep ); + + newContour->SetIsClosed(contour->IsClosed(timestep), timestep); + + m_DataNode->SetData(newContour); + + + assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + + } + return true; +} + + + + +bool mitk::ContourModelLiveWireInteractor::OnMovePoint( Action* action, const StateEvent* stateEvent) +{ + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) return false; + + int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); + + mitk::ContourModel *contour = dynamic_cast( m_DataNode->GetData() ); + + mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); + newContour->Expand(contour->GetTimeSteps()); + + /*++++++++++++++ concatenate LEFT ++++++++++++++++++++++++++++++*/ + newContour->Concatenate( m_ContourLeft, timestep ); + + + mitk::Point3D currentPosition = positionEvent->GetWorldPosition(); + + + /*+++++++++++++++ start computation ++++++++++++++++++++*/ + //recompute contour between previous active vertex and selected vertex + this->m_LiveWireFilter->SetStartPoint( m_NextActiveVertexDown ); + this->m_LiveWireFilter->SetEndPoint( currentPosition ); + this->m_LiveWireFilter->Update(); + + mitk::ContourModel::Pointer liveWireContour = mitk::ContourModel::New(); + liveWireContour = this->m_LiveWireFilter->GetOutput(); + + //remove point at current position because it is included in next livewire segment too. + liveWireContour->RemoveVertexAt( liveWireContour->GetNumberOfVertices(timestep) - 1, timestep); + + /*++++++++++++++ concatenate LIVEWIRE ++++++++++++++++++++++++++++++*/ + //insert new liveWire computed points + newContour->Concatenate( liveWireContour, timestep ); + + + //recompute contour between selected vertex and next active vertex + this->m_LiveWireFilter->SetStartPoint( currentPosition ); + this->m_LiveWireFilter->SetEndPoint( m_NextActiveVertexUp ); + this->m_LiveWireFilter->Update(); + + liveWireContour = this->m_LiveWireFilter->GetOutput(); + + //make point at mouse position active again, so it is drawn + const_cast( liveWireContour->GetVertexAt(0, timestep) )->IsControlPoint = true; + + /*++++++++++++++ concatenate RIGHT ++++++++++++++++++++++++++++++*/ + //insert new liveWire computed points + newContour->Concatenate( liveWireContour, timestep ); + /*------------------------------------------------*/ + + + newContour->Concatenate( m_ContourRight, timestep ); + + newContour->SetIsClosed(contour->IsClosed(timestep), timestep); + newContour->Deselect();//just to make sure + m_DataNode->SetData(newContour); + + this->m_lastMousePosition = positionEvent->GetWorldPosition(); + + assert( positionEvent->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); + + return true; +} + + + +int mitk::ContourModelLiveWireInteractor::SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour, mitk::ContourModel* destinationContour, bool fromSelectedUpwards, int timestep) +{ + + mitk::ContourModel::VertexIterator end =sourceContour->IteratorEnd(); + mitk::ContourModel::VertexIterator begin =sourceContour->IteratorBegin(); + + //search next active control point to left and rigth and set as start and end point for filter + mitk::ContourModel::VertexIterator itSelected = sourceContour->IteratorBegin(); + + + //move iterator to position + while((*itSelected) != sourceContour->GetSelectedVertex()) + { + itSelected++; + } + + //CASE search upwards for next control point + if(fromSelectedUpwards) + { + mitk::ContourModel::VertexIterator itUp = itSelected; + + if(itUp != end) + { + itUp++;//step once up otherwise the the loop breaks immediately + } + + while( itUp != end && !((*itUp)->IsControlPoint)){ itUp++; } + + mitk::ContourModel::VertexIterator it = itUp; + + + if(itSelected != begin) + { + //copy the rest of the original contour + while(it != end) + { + destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); + it++; + } + } + //else do not copy the contour + + + //return the offset of iterator at one before next-vertex-upwards + if(itUp != begin) + { + return std::distance( begin, itUp) - 1; + } + else + { + return std::distance( begin, itUp); + } + + } + else //CASE search downwards for next control point + { + mitk::ContourModel::VertexIterator itDown = itSelected; + mitk::ContourModel::VertexIterator it = sourceContour->IteratorBegin(); + + if( itSelected != begin ) + { + if(itDown != begin) + { + itDown--;//step once down otherwise the the loop breaks immediately + } + + while( itDown != begin && !((*itDown)->IsControlPoint)){ itDown--; } + + if(it != end)//if not empty + { + //always add the first vertex + destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); + it++; + } + //copy from begin to itDown + while(it <= itDown) + { + destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); + it++; + } + } + else + { + //if selected vertex is the first element search from end of contour downwards + itDown = end; + itDown--; + while(!((*itDown)->IsControlPoint)){itDown--;} + + //move one forward as we don't want the first control point + it++; + //move iterator to second control point + while( (it!=end) && !((*it)->IsControlPoint) ){it++;} + //copy from begin to itDown + while(it <= itDown) + { + //copy the contour from second control point to itDown + destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); + it++; + } + } + + + //add vertex at itDown - it's not considered during while loop + if( it != begin && it != end) + { + //destinationContour->AddVertex( (*it)->Coordinates, (*it)->IsControlPoint, timestep); + } + + //return the offset of iterator at one after next-vertex-downwards + if( itDown != end) + { + return std::distance( begin, itDown);// + 1;//index of next vertex + } + else + { + return std::distance( begin, itDown) - 1; + } + } +} diff --git a/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h new file mode 100644 index 0000000000..ae44899f95 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkContourModelLiveWireInteractor.h @@ -0,0 +1,89 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkContourModelLiveWireInteractor_h_Included +#define mitkContourModelLiveWireInteractor_h_Included + +#include "mitkCommon.h" +#include "SegmentationExports.h" +#include "mitkContourModelInteractor.h" +#include +#include + +#include + +namespace mitk +{ + + + /** + \brief + + \sa Interactor + \sa ContourModelInteractor + + \ingroup Interaction + + + \warning Make sure the working image is properly set, otherwise the algorithm for computing livewire contour segments will not work! + + */ + class Segmentation_EXPORT ContourModelLiveWireInteractor : public ContourModelInteractor + { + public: + + mitkClassMacro(ContourModelLiveWireInteractor, ContourModelInteractor); + mitkNewMacro1Param(Self, DataNode*); + + + virtual void SetWorkingImage (mitk::Image* _arg) + { + if (this->m_WorkingImage != _arg) + { + this->m_WorkingImage = _arg; + this->m_LiveWireFilter->SetInput(this->m_WorkingImage); + this->Modified(); + } + } + + protected: + + ContourModelLiveWireInteractor(DataNode* dataNode); + virtual ~ContourModelLiveWireInteractor(); + + + virtual bool OnDeletePoint(Action*, const StateEvent*); + virtual bool OnMovePoint(Action*, const StateEvent*); + virtual bool OnCheckPointClick( Action* action, const StateEvent* stateEvent); + + int SplitContourFromSelectedVertex(mitk::ContourModel* sourceContour, + mitk::ContourModel* destinationContour, + bool fromSelectedUpwards, + int timestep); + + mitk::ImageLiveWireContourModelFilter::Pointer m_LiveWireFilter; + mitk::Image::Pointer m_WorkingImage; + + mitk::Point3D m_NextActiveVertexDown; + mitk::Point3D m_NextActiveVertexUp; + mitk::ContourModel::Pointer m_ContourLeft; + mitk::ContourModel::Pointer m_ContourRight; + + }; + +} // namespace + +#endif diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp new file mode 100644 index 0000000000..20082f9f8e --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp @@ -0,0 +1,653 @@ +/*=================================================================== + +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 "mitkLiveWireTool2D.h" + +#include "mitkToolManager.h" +#include "mitkBaseRenderer.h" +#include "mitkRenderingManager.h" + +#include "mitkLiveWireTool2D.xpm" + +#include +#include +#include + +#include "mitkContourUtils.h" +#include "mitkContour.h" + +#include + + +namespace mitk { + MITK_TOOL_MACRO(Segmentation_EXPORT, LiveWireTool2D, "LiveWire tool"); +} + + + +mitk::LiveWireTool2D::LiveWireTool2D() +:SegTool2D("LiveWireTool") +{ + m_Contour = mitk::ContourModel::New(); + m_ContourModelNode = mitk::DataNode::New(); + m_ContourModelNode->SetData( m_Contour ); + m_ContourModelNode->SetProperty("name", StringProperty::New("working contour node")); + m_ContourModelNode->SetProperty("visible", BoolProperty::New(true)); + m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(0.9, 1.0, 0.1), NULL, true ); + m_ContourModelNode->AddProperty( "selectedcolor", ColorProperty::New(1.0, 0.0, 0.1), NULL, true ); + + + m_LiveWireContour = mitk::ContourModel::New(); + m_LiveWireContourNode = mitk::DataNode::New(); + //m_LiveWireContourNode->SetData( m_LiveWireContour ); + m_LiveWireContourNode->SetProperty("name", StringProperty::New("active livewire node")); + m_LiveWireContourNode->SetProperty("visible", BoolProperty::New(true)); + m_LiveWireContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true ); + m_LiveWireContourNode->AddProperty( "selectedcolor", ColorProperty::New(0.5, 0.5, 0.1), NULL, true ); + + + m_LiveWireFilter = mitk::ImageLiveWireContourModelFilter::New(); + + + // great magic numbers + CONNECT_ACTION( AcINITNEWOBJECT, OnInitLiveWire ); + CONNECT_ACTION( AcADDPOINT, OnAddPoint ); + CONNECT_ACTION( AcMOVE, OnMouseMoveNoDynamicCosts ); + CONNECT_ACTION( AcCHECKPOINT, OnCheckPoint ); + CONNECT_ACTION( AcFINISH, OnFinish ); + CONNECT_ACTION( AcDELETEPOINT, OnLastSegmentDelete ); + CONNECT_ACTION( AcADDLINE, OnMouseMoved ); +} + + + + +mitk::LiveWireTool2D::~LiveWireTool2D() +{ + m_Contours.clear(); +} + + + +float mitk::LiveWireTool2D::CanHandleEvent( StateEvent const *stateEvent) const +{ + mitk::PositionEvent const *positionEvent = + dynamic_cast (stateEvent->GetEvent()); + + //Key event handling: + if (positionEvent == NULL) + { + //check for delete and escape event + if(stateEvent->GetId() == 12 || stateEvent->GetId() == 14) + { + return 1.0; + } + //check, if the current state has a transition waiting for that key event. + else if (this->GetCurrentState()->GetTransition(stateEvent->GetId())!=NULL) + { + return 0.5; + } + else + { + return 0.0; + } + } + else + { + if ( positionEvent->GetSender()->GetMapperID() != BaseRenderer::Standard2D ) + return 0.0; // we don't want anything but 2D + + return 1.0; + } + +} + + + + +const char** mitk::LiveWireTool2D::GetXPM() const +{ + return mitkLiveWireTool2D_xpm; +} + + + + +const char* mitk::LiveWireTool2D::GetName() const +{ + return "LiveWire"; +} + + + + +void mitk::LiveWireTool2D::Activated() +{ + Superclass::Activated(); +} + + + + +void mitk::LiveWireTool2D::Deactivated() +{ + this->FinishTool(); + + DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); + if ( !workingNode ) return; + + Image* workingImage = dynamic_cast(workingNode->GetData()); + if ( !workingImage ) return; + + ContourUtils::Pointer contourUtils = mitk::ContourUtils::New(); + + /*+++++++++++++++++++++++ for all contours in list (currently created by tool) ++++++++++++++++++++++++++++++++++++*/ + std::vector< std::pair >::iterator it = m_Contours.begin(); + while(it != m_Contours.end() ) + { + + //++++++++++if node contains data + if( it->first->GetData() ) + { + + //+++++++++++++++if this is a contourModel + mitk::ContourModel* contourModel = dynamic_cast(it->first->GetData()); + if( contourModel ) + { + + //++++++++++++++++++++++ for each timestep of this contourModel + for( int currentTimestep = 0; currentTimestep < contourModel->GetTimeSlicedGeometry()->GetTimeSteps(); currentTimestep++) + { + + //get the segmentation image slice at current timestep + mitk::Image::Pointer workingSlice = this->GetAffectedImageSliceAs2DImage(it->second, workingImage, currentTimestep); + + /*++++++++++++++++++++++ transfer to plain old contour to use contour util functionality +++++++++++++++++++++++*/ + mitk::Contour::Pointer plainOldContour = mitk::Contour::New(); + mitk::ContourModel::VertexIterator iter = contourModel->IteratorBegin(currentTimestep); + while(iter != contourModel->IteratorEnd(currentTimestep) ) + { + plainOldContour->AddVertex( (*iter)->Coordinates ); + iter++; + } + /*-------------------------------------------------------------------------------*/ + + + mitk::Contour::Pointer projectedContour = contourUtils->ProjectContourTo2DSlice(workingSlice, plainOldContour, true, false); + contourUtils->FillContourInSlice(projectedContour, workingSlice, 1.0); + + //write back to image volume + this->WriteBackSegmentationResult(it->second, workingSlice, currentTimestep); + } + + //remove contour node from datastorage + m_ToolManager->GetDataStorage()->Remove( it->first ); + } + } + + ++it; + } + + m_Contours.clear(); + + Superclass::Deactivated(); +} + + + + +bool mitk::LiveWireTool2D::OnInitLiveWire (Action* action, const StateEvent* stateEvent) +{ + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) return false; + + m_LastEventSender = positionEvent->GetSender(); + m_LastEventSlice = m_LastEventSender->GetSlice(); + + if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false; + + + int timestep = positionEvent->GetSender()->GetTimeStep(); + + m_Contour->Expand(timestep+1); + + m_ToolManager->GetDataStorage()->Add( m_ContourModelNode ); + + m_ToolManager->GetDataStorage()->Add( m_LiveWireContourNode ); + + //set current slice as input for ImageToLiveWireContourFilter + m_WorkingSlice = this->GetAffectedReferenceSlice(positionEvent); + m_LiveWireFilter->SetInput(m_WorkingSlice); + + //map click to pixel coordinates + mitk::Point3D click = const_cast(positionEvent->GetWorldPosition()); + itk::Index<3> idx; + m_WorkingSlice->GetGeometry()->WorldToIndex(click, idx); + + /*+++++++++++++++++++++++ get the pixel the gradient in region of 5x5 ++++++++++++++++++++++++++*/ + itk::Index<3> indexWithHighestGradient; + AccessFixedDimensionByItk_2(m_WorkingSlice, FindHighestGradientMagnitudeByITK, 2, idx, indexWithHighestGradient); + /*----------------------------------------------------------------------------------------------------------------*/ + + //itk::Index to mitk::Point3D + click[0] = indexWithHighestGradient[0]; + click[1] = indexWithHighestGradient[1]; + click[2] = indexWithHighestGradient[2]; + m_WorkingSlice->GetGeometry()->IndexToWorld(click, click); + + //set initial start point + m_Contour->AddVertex( click, true, timestep ); + m_LiveWireFilter->SetStartPoint(click); + + m_CreateAndUseDynamicCosts = true; + + //render + assert( positionEvent->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); + + return true; +} + + + + +bool mitk::LiveWireTool2D::OnAddPoint (Action* action, const StateEvent* stateEvent) +{ + //complete LiveWire interaction for last segment + //add current LiveWire contour to the finished contour and reset + //to start new segment and computation + + /* check if event can be handled */ + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) return false; + + if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false; + /* END check if event can be handled */ + + + int timestep = positionEvent->GetSender()->GetTimeStep(); + + //remove duplicate first vertex, it's already contained in m_Contour + m_LiveWireContour->RemoveVertexAt(0, timestep); + + + /* TODO fix this hack*/ + //set last to active added point + if( m_LiveWireContour->GetNumberOfVertices(timestep) > 0) + { + const_cast( m_LiveWireContour->GetVertexAt(m_LiveWireContour->GetNumberOfVertices(timestep)-1, timestep) )->IsControlPoint = true; + } + + //merge contours + m_Contour->Concatenate(m_LiveWireContour, timestep); + + + //clear the livewire contour and reset the corresponding datanode + m_LiveWireContour->Clear(timestep); + + //set new start point + m_LiveWireFilter->SetStartPoint(const_cast(positionEvent->GetWorldPosition())); + + if( m_CreateAndUseDynamicCosts ) + { + //use dynamic cost map for next update + m_LiveWireFilter->CreateDynamicCostMap(m_Contour); + m_LiveWireFilter->SetUseDynamicCostMap(true); + //m_CreateAndUseDynamicCosts = false; + } + + //render + assert( positionEvent->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); + + return true; +} + + + + +bool mitk::LiveWireTool2D::OnMouseMoved( Action* action, const StateEvent* stateEvent) +{ + //compute LiveWire segment from last control point to current mouse position + + /* check if event can be handled */ + if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false; + + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) return false; + /* END check if event can be handled */ + + + /* actual LiveWire computation */ + int timestep = positionEvent->GetSender()->GetTimeStep(); + + m_LiveWireFilter->SetEndPoint(const_cast(positionEvent->GetWorldPosition())); + + m_LiveWireFilter->SetTimestep(timestep); + m_LiveWireFilter->Update(); + + + //ContourModel::VertexType* currentVertex = const_cast(m_LiveWireContour->GetVertexAt(0)); + + this->m_LiveWireContour = this->m_LiveWireFilter->GetOutput(); + this->m_LiveWireContourNode->SetData(this->m_LiveWireFilter->GetOutput()); + + /* END actual LiveWire computation */ + + //render + assert( positionEvent->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( positionEvent->GetSender()->GetRenderWindow() ); + + return true; +} + + + +bool mitk::LiveWireTool2D::OnMouseMoveNoDynamicCosts(Action* action, const StateEvent* stateEvent) +{ + //do not use dynamic cost map + m_LiveWireFilter->SetUseDynamicCostMap(false); + OnMouseMoved(action, stateEvent); + m_LiveWireFilter->SetUseDynamicCostMap(true); + return true; +} + + + + + +bool mitk::LiveWireTool2D::OnCheckPoint( Action* action, const StateEvent* stateEvent) +{ + //check double click on first control point to finish the LiveWire tool + // + //Check distance to first point. + //Transition YES if click close to first control point + // + + mitk::StateEvent* newStateEvent = NULL; + + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) + { + //stay in current state + newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); + } + else + { + int timestep = positionEvent->GetSender()->GetTimeStep(); + + mitk::Point3D click = positionEvent->GetWorldPosition(); + + mitk::Point3D first = this->m_Contour->GetVertexAt(0, timestep)->Coordinates; + + + if (first.EuclideanDistanceTo(click) < 1.5) + { + //finish + newStateEvent = new mitk::StateEvent(EIDYES, stateEvent->GetEvent()); + }else + { + //stay active + newStateEvent = new mitk::StateEvent(EIDNO, stateEvent->GetEvent()); + } + } + + this->HandleEvent( newStateEvent ); + + + return true; +} + + + + +bool mitk::LiveWireTool2D::OnFinish( Action* action, const StateEvent* stateEvent) +{ + // finish livewire tool interaction + + /* check if event can be handled */ + if ( Superclass::CanHandleEvent(stateEvent) < 1.0 ) return false; + + const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); + if (!positionEvent) return false; + /* END check if event can be handled */ + + + //actual timestep + int timestep = positionEvent->GetSender()->GetTimeStep(); + + //remove last control point being added by double click + m_Contour->RemoveVertexAt(m_Contour->GetNumberOfVertices(timestep) - 1, timestep); + + //save contour and corresponding plane geometry to list + std::pair contourPair(m_ContourModelNode.GetPointer(), dynamic_cast(positionEvent->GetSender()->GetCurrentWorldGeometry2D()->Clone().GetPointer()) ); + m_Contours.push_back(contourPair); + + m_LiveWireFilter->SetUseDynamicCostMap(false); + this->FinishTool(); + + return true; +} + + + +void mitk::LiveWireTool2D::FinishTool() +{ + + unsigned int numberOfTimesteps = m_Contour->GetTimeSlicedGeometry()->GetTimeSteps(); + + //close contour in each timestep + for( int i = 0; i <= numberOfTimesteps; i++) + { + m_Contour->Close(i); + } + + //clear LiveWire node + m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode ); + m_LiveWireContourNode = NULL; + m_LiveWireContour = NULL; + + + //TODO visual feedback for completing livewire tool + m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(1.0, 1.0, 0.1), NULL, true ); + m_ContourModelNode->SetProperty("name", StringProperty::New("contour node")); + + //set the livewire interactor to edit control points + mitk::ContourModelLiveWireInteractor::Pointer interactor = mitk::ContourModelLiveWireInteractor::New(m_ContourModelNode); + interactor->SetWorkingImage(this->m_WorkingSlice); + m_ContourModelNode->SetInteractor(interactor); + + //add interactor to globalInteraction instance + mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); + /* END complete livewire tool interaction */ + + + /* reset contours and datanodes */ + m_Contour = mitk::ContourModel::New(); + m_ContourModelNode = mitk::DataNode::New(); + m_ContourModelNode->SetData( m_Contour ); + m_ContourModelNode->SetProperty("name", StringProperty::New("working contour node")); + m_ContourModelNode->SetProperty("visible", BoolProperty::New(true)); + m_ContourModelNode->AddProperty( "contour.color", ColorProperty::New(0.9, 1.0, 0.1), NULL, true ); + m_ContourModelNode->AddProperty( "points.color", ColorProperty::New(1.0, 0.0, 0.1), NULL, true ); + + m_LiveWireContour = mitk::ContourModel::New(); + m_LiveWireContourNode = mitk::DataNode::New(); + //m_LiveWireContourNode->SetData( m_LiveWireContour ); + m_LiveWireContourNode->SetProperty("name", StringProperty::New("active livewire node")); + m_LiveWireContourNode->SetProperty("visible", BoolProperty::New(true)); + m_LiveWireContourNode->AddProperty( "contour.color", ColorProperty::New(0.1, 1.0, 0.1), NULL, true ); + m_LiveWireContourNode->AddProperty( "points.color", ColorProperty::New(0.5, 0.5, 0.1), NULL, true ); + /* END reset contours and datanodes */ +} + + + + +bool mitk::LiveWireTool2D::OnLastSegmentDelete( Action* action, const StateEvent* stateEvent) +{ + int timestep = stateEvent->GetEvent()->GetSender()->GetTimeStep(); + + //if last point of current contour will be removed go to start state and remove nodes + if( m_Contour->GetNumberOfVertices(timestep) <= 1 ) + { + m_ToolManager->GetDataStorage()->Remove( m_LiveWireContourNode ); + m_ToolManager->GetDataStorage()->Remove( m_ContourModelNode ); + m_LiveWireContour = mitk::ContourModel::New(); + m_Contour = mitk::ContourModel::New(); + m_ContourModelNode->SetData( m_Contour ); + m_LiveWireContourNode->SetData( m_LiveWireContour ); + Superclass::Deactivated(); //go to start state + } + else //remove last segment from contour and reset livewire contour + { + + m_LiveWireContour = mitk::ContourModel::New(); + + m_LiveWireContourNode->SetData(m_LiveWireContour); + + + mitk::ContourModel::Pointer newContour = mitk::ContourModel::New(); + newContour->Expand(m_Contour->GetTimeSteps()); + + mitk::ContourModel::VertexIterator begin = m_Contour->IteratorBegin(); + + //iterate from last point to next active point + mitk::ContourModel::VertexIterator newLast = m_Contour->IteratorBegin() + (m_Contour->GetNumberOfVertices() - 1); + + //go at least one down + if(newLast != begin) + { + newLast--; + } + + //search next active control point + while(newLast != begin && !((*newLast)->IsControlPoint) ) + { + newLast--; + } + + //set position of start point for livewire filter to coordinates of the new last point + m_LiveWireFilter->SetStartPoint((*newLast)->Coordinates); + + mitk::ContourModel::VertexIterator it = m_Contour->IteratorBegin(); + + //fill new Contour + while(it <= newLast) + { + newContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, timestep); + it++; + } + + newContour->SetIsClosed(m_Contour->IsClosed()); + + //set new contour visible + m_ContourModelNode->SetData(newContour); + + m_Contour = newContour; + + assert( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + mitk::RenderingManager::GetInstance()->RequestUpdate( stateEvent->GetEvent()->GetSender()->GetRenderWindow() ); + } + + return true; +} + + +template +void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image* inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex) +{ + typedef itk::Image InputImageType; + typedef typename InputImageType::IndexType IndexType; + + unsigned long xMAX = inputImage->GetLargestPossibleRegion().GetSize()[0]; + unsigned long yMAX = inputImage->GetLargestPossibleRegion().GetSize()[1]; + + returnIndex[0] = index[0]; + returnIndex[1] = index[1]; + returnIndex[2] = 0.0; + + + double gradientMagnitude = 0.0; + double maxGradientMagnitude = 0.0; + + /* + the size and thus the region of 7x7 is only used to calculate the gradient magnitude in that region + not for searching the maximum value + */ + + //maximum value in each direction for size + typename InputImageType::SizeType size; + size[0] = 7; + size[1] = 7; + + //minimum value in each direction for startRegion + IndexType startRegion; + startRegion[0] = index[0] - 3; + startRegion[1] = index[1] - 3; + if(startRegion[0] < 0) startRegion[0] = 0; + if(startRegion[1] < 0) startRegion[1] = 0; + if(xMAX - index[0] < 7) startRegion[0] = xMAX - 7; + if(yMAX - index[1] < 7) startRegion[1] = yMAX - 7; + + index[0] = startRegion[0] + 3; + index[1] = startRegion[1] + 3; + + + + typename InputImageType::RegionType region; + region.SetSize( size ); + region.SetIndex( startRegion ); + + typedef typename itk::GradientMagnitudeImageFilter< InputImageType, InputImageType> GradientMagnitudeFilterType; + typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); + gradientFilter->SetInput(inputImage); + gradientFilter->GetOutput()->SetRequestedRegion(region); + + gradientFilter->Update(); + typename InputImageType::Pointer gradientMagnImage; + gradientMagnImage = gradientFilter->GetOutput(); + + + IndexType currentIndex; + currentIndex[0] = 0; + currentIndex[1] = 0; + + // search max (approximate) gradient magnitude + for( int x = -1; x <= 1; ++x) + { + currentIndex[0] = index[0] + x; + + for( int y = -1; y <= 1; ++y) + { + currentIndex[1] = index[1] + y; + + gradientMagnitude = gradientMagnImage->GetPixel(currentIndex); + + //check for new max + if(maxGradientMagnitude < gradientMagnitude) + { + maxGradientMagnitude = gradientMagnitude; + returnIndex[0] = currentIndex[0]; + returnIndex[1] = currentIndex[1]; + returnIndex[2] = 0.0; + }//end if + }//end for y + + currentIndex[1] = index[1]; + }//end for x + +} diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.h b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.h new file mode 100644 index 0000000000..99366a5b80 --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.h @@ -0,0 +1,121 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkCorrectorTool2D_h_Included +#define mitkCorrectorTool2D_h_Included + +#include "mitkCommon.h" +#include "SegmentationExports.h" +#include "mitkSegTool2D.h" +#include +#include + +#include + +namespace mitk +{ + + +/** + \brief A 2D segmentation tool based on LiveWire approach. + The contour between the last user added point and the current mouse position + is computed by searching the shortest path according to specific features of + the image. The contour thus snappest to the boundary of objects. + + + \sa SegTool2D + \sa ImageLiveWireContourModelFilter + + \ingroup Interaction + \ingroup ToolManagerEtAl + + \warning Only to be instantiated by mitk::ToolManager. +*/ +class Segmentation_EXPORT LiveWireTool2D : public SegTool2D +{ + public: + + mitkClassMacro(LiveWireTool2D, SegTool2D); + itkNewMacro(LiveWireTool2D); + + virtual const char** GetXPM() const; + virtual const char* GetName() const; + + protected: + + LiveWireTool2D(); + virtual ~LiveWireTool2D(); + + /** + * \brief Calculates how good the data, this statemachine handles, is hit by the event. + * + */ + virtual float CanHandleEvent( StateEvent const *stateEvent) const; + + virtual void Activated(); + virtual void Deactivated(); + + /// \brief Initialize tool + virtual bool OnInitLiveWire (Action*, const StateEvent*); + + /// \brief Add a control point and finish current segment + virtual bool OnAddPoint (Action*, const StateEvent*); + + /// \breif Actual LiveWire computation + virtual bool OnMouseMoved(Action*, const StateEvent*); + + /// \brief Check double click on first control point to finish the LiveWire tool + virtual bool OnCheckPoint(Action*, const StateEvent*); + + /// \brief Finish LiveWire tool + virtual bool OnFinish(Action*, const StateEvent*); + + /// \brief Close the contour + virtual bool OnLastSegmentDelete(Action*, const StateEvent*); + + /// \brief Don't use dynamic cost map for LiveWire calculation + virtual bool OnMouseMoveNoDynamicCosts(Action*, const StateEvent*); + + /// \brief Finish contour interaction. + void FinishTool(); + + + //the contour already set by the user + mitk::ContourModel::Pointer m_Contour; + //the corresponding datanode + mitk::DataNode::Pointer m_ContourModelNode; + + //the current LiveWire computed contour + mitk::ContourModel::Pointer m_LiveWireContour; + //the corresponding datanode + mitk::DataNode::Pointer m_LiveWireContourNode; + + //the current reference image + mitk::Image::Pointer m_WorkingSlice; + + mitk::ImageLiveWireContourModelFilter::Pointer m_LiveWireFilter; + + bool m_CreateAndUseDynamicCosts; + + std::vector< std::pair > m_Contours; + + template + void FindHighestGradientMagnitudeByITK(itk::Image* inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex); +}; + +} // namespace + +#endif diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.xpm b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.xpm new file mode 100644 index 0000000000..e5c4a22a1a --- /dev/null +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.xpm @@ -0,0 +1,99 @@ +/* XPM */ +static const char * mitkLiveWireTool2D_xpm[] = { +"24 24 72 1", +" c None", +". c #179FBF", +"+ c #01AAD2", +"@ c #00AAD3", +"# c #0BA4CA", +"$ c #14A0C1", +"% c #11A2C4", +"& c #06A7CE", +"* c #0AA5CB", +"= c #2895B1", +"- c #229AB5", +"; c #02A9D1", +"> c #0DA3C8", +", c #1F99B7", +"' c #2598B5", +") c #0CA4C9", +"! c #13A1C2", +"~ c #03A8D0", +"{ c #2795B1", +"] c #179EBF", +"^ c #04A9D0", +"/ c #1C9BBA", +"( c #2497B3", +"_ c #1E9AB9", +": c #209AB9", +"< c #13A0C3", +"[ c #03A9D1", +"} c #189DBE", +"| c #07A7CD", +"1 c #1A9CBC", +"2 c #1E9BBA", +"3 c #2699B4", +"4 c #2498B4", +"5 c #229AB6", +"6 c #0EA3C8", +"7 c #07A7CE", +"8 c #189EBE", +"9 c #1C9CBA", +"0 c #04A7CF", +"a c #11A1C5", +"b c #07A6CD", +"c c #09A6CC", +"d c #2A94AD", +"e c #1C9CBB", +"f c #1E9BB8", +"g c #259AB4", +"h c #05A7CE", +"i c #2E92A9", +"j c #0EA2C6", +"k c #3A8FA2", +"l c #1B9CBC", +"m c #1D9BB9", +"n c #169FC1", +"o c #00A9D2", +"p c #1D9BBA", +"q c #2B94AC", +"r c #16A0C1", +"s c #10A2C6", +"t c #209BB9", +"u c #1D9CBB", +"v c #179FC0", +"w c #000000", +"x c #219AB4", +"y c #FFFFFF", +"z c #F3F6F1", +"A c #189EC0", +"B c #00AAD2", +"C c #16A7BC", +"D c #17A0BF", +"E c #2299B7", +"F c #1D9BB8", +"G c #1A9CBD", +" .+@#$%&@*= ", +" -;>, '); ", +" !~{ &) ", +" ]^ /@ ", +" (@_ :@ ", +" <[ }| ", +" @1 +2 ", +" @345 67 ", +" +@890 a^ ", +" }bcdef gh|i ", +" jk&@l(mn^op ", +" qr+@@@@st ", +" u& ", +" 0vwwwwwwwww ", +" @xwwwyyzyzww ", +" ABwwwwzzzzzzww ", +" oCwwwwwwwwzzzw ", +" D@ wwzzw ", +" c@@@ wzzw ", +" EFG wwzzw ", +" wwwwwwwwzzzw ", +" wwwwzzzzzyww ", +" wwwwyyyyyww ", +" wwwwwwwwww "}; diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp index 739ed49b80..48a6c64515 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.cpp @@ -1,373 +1,400 @@ /*=================================================================== 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 "mitkSegTool2D.h" #include "mitkToolManager.h" #include "mitkDataStorage.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkExtractImageFilter.h" #include "mitkExtractDirectedPlaneImageFilter.h" //Include of the new ImageExtractor #include "mitkExtractDirectedPlaneImageFilterNew.h" #include "mitkPlanarCircle.h" #include "mitkOverwriteSliceImageFilter.h" #include "mitkOverwriteDirectedPlaneImageFilter.h" #include "mitkGetModuleContext.h" //Includes for 3DSurfaceInterpolation #include "mitkImageToContourFilter.h" #include "mitkSurfaceInterpolationController.h" //includes for resling and overwriting #include #include #include #include #include #include "mitkOperationEvent.h" #include "mitkUndoController.h" #define ROUND(a) ((a)>0 ? (int)((a)+0.5) : -(int)(0.5-(a))) mitk::SegTool2D::SegTool2D(const char* type) :Tool(type), - m_LastEventSender(NULL), - m_LastEventSlice(0), - m_Contourmarkername ("Position"), - m_ShowMarkerNodes (false), - m_3DInterpolationEnabled(true) +m_LastEventSender(NULL), +m_LastEventSlice(0), +m_Contourmarkername ("Position"), +m_ShowMarkerNodes (false), +m_3DInterpolationEnabled(true) { } mitk::SegTool2D::~SegTool2D() { } float mitk::SegTool2D::CanHandleEvent( StateEvent const *stateEvent) const { const PositionEvent* positionEvent = dynamic_cast(stateEvent->GetEvent()); if (!positionEvent) return 0.0; if ( positionEvent->GetSender()->GetMapperID() != BaseRenderer::Standard2D ) return 0.0; // we don't want anything but 2D //This are the mouse event that are used by the statemachine patterns for zooming and panning. This must be possible although a tool is activ if (stateEvent->GetId() == EIDRIGHTMOUSEBTN || stateEvent->GetId() == EIDMIDDLEMOUSEBTN || stateEvent->GetId() == EIDRIGHTMOUSEBTNANDCTRL || - stateEvent->GetId() == EIDMIDDLEMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSEBTNANDMOUSEMOVE || - stateEvent->GetId() == EIDMIDDLEMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNRELEASE ) + stateEvent->GetId() == EIDMIDDLEMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSERELEASE || stateEvent->GetId() == EIDRIGHTMOUSEBTNANDMOUSEMOVE || + stateEvent->GetId() == EIDMIDDLEMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE || stateEvent->GetId() == EIDCTRLANDRIGHTMOUSEBTNRELEASE ) { //Since the usual segmentation tools currently do not need right click interaction but the mitkDisplayVectorInteractor return 0.0; } else { return 1.0; } } bool mitk::SegTool2D::DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ) { assert(image); assert(plane); // compare normal of plane to the three axis vectors of the image Vector3D normal = plane->GetNormal(); Vector3D imageNormal0 = image->GetSlicedGeometry()->GetAxisVector(0); Vector3D imageNormal1 = image->GetSlicedGeometry()->GetAxisVector(1); Vector3D imageNormal2 = image->GetSlicedGeometry()->GetAxisVector(2); normal.Normalize(); imageNormal0.Normalize(); imageNormal1.Normalize(); imageNormal2.Normalize(); imageNormal0.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal0.Get_vnl_vector()) ); imageNormal1.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal1.Get_vnl_vector()) ); imageNormal2.Set_vnl_vector( vnl_cross_3d(normal.Get_vnl_vector(),imageNormal2.Get_vnl_vector()) ); double eps( 0.00001 ); // axial if ( imageNormal2.GetNorm() <= eps ) { affectedDimension = 2; } // sagittal else if ( imageNormal1.GetNorm() <= eps ) { affectedDimension = 1; } // frontal else if ( imageNormal0.GetNorm() <= eps ) { affectedDimension = 0; } else { affectedDimension = -1; // no idea return false; } // determine slice number in image Geometry3D* imageGeometry = image->GetGeometry(0); Point3D testPoint = imageGeometry->GetCenter(); Point3D projectedPoint; plane->Project( testPoint, projectedPoint ); Point3D indexPoint; imageGeometry->WorldToIndex( projectedPoint, indexPoint ); affectedSlice = ROUND( indexPoint[affectedDimension] ); MITK_DEBUG << "indexPoint " << indexPoint << " affectedDimension " << affectedDimension << " affectedSlice " << affectedSlice; // check if this index is still within the image if ( affectedSlice < 0 || affectedSlice >= static_cast(image->GetDimension(affectedDimension)) ) return false; return true; } + mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PositionEvent* positionEvent, const Image* image) { if (!positionEvent) return NULL; assert( positionEvent->GetSender() ); // sure, right? unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); // get the timestep of the visible part (time-wise) of the image // first, we determine, which slice is affected const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); + return this->GetAffectedImageSliceAs2DImage(planeGeometry, image, timeStep); +} + + +mitk::Image::Pointer mitk::SegTool2D::GetAffectedImageSliceAs2DImage(const PlaneGeometry* planeGeometry, const Image* image, unsigned int timeStep) +{ if ( !image || !planeGeometry ) return NULL; //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //set to false to extract a slice reslice->SetOverwriteMode(false); reslice->Modified(); //use ExtractSliceFilter with our specific vtkImageReslice for overwriting and extracting mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( timeStep ); extractor->SetWorldGeometry( planeGeometry ); extractor->SetVtkOutputRequest(false); extractor->SetResliceTransformByGeometry( image->GetTimeSlicedGeometry()->GetGeometry3D( timeStep ) ); extractor->Modified(); extractor->Update(); Image::Pointer slice = extractor->GetOutput(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the non edited slice m_undoOperation = new DiffSliceOperation(const_cast(image), extractor->GetVtkOutput(), slice->GetGeometry(), timeStep, const_cast(planeGeometry)); /*============= END undo feature block ========================*/ return slice; } + mitk::Image::Pointer mitk::SegTool2D::GetAffectedWorkingSlice(const PositionEvent* positionEvent) { DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); if ( !workingNode ) return NULL; Image* workingImage = dynamic_cast(workingNode->GetData()); if ( !workingImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, workingImage ); } + mitk::Image::Pointer mitk::SegTool2D::GetAffectedReferenceSlice(const PositionEvent* positionEvent) { DataNode* referenceNode( m_ToolManager->GetReferenceData(0) ); if ( !referenceNode ) return NULL; Image* referenceImage = dynamic_cast(referenceNode->GetData()); if ( !referenceImage ) return NULL; return GetAffectedImageSliceAs2DImage( positionEvent, referenceImage ); } void mitk::SegTool2D::WriteBackSegmentationResult (const PositionEvent* positionEvent, Image* slice) { + if(!positionEvent) return; + const PlaneGeometry* planeGeometry( dynamic_cast (positionEvent->GetSender()->GetCurrentWorldGeometry2D() ) ); + if( planeGeometry && slice) + { + DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); + Image* image = dynamic_cast(workingNode->GetData()); + unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); + this->WriteBackSegmentationResult(planeGeometry, slice, timeStep); + + slice->DisconnectPipeline(); + ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New(); + contourExtractor->SetInput(slice); + contourExtractor->Update(); + mitk::Surface::Pointer contour = contourExtractor->GetOutput(); + + if (m_3DInterpolationEnabled && contour->GetVtkPolyData()->GetNumberOfPoints() > 0 ) + { + unsigned int pos = this->AddContourmarker(positionEvent); + mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); + PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); + mitk::SurfaceInterpolationController::GetInstance()->AddNewContour( contour, service->GetPlanePosition(pos)); + contour->DisconnectPipeline(); + } + } + +} + + +void mitk::SegTool2D::WriteBackSegmentationResult (const PlaneGeometry* planeGeometry, Image* slice, unsigned int timeStep) +{ + if(!planeGeometry || !slice) return; + + DataNode* workingNode( m_ToolManager->GetWorkingData(0) ); Image* image = dynamic_cast(workingNode->GetData()); - unsigned int timeStep = positionEvent->GetSender()->GetTimeStep( image ); - //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer + //Make sure that for reslicing and overwriting the same alogrithm is used. We can specify the mode of the vtk reslicer vtkSmartPointer reslice = vtkSmartPointer::New(); //Set the slice as 'input' reslice->SetInputSlice(slice->GetVtkImageData()); //set overwrite mode to true to write back to the image volume reslice->SetOverwriteMode(true); reslice->Modified(); mitk::ExtractSliceFilter::Pointer extractor = mitk::ExtractSliceFilter::New(reslice); extractor->SetInput( image ); extractor->SetTimeStep( timeStep ); extractor->SetWorldGeometry( planeGeometry ); extractor->SetVtkOutputRequest(true); extractor->SetResliceTransformByGeometry( image->GetTimeSlicedGeometry()->GetGeometry3D( timeStep ) ); extractor->Modified(); extractor->Update(); //the image was modified within the pipeline, but not marked so image->Modified(); image->GetVtkImageData()->Modified(); /*============= BEGIN undo feature block ========================*/ //specify the undo operation with the edited slice m_doOperation = new DiffSliceOperation(image, extractor->GetVtkOutput(),slice->GetGeometry(), timeStep, const_cast(planeGeometry)); //create an operation event for the undo stack OperationEvent* undoStackItem = new OperationEvent( DiffSliceOperationApplier::GetInstance(), m_doOperation, m_undoOperation, "Segmentation" ); //add it to the undo controller UndoController::GetCurrentUndoModel()->SetOperationEvent( undoStackItem ); //clear the pointers as the operation are stored in the undocontroller and also deleted from there m_undoOperation = NULL; m_doOperation = NULL; /*============= END undo feature block ========================*/ - slice->DisconnectPipeline(); - ImageToContourFilter::Pointer contourExtractor = ImageToContourFilter::New(); - contourExtractor->SetInput(slice); - contourExtractor->Update(); - mitk::Surface::Pointer contour = contourExtractor->GetOutput(); - - if (m_3DInterpolationEnabled) - { - unsigned int pos = this->AddContourmarker(positionEvent); - mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); - PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); - mitk::SurfaceInterpolationController::GetInstance()->AddNewContour( contour, service->GetPlanePosition(pos)); - contour->DisconnectPipeline(); - } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } void mitk::SegTool2D::SetShowMarkerNodes(bool status) { - m_ShowMarkerNodes = status; + m_ShowMarkerNodes = status; } void mitk::SegTool2D::SetEnable3DInterpolation(bool enabled) { m_3DInterpolationEnabled = enabled; } unsigned int mitk::SegTool2D::AddContourmarker ( const PositionEvent* positionEvent ) { const mitk::Geometry2D* plane = dynamic_cast (dynamic_cast< const mitk::SlicedGeometry3D*>( positionEvent->GetSender()->GetSliceNavigationController()->GetCurrentGeometry3D())->GetGeometry2D(0)); mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); PlanePositionManagerService* service = dynamic_cast(mitk::GetModuleContext()->GetService(serviceRef)); unsigned int size = service->GetNumberOfPlanePositions(); unsigned int id = service->AddNewPlanePosition(plane, positionEvent->GetSender()->GetSliceNavigationController()->GetSlice()->GetPos()); mitk::PlanarCircle::Pointer contourMarker = mitk::PlanarCircle::New(); mitk::Point2D p1; plane->Map(plane->GetCenter(), p1); mitk::Point2D p2 = p1; p2[0] -= plane->GetSpacing()[0]; p2[1] -= plane->GetSpacing()[1]; contourMarker->PlaceFigure( p1 ); contourMarker->SetCurrentControlPoint( p1 ); contourMarker->SetGeometry2D( const_cast(plane)); std::stringstream markerStream; mitk::DataNode* workingNode (m_ToolManager->GetWorkingData(0)); markerStream << m_Contourmarkername ; markerStream << " "; markerStream << id+1; DataNode::Pointer rotatedContourNode = DataNode::New(); rotatedContourNode->SetData(contourMarker); rotatedContourNode->SetProperty( "name", StringProperty::New(markerStream.str()) ); rotatedContourNode->SetProperty( "isContourMarker", BoolProperty::New(true)); rotatedContourNode->SetBoolProperty( "PlanarFigureInitializedWindow", true, positionEvent->GetSender() ); rotatedContourNode->SetProperty( "includeInBoundingBox", BoolProperty::New(false)); rotatedContourNode->SetProperty( "helper object", mitk::BoolProperty::New(!m_ShowMarkerNodes)); rotatedContourNode->SetProperty( "planarfigure.drawcontrolpoints", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawname", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawoutline", BoolProperty::New(false)); rotatedContourNode->SetProperty( "planarfigure.drawshadow", BoolProperty::New(false)); if (plane) { if ( id == size ) { m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } else { - mitk::NodePredicateProperty::Pointer isMarker = mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)); - - mitk::DataStorage::SetOfObjects::ConstPointer markers = m_ToolManager->GetDataStorage()->GetDerivations(workingNode,isMarker); - - for ( mitk::DataStorage::SetOfObjects::const_iterator iter = markers->begin(); - iter != markers->end(); - ++iter) + mitk::NodePredicateProperty::Pointer isMarker = mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true)); + + mitk::DataStorage::SetOfObjects::ConstPointer markers = m_ToolManager->GetDataStorage()->GetDerivations(workingNode,isMarker); + + for ( mitk::DataStorage::SetOfObjects::const_iterator iter = markers->begin(); + iter != markers->end(); + ++iter) + { + std::string nodeName = (*iter)->GetName(); + unsigned int t = nodeName.find_last_of(" "); + unsigned int markerId = atof(nodeName.substr(t+1).c_str())-1; + if(id == markerId) { - std::string nodeName = (*iter)->GetName(); - unsigned int t = nodeName.find_last_of(" "); - unsigned int markerId = atof(nodeName.substr(t+1).c_str())-1; - if(id == markerId) - { - return id; - } + return id; } - m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); + } + m_ToolManager->GetDataStorage()->Add(rotatedContourNode, workingNode); } } return id; } void mitk::SegTool2D::InteractiveSegmentationBugMessage( const std::string& message ) { MITK_ERROR << "********************************************************************************" << std::endl << " " << message << std::endl << "********************************************************************************" << std::endl << " " << std::endl << " If your image is rotated or the 2D views don't really contain the patient image, try to press the button next to the image selection. " << std::endl << " " << std::endl << " Please file a BUG REPORT: " << std::endl << " http://bugs.mitk.org" << std::endl << " Contain the following information:" << std::endl << " - What image were you working on?" << std::endl << " - Which region of the image?" << std::endl << " - Which tool did you use?" << std::endl << " - What did you do?" << std::endl << " - What happened (not)? What did you expect?" << std::endl; } - diff --git a/Modules/Segmentation/Interactions/mitkSegTool2D.h b/Modules/Segmentation/Interactions/mitkSegTool2D.h index fa039ef25a..e49e148054 100644 --- a/Modules/Segmentation/Interactions/mitkSegTool2D.h +++ b/Modules/Segmentation/Interactions/mitkSegTool2D.h @@ -1,145 +1,151 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSegTool2D_h_Included #define mitkSegTool2D_h_Included #include "mitkCommon.h" #include "SegmentationExports.h" #include "mitkTool.h" #include "mitkImage.h" #include "mitkStateEvent.h" #include "mitkPositionEvent.h" #include "mitkPlanePositionManager.h" #include "mitkRestorePlanePositionOperation.h" #include "mitkInteractionConst.h" #include namespace mitk { class BaseRenderer; /** \brief Abstract base class for segmentation tools. \sa Tool \ingroup Interaction \ingroup ToolManagerEtAl Implements 2D segmentation specific helper methods, that might be of use to all kind of 2D segmentation tools. At the moment these are: - Determination of the slice where the user paints upon (DetermineAffectedImageSlice) - Projection of a 3D contour onto a 2D plane/slice SegTool2D tries to structure the interaction a bit. If you pass "PressMoveRelease" as the interaction type of your derived tool, you might implement the methods OnMousePressed, OnMouseMoved, and OnMouseReleased. Yes, your guess about when they are called is correct. \warning Only to be instantiated by mitk::ToolManager. $Author$ */ class Segmentation_EXPORT SegTool2D : public Tool { public: mitkClassMacro(SegTool2D, Tool); /** \brief Calculates for a given Image and PlaneGeometry, which slice of the image (in index corrdinates) is meant by the plane. \return false, if no slice direction seems right (e.g. rotated planes) \param affectedDimension The image dimension, which is constant for all points in the plane, e.g. Axial --> 2 \param affectedSlice The index of the image slice */ static bool DetermineAffectedImageSlice( const Image* image, const PlaneGeometry* plane, int& affectedDimension, int& affectedSlice ); void SetShowMarkerNodes(bool); /** * \brief Enables or disables the 3D interpolation after writing back the 2D segmentation result, and defaults to true. */ void SetEnable3DInterpolation(bool); protected: SegTool2D(); // purposely hidden SegTool2D(const char*); // purposely hidden virtual ~SegTool2D(); /** * \brief Calculates how good the data, this statemachine handles, is hit by the event. * */ virtual float CanHandleEvent( StateEvent const *stateEvent) const; /** \brief Extract the slice of an image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position. */ Image::Pointer GetAffectedImageSliceAs2DImage(const PositionEvent*, const Image* image); + /** + \brief Extract the slice of an image cut by given plane. + \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position. + */ + Image::Pointer GetAffectedImageSliceAs2DImage(const PlaneGeometry* planeGeometry, const Image* image, unsigned int timeStep); + /** \brief Extract the slice of the currently selected working image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no working image is selected. */ Image::Pointer GetAffectedWorkingSlice(const PositionEvent*); /** \brief Extract the slice of the currently selected reference image that the user just scribbles on. \return NULL if SegTool2D is either unable to determine which slice was affected, or if there was some problem getting the image data at that position, or just no reference image is selected. */ Image::Pointer GetAffectedReferenceSlice(const PositionEvent*); void WriteBackSegmentationResult (const PositionEvent*, Image*); + void WriteBackSegmentationResult (const PlaneGeometry* planeGeometry, Image*, unsigned int timeStep); + /** \brief Adds a new node called Contourmarker to the datastorage which holds a mitk::PlanarFigure. By selecting this node the slicestack will be reoriented according to the PlanarFigure's Geometry */ unsigned int AddContourmarker ( const PositionEvent* ); void InteractiveSegmentationBugMessage( const std::string& message ); BaseRenderer* m_LastEventSender; unsigned int m_LastEventSlice; private: //The prefix of the contourmarkername. Suffix is a consecutive number const std::string m_Contourmarkername; bool m_ShowMarkerNodes; bool m_3DInterpolationEnabled; DiffSliceOperation* m_doOperation; DiffSliceOperation* m_undoOperation; }; } // namespace #endif - - diff --git a/Modules/Segmentation/Rendering/mitkContourModelGLMapper2D.cpp b/Modules/Segmentation/Rendering/mitkContourModelGLMapper2D.cpp index 4cf207e539..62f3632b67 100644 --- a/Modules/Segmentation/Rendering/mitkContourModelGLMapper2D.cpp +++ b/Modules/Segmentation/Rendering/mitkContourModelGLMapper2D.cpp @@ -1,277 +1,280 @@ /*=================================================================== 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 "mitkContourModelGLMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkPlaneGeometry.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkContourModel.h" #include "mitkContourModelSubDivisionFilter.h" #include #include "mitkGL.h" mitk::ContourModelGLMapper2D::ContourModelGLMapper2D() { } mitk::ContourModelGLMapper2D::~ContourModelGLMapper2D() { } void mitk::ContourModelGLMapper2D::Paint(mitk::BaseRenderer * renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; bool updateNeccesary=true; int timestep = renderer->GetTimeStep(); mitk::ContourModel::Pointer input = const_cast(this->GetInput()); mitk::ContourModel::Pointer renderingContour = input; bool subdivision = false; this->GetDataNode()->GetBoolProperty( "subdivision curve", subdivision, renderer ); if (subdivision) { mitk::ContourModel::Pointer subdivContour = mitk::ContourModel::New(); mitk::ContourModelSubDivisionFilter::Pointer subdivFilter = mitk::ContourModelSubDivisionFilter::New(); subdivFilter->SetInput(input); subdivFilter->Update(); subdivContour = subdivFilter->GetOutput(); if(subdivContour->GetNumberOfVertices() == 0 ) { subdivContour = input; } renderingContour = subdivContour; } renderingContour->UpdateOutputInformation(); if( renderingContour->GetMTime() < this->m_LastUpdateTime ) updateNeccesary = false; if(renderingContour->GetNumberOfVertices(timestep) < 1) updateNeccesary = false; if (updateNeccesary) { // ok, das ist aus GenerateData kopiert mitk::DisplayGeometry::Pointer displayGeometry = renderer->GetDisplayGeometry(); assert(displayGeometry.IsNotNull()); //apply color and opacity read from the PropertyList ApplyProperties(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty("contour.color", renderer)); if(colorprop) { //set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); glColor4f(red,green,blue,0.5); } mitk::ColorProperty::Pointer selectedcolor = dynamic_cast(GetDataNode()->GetProperty("points.color", renderer)); if(!selectedcolor) { selectedcolor = mitk::ColorProperty::New(1.0,0.0,0.1); } vtkLinearTransform* transform = GetDataNode()->GetVtkTransform(); // ContourModel::OutputType point; mitk::Point3D point; mitk::Point3D p, projected_p; float vtkp[3]; float lineWidth = 3.0; if (dynamic_cast(this->GetDataNode()->GetProperty("contour.width")) != NULL) lineWidth = dynamic_cast(this->GetDataNode()->GetProperty("contour.width"))->GetValue(); glLineWidth(lineWidth); bool drawit=false; mitk::ContourModel::VertexIterator pointsIt = renderingContour->IteratorBegin(timestep); Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; while ( pointsIt != renderingContour->IteratorEnd(timestep) ) { lastPt2d = pt2d; point = (*pointsIt)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; - ScalarType scalardiff = diff.GetSquaredNorm(); + ScalarType scalardiff = diff.GetNorm(); //draw lines bool projectmode=false; - GetDataNode()->GetVisibility(projectmode, renderer, "project"); + GetDataNode()->GetVisibility(projectmode, renderer, "contour.project-onto-plane"); if(projectmode) + { drawit=true; - else + } + else if(scalardiff<0.25) { - if(diff.GetSquaredNorm()<0.5) - drawit=true; + drawit=true; } + if(drawit) { //lastPt2d is not valid in first step if( !(pointsIt == renderingContour->IteratorBegin(timestep)) ) { glBegin (GL_LINES); glVertex2f(pt2d[0], pt2d[1]); glVertex2f(lastPt2d[0], lastPt2d[1]); glEnd(); } //draw active points if ((*pointsIt)->IsControlPoint) { float pointsize = 4; Point2D tmp; Vector2D horz,vert; - horz[0]=pointsize-scalardiff*2; horz[1]=0; - vert[0]=0; vert[1]=pointsize-scalardiff*2; + horz[1]=0; + vert[0]=0; horz[0]=pointsize; vert[1]=pointsize; glColor3f(selectedcolor->GetColor().GetRed(), selectedcolor->GetColor().GetBlue(), selectedcolor->GetColor().GetGreen()); glLineWidth(1); //a rectangle around the point with the selected color glBegin (GL_LINE_LOOP); tmp=pt2d-horz; glVertex2fv(&tmp[0]); tmp=pt2d+vert; glVertex2fv(&tmp[0]); tmp=pt2d+horz; glVertex2fv(&tmp[0]); tmp=pt2d-vert; glVertex2fv(&tmp[0]); - glEnd (); + glEnd(); glLineWidth(1); //the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(),colorprop->GetColor().GetGreen(),colorprop->GetColor().GetBlue()); glPointSize(1); glBegin (GL_POINTS); tmp=pt2d; glVertex2fv(&tmp[0]); glEnd (); } } pointsIt++; }//end while iterate over controlpoints //close contour if necessary if(renderingContour->IsClosed(timestep) && drawit) { lastPt2d = pt2d; point = renderingContour->GetVertexAt(0,timestep)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); glBegin (GL_LINES); glVertex2f(lastPt2d[0], lastPt2d[1]); glVertex2f( pt2d[0], pt2d[1] ); glEnd(); } //draw selected vertex if exists if(renderingContour->GetSelectedVertex()) { //transform selected vertex point = renderingContour->GetSelectedVertex()->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp,p); displayGeometry->Project(p, projected_p); displayGeometry->Map(projected_p, pt2d); displayGeometry->WorldToDisplay(pt2d, pt2d); Vector3D diff=p-projected_p; - ScalarType scalardiff = diff.GetSquaredNorm(); + ScalarType scalardiff = diff.GetNorm(); //---------------------------------- //draw point if close to plane - if(scalardiff<0.5) + if(scalardiff<0.25) { float pointsize = 3.2; Point2D tmp; glColor3f(0.0, 1.0, 0.0); glLineWidth(1); //a diamond around the point glBegin (GL_LINE_LOOP); //begin from upper left corner and paint clockwise tmp[0]=pt2d[0]-pointsize; tmp[1]=pt2d[1]+pointsize; glVertex2fv(&tmp[0]); tmp[0]=pt2d[0]+pointsize; tmp[1]=pt2d[1]+pointsize; glVertex2fv(&tmp[0]); tmp[0]=pt2d[0]+pointsize; tmp[1]=pt2d[1]-pointsize; glVertex2fv(&tmp[0]); tmp[0]=pt2d[0]-pointsize; tmp[1]=pt2d[1]-pointsize; glVertex2fv(&tmp[0]); glEnd (); } //------------------------------------ } } } const mitk::ContourModel* mitk::ContourModelGLMapper2D::GetInput(void) { return static_cast ( GetDataNode()->GetData() ); } void mitk::ContourModelGLMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "contour.color", ColorProperty::New(0.9, 1.0, 0.1), renderer, overwrite ); node->AddProperty( "points.color", ColorProperty::New(1.0, 0.0, 0.1), renderer, overwrite ); node->AddProperty( "contour.width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); node->AddProperty( "subdivision curve", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "contour.project-onto-plane", mitk::BoolProperty::New( false ), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/Segmentation/Rendering/mitkContourModelMapper3D.cpp b/Modules/Segmentation/Rendering/mitkContourModelMapper3D.cpp index 45075dc3da..8c2971b0dc 100644 --- a/Modules/Segmentation/Rendering/mitkContourModelMapper3D.cpp +++ b/Modules/Segmentation/Rendering/mitkContourModelMapper3D.cpp @@ -1,242 +1,242 @@ /*=================================================================== 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 mitk::ContourModelMapper3D::ContourModelMapper3D() { } mitk::ContourModelMapper3D::~ContourModelMapper3D() { } const mitk::ContourModel* mitk::ContourModelMapper3D::GetInput( void ) { //convient way to get the data from the dataNode return static_cast< const mitk::ContourModel * >( GetDataNode()->GetData() ); } vtkProp* mitk::ContourModelMapper3D::GetVtkProp(mitk::BaseRenderer* renderer) { //return the actor corresponding to the renderer return m_LSH.GetLocalStorage(renderer)->m_Actor; } void mitk::ContourModelMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { /* First convert the contourModel to vtkPolyData, then tube filter it and * set it input for our mapper */ LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); mitk::ContourModel* inputContour = static_cast< mitk::ContourModel* >( GetDataNode()->GetData() ); localStorage->m_OutlinePolyData = this->CreateVtkPolyDataFromContour(inputContour); this->ApplyContourProperties(renderer); //tube filter the polyData localStorage->m_TubeFilter->SetInput(localStorage->m_OutlinePolyData); float lineWidth(1.0); if (this->GetDataNode()->GetFloatProperty( "3D contour width", lineWidth, renderer )) { localStorage->m_TubeFilter->SetRadius(lineWidth); }else { - localStorage->m_TubeFilter->SetRadius(0.2); + localStorage->m_TubeFilter->SetRadius(0.5); } localStorage->m_TubeFilter->CappingOn(); localStorage->m_TubeFilter->SetNumberOfSides(10); localStorage->m_TubeFilter->Update(); localStorage->m_Mapper->SetInput(localStorage->m_TubeFilter->GetOutput()); } void mitk::ContourModelMapper3D::Update(mitk::BaseRenderer* renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); mitk::ContourModel* data = static_cast< mitk::ContourModel*>( GetDataNode()->GetData() ); if ( data == NULL ) { return; } // Calculate time step of the input data for the specified renderer (integer value) this->CalculateTimeStep( renderer ); LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); // Check if time step is valid const TimeSlicedGeometry *dataTimeGeometry = data->GetTimeSlicedGeometry(); if ( ( dataTimeGeometry == NULL ) || ( dataTimeGeometry->GetTimeSteps() == 0 ) || ( !dataTimeGeometry->IsValidTime( renderer->GetTimeStep() ) ) ) { //clear the rendered polydata localStorage->m_Mapper->SetInput(vtkSmartPointer::New()); return; } const DataNode *node = this->GetDataNode(); data->UpdateOutputInformation(); //check if something important has changed and we need to rerender if ( (localStorage->m_LastUpdateTime < node->GetMTime()) //was the node modified? || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2DUpdateTime()) //was the geometry modified? || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldGeometry2D()->GetMTime()) || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) { this->GenerateDataForRenderer( renderer ); } // since we have checked that nothing important has changed, we can set // m_LastUpdateTime to the current time localStorage->m_LastUpdateTime.Modified(); } vtkSmartPointer mitk::ContourModelMapper3D::CreateVtkPolyDataFromContour(mitk::ContourModel* inputContour) { unsigned int timestep = this->GetTimestep(); //the points to draw vtkSmartPointer points = vtkSmartPointer::New(); //the lines to connect the points vtkSmartPointer lines = vtkSmartPointer::New(); // Create a polydata to store everything in vtkSmartPointer polyData = vtkSmartPointer::New(); //iterate over the control points mitk::ContourModel::VertexIterator current = inputContour->IteratorBegin(timestep); mitk::ContourModel::VertexIterator next = inputContour->IteratorBegin(timestep); if(next != inputContour->IteratorEnd(timestep)) { next++; mitk::ContourModel::VertexIterator end = inputContour->IteratorEnd(timestep); while(next != end) { mitk::ContourModel::VertexType* currentControlPoint = *current; mitk::ContourModel::VertexType* nextControlPoint = *next; if( !(currentControlPoint->Coordinates[0] == nextControlPoint->Coordinates[0] && currentControlPoint->Coordinates[1] == nextControlPoint->Coordinates[1] && currentControlPoint->Coordinates[2] == nextControlPoint->Coordinates[2])) { vtkIdType p1 = points->InsertNextPoint(currentControlPoint->Coordinates[0], currentControlPoint->Coordinates[1], currentControlPoint->Coordinates[2]); vtkIdType p2 = points->InsertNextPoint(nextControlPoint->Coordinates[0], nextControlPoint->Coordinates[1], nextControlPoint->Coordinates[2]); //add the line between both contorlPoints lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } current++; next++; } if(inputContour->IsClosed(timestep)) { // If the contour is closed add a line from the last to the first control point mitk::ContourModel::VertexType* firstControlPoint = *(inputContour->IteratorBegin(timestep)); mitk::ContourModel::VertexType* lastControlPoint = *(--(inputContour->IteratorEnd(timestep))); if( lastControlPoint->Coordinates[0] != firstControlPoint->Coordinates[0] && lastControlPoint->Coordinates[1] != firstControlPoint->Coordinates[1] && lastControlPoint->Coordinates[2] != firstControlPoint->Coordinates[2]) { vtkIdType p2 = points->InsertNextPoint(lastControlPoint->Coordinates[0], lastControlPoint->Coordinates[1], lastControlPoint->Coordinates[2]); vtkIdType p1 = points->InsertNextPoint(firstControlPoint->Coordinates[0], firstControlPoint->Coordinates[1], firstControlPoint->Coordinates[2]); //add the line to the cellArray lines->InsertNextCell(2); lines->InsertCellPoint(p1); lines->InsertCellPoint(p2); } } // Add the points to the dataset polyData->SetPoints(points); // Add the lines to the dataset polyData->SetLines(lines); } return polyData; } void mitk::ContourModelMapper3D::ApplyContourProperties(mitk::BaseRenderer* renderer) { LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty ("color", renderer)); if(colorprop) { //set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); localStorage->m_Actor->GetProperty()->SetColor(red, green, blue); } } /*+++++++++++++++++++ LocalStorage part +++++++++++++++++++++++++*/ mitk::ContourModelMapper3D::LocalStorage* mitk::ContourModelMapper3D::GetLocalStorage(mitk::BaseRenderer* renderer) { return m_LSH.GetLocalStorage(renderer); } mitk::ContourModelMapper3D::LocalStorage::LocalStorage() { m_Mapper = vtkSmartPointer::New(); m_Actor = vtkSmartPointer::New(); m_OutlinePolyData = vtkSmartPointer::New(); m_TubeFilter = vtkSmartPointer::New(); //set the mapper for the actor m_Actor->SetMapper(m_Mapper); } void mitk::ContourModelMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { node->AddProperty( "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); - node->AddProperty( "3D contour width", mitk::FloatProperty::New( 0.2 ), renderer, overwrite ); + node->AddProperty( "3D contour width", mitk::FloatProperty::New( 0.5 ), renderer, overwrite ); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/Segmentation/files.cmake b/Modules/Segmentation/files.cmake index 5d11450bea..47bd8f2216 100644 --- a/Modules/Segmentation/files.cmake +++ b/Modules/Segmentation/files.cmake @@ -1,70 +1,75 @@ set(CPP_FILES Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkComputeContourSetNormalsFilter.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkCreateDistanceImageFromSurfaceFilter.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkImageToContourFilter.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp Algorithms/mitkOverwriteSliceImageFilter.cpp Algorithms/mitkReduceContourSetFilter.cpp Algorithms/mitkSegmentationObjectFactory.cpp Algorithms/mitkSegmentationSink.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkVtkImageOverwrite.cpp Algorithms/mitkDiffSliceOperation.cpp Algorithms/mitkDiffSliceOperationApplier.cpp Algorithms/mitkContourModelSource.cpp Algorithms/mitkContourModelToPointSetFilter.cpp Algorithms/mitkContourModelToSurfaceFilter.cpp Algorithms/mitkContourModelSubDivisionFilter.cpp +Algorithms/mitkImageToContourModelFilter.cpp +Algorithms/mitkImageToLiveWireContourFilter.cpp +Algorithms/mitkImageLiveWireContourModelFilter.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkSurfaceInterpolationController.cpp # DataManagement/mitkApplyDiffImageOperation.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkExtrudedContour.cpp DataManagement/mitkContourModel.cpp DataManagement/mitkContourElement.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkAutoSegmentationTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkCalculateGrayValueStatisticsTool.cpp Interactions/mitkCalculateVolumetryTool.cpp Interactions/mitkContourInteractor.cpp Interactions/mitkContourTool.cpp Interactions/mitkCorrectorTool2D.cpp Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkExtrudedContourInteractor.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkRegionGrow3DTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSetRegionTool.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkContourModelInteractor.cpp +Interactions/mitkContourModelLiveWireInteractor.cpp +Interactions/mitkLiveWireTool2D.cpp IO/mitkContourModelIOFactory.cpp IO/mitkContourModelReader.cpp IO/mitkContourModelWriter.cpp IO/mitkContourModelWriterFactory.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp Rendering/mitkContourModelMapper2D.cpp Rendering/mitkContourModelMapper3D.cpp Rendering/mitkContourModelGLMapper2D.cpp ) diff --git a/Modules/Simulation/Documentation/doxygen/Manual.dox b/Modules/Simulation/Documentation/doxygen/Manual.dox index 283292abf0..06b217c3af 100644 --- a/Modules/Simulation/Documentation/doxygen/Manual.dox +++ b/Modules/Simulation/Documentation/doxygen/Manual.dox @@ -1,103 +1,126 @@ /** \page SimulationManualPage The MITK Simulation Module -The MITK Simulation Module provides medical simulation capabilities by integrating the Simulation Open Framework Architecture (SOFA) into MITK. +The MITK simulation module provides medical simulation capabilities by integrating the Simulation Open Framework Architecture (SOFA) into MITK. \section SimulationManualBuildInstructions Build Instructions -Activate the %CMake option MITK_USE_SOFA to automatically download and build SOFA as well as the MITK Simulation Module during the superbuild process. -Afterwards you can activate simulation-enabled plugins during the MITK build configuration, e.g. MITK_BUILD_org.mitk.gui.qt.simulation. +Activate the %CMake option MITK_USE_SOFA when configuring the MITK superbuild. +SOFA is automatically downloaded and built during the superbuild (as well as the MITK simulation module, which depends on SOFA). +Simulation-related plugins can be activated when configuring the MITK build, i.e. activate MITK_BUILD_org.mitk.gui.qt.simulation, which will automatically activate MITK_BUILD_org.mitk.simulation in turn. -\section SimulationManualIntroduction Introduction +\subsection SimulationManualSOFAPluginBuildInstructions SOFA Plugins + +SOFA plugins are built automatically during the MITK superbuild if they are located in the right directory and contain a %CMake script to build them. + +SOFA build configuration is originally qmake-based. However, for seamless MITK superbuild integration a %CMake-based build script is used instead. +After you activated the %CMake option MITK_USE_SOFA, SOFA complete with the %CMake-based build script is downloaded during the superbuild. +Following the MITK superbuild convention for external projects, it is located in the SOFA-src directory right beneath the top-level MITK build directory. +Following the SOFA convention for plugins, they should be located in applications/plugins. +Hence, create an applications/plugins directory in SOFA-src and place your plugin here, i.e. SOFA-src/applications/plugins/myplugin. + +The second and last step is to create a CMakeLists.txt file inside your plugin directory. +Use the %CMake function add_sofa_library() to easily set up your plugin build script. +Below is an example of a CMakeLists.txt file for a fictional plugin named "myplugin": + +\code +set(MYPLUGIN_SOURES + Topologies/MyTopology.cpp + MyInteraction.cpp +) -It is strongly recommended that you are at least familiar with the basic concepts of SOFA before you proceed reading. +set(MYPLUGIN_LIBS + sofa_base_topology + sofa_user_interaction +) -SOFA is intended to be used as a framework by itself. It is split into the following three parts: +add_sofa_library(myplugin NO_PREFIX) +\endcode + +The naming of MYPLUGIN_SOURCES and MYPLUGIN_LIBS is crucial for add_sofa_library(myplugin) to find the sources and libraries. +For more information see SOFA-src/CMake/AddSOFALibrary.cmake. + +Once your plugin is placed in the right directory and provides a CMakeLists.txt file it is built during the MITK superbuild. +Binaries of your plugin are placed in SOFA-build/bin. + +SOFA plugins can be loaded at runtime via the simulation preferences by clicking the Add... button. + +\image html SimulationPreferences.png The simulation preferences dialog box. + +\section SimulationManualIntroduction Introduction + +SOFA is split into the following three parts:
  • Framework
  • Modules
  • Applications
-While the former two parts make up the actual framework, the latter part is built on top of them and provides end user applications, e.g. runSofa. +While the former two parts make up the actual framework functionality, the applications part provides end user applications, e.g. runSofa. +The MITK simulation module and plugins replace the applications part of SOFA and make use of the framework and modules parts in terms of a toolkit. -To be able to integrate SOFA into MITK, the MITK Simulation Module conceptionally replaces the application layer and solely uses the framework and module layer as a toolkit. +\image html SOFA_MITK.png Conceptional layers and dependencies of SOFA and the MITK simulation module. -\section SimulationManualHowToUpdate How to update SOFA +\remark While the framework and modules parts of SOFA are LGPL-licensed, the applications part, which is not used by MITK, is GPL-licensed. -SOFA is deployed to the MITK superbuild in three ZIP archives, namely +\section SimulationManualHowToUpdate How to supply SOFA to the MITK Superbuild -
    -
  • sofa-rev[rev].zip -
  • sofa-rev[rev]-cmake.zip -
  • sofa-rev[rev]-gl.zip -
+\remark If you are not a member of the MITK staff you can safely skip this section. + +SOFA build configuration is originally qmake-based. However, for seamless MITK superbuild integration a %CMake-based build script is used instead. +To maintain this script and to ensure that it matches the right revision of SOFA we set up a Git repository at %git\@mitk.org:MITK-SOFA. -where [rev] is a substitute for the SVN revision of SOFA, e.g. 8935. -The follwing process was proven suitable to create these ZIP archives out of a certain SOFA revision. -Since it is a very time-consuming task you should only update SOFA if it is really necessary! - -
    -
  1. Follow the instructions of the SOFA framework download website to check out a recent revsion of the trunk form their SVN server into a newly created directory named SOFA-svn (check the dashboard first to see if that revision is likely to compile properly on all supported platforms). -
  2. To get rid of all SVN files in the source directory use SVN export to export the source code to a separate directory named SOFA-rev[rev]. -
  3. Delete all irrelevant directories and files in SOFA-rev[rev]. Relevant directories and files are: -
      -
    • extlibs/eigen-3.1.1, extlibs/miniBoost, extlibs/miniFlowVR, extlibs/newmat, extlibs/tinyxml -
    • framework -
    • modules/sofa/component, modules/sofa/simulation, modules/copyright.txt, modules/LGPL-license.txt -
    • Authors.txt, LICENCE.txt, readme.txt -
    -
  4. Create sofa-rev[rev].zip out of the SOFA-rev[rev] directory. -
  5. Download the old sofa-rev[old_rev].zip and extract it to SOFA-rev[old_rev]. -
  6. Download the old sofa-rev[old_rev]-cmake.zip and extract it to SOFA-CMake. -
  7. Download the old sofa-rev[old_rev]-gl.zip and extract it to SOFA-GL. -
  8. Download a directory diff tool like DirDiff for Windows and compare sofa-rev[old_rev] with sofa_rev[rev] to get an overview of what has changed. Note that you have to look at the .pro files to see which files were added or removed to the projects. Just looking at the files in a project directory is not sufficient! -
  9. Adapt the CMake files in SOFA-CMake to the changes. -
  10. Copy SOFA-rev[rev] to SOFA-rev[rev]-Test and also copy SOFA-CMake and SOFA-GL into that directory. -
  11. Manually apply the patch for SOFA you find in the MITK source tree (MITK/CMakeExternals/PatchSOFA-rev[old_rev].cmake. -
  12. Try to build SOFA-rev[rev]-Test. Make changes to SOFA-CMake and SOFA-GL files (don't forget to reapply the patch or even change the patch if necessary) until you can build everything successfully. -
  13. Create sofa-rev[rev]-cmake.zip out of SOFA-CMake and sofa-rev[rev]-gl.zip out of SOFA-GL. -
  14. Upload all three ZIP archives to a easily accessible location like your public DropBox folder. -
  15. Update MITK/CMakeExternals/SOFA.cmake to point to the temporary locations and don't forget to update the MD5 hashes and to use an up-to-date patch file, i.e. PatchSOFA-rev[rev].cmake. -
  16. Try to build MITK. Repeat any of the above steps until you are able to compile and use MITK with SOFA on every supprted plattform. -
  17. Upload the new SOFA archives to mitk.org and adapt the URLs in MITK/CMakeExternals/SOFA.cmake. -
+When the repository was updated a package named SOFA_.tar.gz must be created and uploaded to %http://mitk.org/download/thirdparty/. + consists of the last eight digits of the SHA1 ID of the commit. +To use the new package for the MITK superbuild, the URL and MD5 of the package must be updated in CMakeExternals/SOFA.cmake. + +If you need to patch SOFA sources you must append your patch to CMakeExternals/PatchSOFA-rev.cmake. +Make sure that you keep the filename up to date regarding the revision of SOFA and update the filename for the patch command in CMakeExternals/SOFA.cmake too. + +The commit messages of the MITK-SOFA repository contain valuable information on which parts of SOFA must be stripped from a newly checked out revision. +Please continue writing detailed commit messages when updating the repository. + +Updating the repository to a new SOFA revision can be a time-consuming task. +The best way to keep track of changes and additions to the SOFA sources is to use a free folder comparing tool (e.g. dirdiff). +Especially look at .pro files which describe the individual SOFA projects. \section SimulationManualDrawing Drawing +It is recommended that you are at least familiar with the basic concepts of SOFA, e.g. scene graphs and visitors, before you proceed reading. + Drawing is done by SOFA at three different places:
  • sofa::component::visualmodel classes
  • sofa::core::visual::DrawTool class
  • sofa::helper::gl classes and functions
These cases are handled by the MITK Simulation Module as follows. \subsection SimulationManualDrawingVisualModel sofa::component::visualmodel One of the most important drawing classes is OglModel since it makes up most of the visual part of a simulation scene. It inherits from VisualModel (which encapsulates all API-independent drawing code) and contains OpenGL-related code to draw the visual model. To hook into the drawing of visual models, the MITK Simulation Module creates an alias in the SOFA object system so that every OglModel and VisualModel node found in a scene file is used to instantiate a MITK SimulationModel class instead. This class creates VTK actors that contain the visual model rather than drawing it directly. The simulation mapper, which is responsible for drawing a simulation scene, utilizes the visitor mechanism of SOFA to collect all VTK actors of the scene tree and finally draws them. \subsection SimulationManualDrawingDrawToolGL sofa::core::visual::DrawTool The abstract class DrawTool and its default OpenGL implementation DrawToolGL provide the interface to draw basic primitives, e.g. points, lines, spheres, arrows, and so forth. It is usually set by a call to sofa::core::visual::VisualParams::defaultInstance()->drawTool() at application initialization. The MITK Simulation Module provide its own VTK-based implementation of DrawTool, namely SimulationDrawTool. This class creates VTK actors instead of drawing anything directly. There is one SimulationDrawTool per simulation scene and the simulation mapper draws all current VTK actors according to which simulation scene is drawn. \subsection SimulationManualDrawingGL sofa::helper::gl Classes and functions in this namespace are problematic since they don't support the SOFA object system and therefore cannot be easily replaced by own implementations. Currently they are not handled by MITK at all and an OpenGL stub is injected into SOFA so that all draw related methods and functions in this namespace do practically nothing. This stub is automatically downloaded during the MITK superbuild process (sofa-rev[rev]-gl.zip). However, a patch is additionally applied by the superbuild script to SOFA which alters a few header files to include the stub header files instead of the original OpenGL/GLUT/GLEW ones. */ \ No newline at end of file diff --git a/Modules/Simulation/Documentation/doxygen/SOFA_MITK.png b/Modules/Simulation/Documentation/doxygen/SOFA_MITK.png new file mode 100644 index 0000000000..e2b4acf44e Binary files /dev/null and b/Modules/Simulation/Documentation/doxygen/SOFA_MITK.png differ diff --git a/Modules/Simulation/Documentation/doxygen/SimulationPreferences.png b/Modules/Simulation/Documentation/doxygen/SimulationPreferences.png new file mode 100644 index 0000000000..ee82e3ef41 Binary files /dev/null and b/Modules/Simulation/Documentation/doxygen/SimulationPreferences.png differ diff --git a/Modules/Simulation/files.cmake b/Modules/Simulation/files.cmake index 92064e233b..4284af92e6 100644 --- a/Modules/Simulation/files.cmake +++ b/Modules/Simulation/files.cmake @@ -1,10 +1,13 @@ set(CPP_FILES mitkSimulation.cpp mitkSimulationDrawTool.cpp - mitkSimulationPropAssemblyVisitor.cpp mitkSimulationIOFactory.cpp mitkSimulationMapper3D.cpp - mitkSimulationReader.cpp - mitkSimulationObjectFactory.cpp mitkSimulationModel.cpp + mitkSimulationObjectFactory.cpp + mitkSimulationPropAssemblyVisitor.cpp + mitkSimulationReader.cpp + mitkSimulationTemplate.cpp + mitkSimulationTemplateIOFactory.cpp + mitkSimulationTemplateReader.cpp ) diff --git a/Modules/Simulation/mitkSimulation.cpp b/Modules/Simulation/mitkSimulation.cpp index c499c7b059..17e3bded61 100644 --- a/Modules/Simulation/mitkSimulation.cpp +++ b/Modules/Simulation/mitkSimulation.cpp @@ -1,238 +1,245 @@ /*=================================================================== 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 "mitkSimulation.h" #include "mitkSimulationPropAssemblyVisitor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include -const float mitk::Simulation::ScaleFactor = 1000.0f; +const float mitk::Simulation::ScaleFactor = 1.0f; // 1000.0f static sofa::simulation::Simulation::SPtr CreateSimulation(mitk::Simulation::SimulationType type = mitk::Simulation::Tree) { if (type == mitk::Simulation::DAG) return sofa::core::objectmodel::New(); else if (type == mitk::Simulation::Bgl) return sofa::core::objectmodel::New(); else return sofa::core::objectmodel::New(); } void mitk::Simulation::SetActiveSimulation(mitk::Simulation* simulation) { if (simulation == NULL) { sofa::simulation::setSimulation(NULL); sofa::core::visual::VisualParams::defaultInstance()->drawTool() = NULL; } else { sofa::simulation::Simulation* sofaSimulation = simulation->m_Simulation.get(); if (sofa::simulation::getSimulation() != sofaSimulation) { sofa::simulation::setSimulation(sofaSimulation); sofa::core::visual::VisualParams::defaultInstance()->drawTool() = &simulation->m_DrawTool; } } } mitk::Simulation::Simulation() : m_Simulation(CreateSimulation()), m_DefaultDT(0.0) { } mitk::Simulation::~Simulation() { if (m_Simulation != NULL) { if (m_RootNode != NULL) m_Simulation->unload(m_RootNode); if (sofa::simulation::getSimulation() == m_Simulation.get()) SetActiveSimulation(NULL); } } -void mitk::Simulation::AppendSnapshot(mitk::Surface::Pointer surface) const +bool mitk::Simulation::AppendSnapshot(mitk::Surface::Pointer surface) const { - if (surface.IsNull()) - return; + if (surface.IsNotNull()) + { + vtkSmartPointer snapshot = this->CreateSnapshot(); - vtkSmartPointer snapshot = this->CreateSnapshot(); + if (snapshot != NULL) + { + unsigned int timeStep = surface->GetSizeOfPolyDataSeries(); - if (snapshot != NULL) - { - unsigned int timeStep = surface->GetSizeOfPolyDataSeries(); + if (timeStep != 0 && surface->GetVtkPolyData(timeStep - 1) == NULL) + --timeStep; - if (timeStep != 0 && surface->GetVtkPolyData(timeStep - 1) == NULL) - --timeStep; + surface->SetVtkPolyData(snapshot, timeStep); - surface->SetVtkPolyData(snapshot, timeStep); + return true; + } } + + return false; } vtkSmartPointer mitk::Simulation::CreateSnapshot() const { if (m_RootNode == NULL) return NULL; vtkSmartPointer propAssembly = vtkSmartPointer::New(); SimulationPropAssemblyVisitor propAssemblyVisitor(propAssembly); m_RootNode->executeVisitor(&propAssemblyVisitor); vtkSmartPointer appendFilter = vtkSmartPointer::New(); vtkPropCollection* propCollection = propAssembly->GetParts(); vtkProp* prop = NULL; + if (propCollection->GetNumberOfItems() == 0) + return NULL; + for (propCollection->InitTraversal(); (prop = propCollection->GetNextProp()) != NULL; ) { vtkActor* actor = vtkActor::SafeDownCast(prop); vtkPolyData* polyData = vtkPolyData::SafeDownCast(actor->GetMapper()->GetInput()); appendFilter->AddInput(polyData); } vtkSmartPointer scaleTransform = vtkSmartPointer::New(); scaleTransform->Scale(ScaleFactor, ScaleFactor, ScaleFactor); vtkSmartPointer transformFilter = vtkSmartPointer::New(); transformFilter->SetInputConnection(appendFilter->GetOutputPort()); transformFilter->SetTransform(scaleTransform); transformFilter->Update(); vtkSmartPointer snapshot = vtkSmartPointer::New(); snapshot->ShallowCopy(transformFilter->GetOutputDataObject(0)); return snapshot; } double mitk::Simulation::GetDefaultDT() const { return m_DefaultDT; } mitk::SimulationDrawTool* mitk::Simulation::GetDrawTool() { return &m_DrawTool; } sofa::simulation::Node::SPtr mitk::Simulation::GetRootNode() const { return m_RootNode; } sofa::simulation::Simulation::SPtr mitk::Simulation::GetSimulation() const { return m_Simulation; } bool mitk::Simulation::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } void mitk::Simulation::SetAsActiveSimulation() { SetActiveSimulation(this); } void mitk::Simulation::SetDefaultDT(double dt) { m_DefaultDT = std::max(0.0, dt); } void mitk::Simulation::SetRequestedRegion(itk::DataObject*) { } void mitk::Simulation::SetRequestedRegionToLargestPossibleRegion() { } void mitk::Simulation::SetRootNode(sofa::simulation::Node* rootNode) { m_RootNode.reset(rootNode); } mitk::Surface::Pointer mitk::Simulation::TakeSnapshot() const { vtkSmartPointer snapshot = this->CreateSnapshot(); if (snapshot == NULL) return NULL; Surface::Pointer surface = Surface::New(); surface->SetVtkPolyData(snapshot); return surface; } void mitk::Simulation::UpdateOutputInformation() { if (this->GetSource().IsNotNull()) this->GetSource()->UpdateOutputInformation(); if (m_RootNode != NULL) { const sofa::defaulttype::BoundingBox& boundingBox = m_RootNode->f_bbox.getValue(); const sofa::defaulttype::Vector3& min = boundingBox.minBBox(); const sofa::defaulttype::Vector3& max = boundingBox.maxBBox(); mitk::Geometry3D::BoundsArrayType bounds; bounds[0] = static_cast(min.x() * ScaleFactor); bounds[1] = static_cast(max.x() * ScaleFactor); bounds[2] = static_cast(min.y() * ScaleFactor); bounds[3] = static_cast(max.y() * ScaleFactor); bounds[4] = static_cast(min.z() * ScaleFactor); bounds[5] = static_cast(max.z() * ScaleFactor); if(this->GetGeometry() != NULL) { this->GetGeometry()->SetBounds(bounds); } else { Geometry3D::Pointer geometry = Geometry3D::New(); geometry->SetBounds(bounds); this->SetGeometry(geometry); } } this->GetTimeSlicedGeometry()->UpdateInformation(); } bool mitk::Simulation::VerifyRequestedRegion() { return true; } diff --git a/Modules/Simulation/mitkSimulation.h b/Modules/Simulation/mitkSimulation.h index d58c61a614..5c67c54911 100644 --- a/Modules/Simulation/mitkSimulation.h +++ b/Modules/Simulation/mitkSimulation.h @@ -1,77 +1,77 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulation_h #define mitkSimulation_h #include "mitkSimulationDrawTool.h" #include #include #include #include #include namespace mitk { class Simulation_EXPORT Simulation : public BaseData { public: enum SimulationType { Tree, DAG, Bgl }; mitkClassMacro(Simulation, BaseData); itkNewMacro(Self); static void SetActiveSimulation(Self* simulation); static const float ScaleFactor; - void AppendSnapshot(Surface::Pointer surface) const; + bool AppendSnapshot(Surface::Pointer surface) const; double GetDefaultDT() const; SimulationDrawTool* GetDrawTool(); sofa::simulation::Node::SPtr GetRootNode() const; sofa::simulation::Simulation::SPtr GetSimulation() const; bool RequestedRegionIsOutsideOfTheBufferedRegion(); void SetAsActiveSimulation(); void SetDefaultDT(double dt); void SetRequestedRegion(itk::DataObject* data); void SetRequestedRegionToLargestPossibleRegion(); void SetRootNode(sofa::simulation::Node* rootNode); Surface::Pointer TakeSnapshot() const; void UpdateOutputInformation(); bool VerifyRequestedRegion(); private: Simulation(); ~Simulation(); Simulation(Self&); Self& operator=(const Self&); vtkSmartPointer CreateSnapshot() const; sofa::simulation::Simulation::SPtr m_Simulation; sofa::simulation::Node::SPtr m_RootNode; SimulationDrawTool m_DrawTool; double m_DefaultDT; }; } #endif diff --git a/Modules/Simulation/mitkSimulationObjectFactory.cpp b/Modules/Simulation/mitkSimulationObjectFactory.cpp index ff1c0cef4b..0e70e52e6e 100644 --- a/Modules/Simulation/mitkSimulationObjectFactory.cpp +++ b/Modules/Simulation/mitkSimulationObjectFactory.cpp @@ -1,128 +1,136 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSimulation.h" #include "mitkSimulationMapper3D.h" -#include "mitkSimulationObjectFactory.h" #include "mitkSimulationModel.h" +#include "mitkSimulationObjectFactory.h" +#include "mitkSimulationTemplate.h" #include #include #include #include +static void InitializeSOFA() +{ + sofa::component::init(); + sofa::simulation::xml::initXml(); + + int SimulationModelClass = sofa::core::RegisterObject("").add(); + sofa::core::ObjectFactory::AddAlias("OglModel", "SimulationModel", true); + sofa::core::ObjectFactory::AddAlias("VisualModel", "SimulationModel", true); +} + mitk::SimulationObjectFactory::SimulationObjectFactory() - : m_SimulationIOFactory(SimulationIOFactory::New()) + : m_SimulationIOFactory(SimulationIOFactory::New()), + m_SimulationTemplateIOFactory(SimulationTemplateIOFactory::New()) { itk::ObjectFactoryBase::RegisterFactory(m_SimulationIOFactory); + itk::ObjectFactoryBase::RegisterFactory(m_SimulationTemplateIOFactory); - const std::string description = "SOFA Scene Files"; + std::string description = "SOFA Scene Files"; m_FileExtensionsMap.insert(std::pair("*.scn", description)); m_FileExtensionsMap.insert(std::pair("*.xml", description)); - sofa::component::init(); - sofa::simulation::xml::initXml(); + description = "SOFA Scene File Templates"; + m_FileExtensionsMap.insert(std::pair("*.scn.template", description)); + m_FileExtensionsMap.insert(std::pair("*.xml.template", description)); - int SimulationModelClass = sofa::core::RegisterObject("").add(); - sofa::core::ObjectFactory::AddAlias("OglModel", "SimulationModel", true); - sofa::core::ObjectFactory::AddAlias("VisualModel", "SimulationModel", true); + InitializeSOFA(); } mitk::SimulationObjectFactory::~SimulationObjectFactory() { + itk::ObjectFactoryBase::UnRegisterFactory(m_SimulationTemplateIOFactory); itk::ObjectFactoryBase::UnRegisterFactory(m_SimulationIOFactory); } mitk::Mapper::Pointer mitk::SimulationObjectFactory::CreateMapper(mitk::DataNode* node, MapperSlotId slotId) { mitk::Mapper::Pointer mapper; if (dynamic_cast(node->GetData()) != NULL) { if (slotId == mitk::BaseRenderer::Standard3D) mapper = mitk::SimulationMapper3D::New(); if (mapper.IsNotNull()) mapper->SetDataNode(node); } return mapper; } const char* mitk::SimulationObjectFactory::GetDescription() const { return "mitk::SimulationObjectFactory"; } const char* mitk::SimulationObjectFactory::GetFileExtensions() { std::string fileExtensions; this->CreateFileExtensions(m_FileExtensionsMap, fileExtensions); return fileExtensions.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::SimulationObjectFactory::GetFileExtensionsMap() { return m_FileExtensionsMap; } const char* mitk::SimulationObjectFactory::GetITKSourceVersion() const { return ITK_SOURCE_VERSION; } const char* mitk::SimulationObjectFactory::GetSaveFileExtensions() { std::string saveFileExtensions; this->CreateFileExtensions(m_FileExtensionsMap, saveFileExtensions); return saveFileExtensions.c_str(); } mitk::CoreObjectFactoryBase::MultimapType mitk::SimulationObjectFactory::GetSaveFileExtensionsMap() { return m_SaveFileExtensionsMap; } void mitk::SimulationObjectFactory::SetDefaultProperties(mitk::DataNode* node) { if (node != NULL) { if (dynamic_cast(node->GetData()) != NULL) + { SimulationMapper3D::SetDefaultProperties(node); + } + else if (dynamic_cast(node->GetData()) != NULL) + { + SimulationTemplate* simulationTemplate = static_cast(node->GetData()); + simulationTemplate->SetProperties(node); + } } } -class RegisterSimulationObjectFactory +void mitk::RegisterSimulationObjectFactory() { -public: - RegisterSimulationObjectFactory() - : m_Factory(mitk::SimulationObjectFactory::New()) - { - mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(m_Factory); - } + static bool alreadyRegistered = false; - ~RegisterSimulationObjectFactory() + if (!alreadyRegistered) { - mitk::CoreObjectFactory::GetInstance()->UnRegisterExtraFactory(m_Factory); + mitk::CoreObjectFactory::GetInstance()->RegisterExtraFactory(mitk::SimulationObjectFactory::New()); + alreadyRegistered = true; } - -private: - RegisterSimulationObjectFactory(const RegisterSimulationObjectFactory&); - RegisterSimulationObjectFactory& operator=(const RegisterSimulationObjectFactory&); - - mitk::SimulationObjectFactory::Pointer m_Factory; -}; - -static RegisterSimulationObjectFactory registerSimulationObjectFactory; +} diff --git a/Modules/Simulation/mitkSimulationObjectFactory.h b/Modules/Simulation/mitkSimulationObjectFactory.h index 501eb21f84..c07742ed6b 100644 --- a/Modules/Simulation/mitkSimulationObjectFactory.h +++ b/Modules/Simulation/mitkSimulationObjectFactory.h @@ -1,53 +1,57 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulationObjectFactory_h #define mitkSimulationObjectFactory_h #include "mitkSimulationIOFactory.h" +#include "mitkSimulationTemplateIOFactory.h" #include namespace mitk { class Simulation_EXPORT SimulationObjectFactory : public CoreObjectFactoryBase { public: mitkClassMacro(SimulationObjectFactory, CoreObjectFactoryBase); itkFactorylessNewMacro(Self); Mapper::Pointer CreateMapper(DataNode* node, MapperSlotId slotId); const char* GetDescription() const; const char* GetFileExtensions(); MultimapType GetFileExtensionsMap(); const char* GetITKSourceVersion() const; const char* GetSaveFileExtensions(); MultimapType GetSaveFileExtensionsMap(); void SetDefaultProperties(DataNode* node); private: SimulationObjectFactory(); ~SimulationObjectFactory(); SimulationObjectFactory(const Self&); Self& operator=(const Self&); SimulationIOFactory::Pointer m_SimulationIOFactory; + SimulationTemplateIOFactory::Pointer m_SimulationTemplateIOFactory; MultimapType m_FileExtensionsMap; MultimapType m_SaveFileExtensionsMap; }; + + Simulation_EXPORT void RegisterSimulationObjectFactory(); } #endif diff --git a/Modules/Simulation/mitkSimulationReader.h b/Modules/Simulation/mitkSimulationReader.h index 8d8783ac6a..e8f32059f9 100644 --- a/Modules/Simulation/mitkSimulationReader.h +++ b/Modules/Simulation/mitkSimulationReader.h @@ -1,59 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkSimulationReader_h #define mitkSimulationReader_h #include #include +#include namespace mitk { class Simulation_EXPORT SimulationReader : public BaseProcess, FileReader { public: static bool CanReadFile(const std::string& filename, const std::string& filePrefix, const std::string& filePattern); mitkClassMacro(SimulationReader, BaseProcess); itkNewMacro(Self); const char* GetFileName() const; void SetFileName(const char* aFileName); const char* GetFilePattern() const; void SetFilePattern(const char* aFilePattern); const char* GetFilePrefix() const; void SetFilePrefix(const char* aFilePrefix); protected: void GenerateData(); void GenerateOutputInformation(); private: SimulationReader(); ~SimulationReader(); SimulationReader(const Self &); Self & operator=(const Self &); std::string m_FileName; std::string m_FilePattern; std::string m_FilePrefix; }; } #endif diff --git a/Modules/Simulation/mitkSimulationTemplate.cpp b/Modules/Simulation/mitkSimulationTemplate.cpp new file mode 100644 index 0000000000..238ddd3e26 --- /dev/null +++ b/Modules/Simulation/mitkSimulationTemplate.cpp @@ -0,0 +1,316 @@ +/*=================================================================== + +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 "mitkSimulationTemplate.h" +#include +#include + +typedef std::vector > TemplateIndex; +typedef std::vector > VariableContents; + +static TemplateIndex CreateTemplateIndex(const std::string& contents) +{ + TemplateIndex templateIndex; + + std::string::size_type begin = 0; + begin = contents.find_first_of('{', 0); + + while (begin != std::string::npos) + { + std::string::size_type end = contents.find_first_of('}', begin); + + if (end == std::string::npos) + mitkThrow() << "Expected closing brace before end of file!"; + + templateIndex.push_back(std::make_pair(begin, ++end - begin)); + + begin = contents.find_first_of('{', end); + } + + if (templateIndex.empty()) + mitkThrow() << "No templates found!"; + + return templateIndex; +} + +static std::vector ParseStaticContents(const std::string& contents, const TemplateIndex& templateIndex) +{ + std::vector staticContents; + std::string::size_type index = 0; + + for (TemplateIndex::const_iterator it = templateIndex.begin(); it != templateIndex.end(); ++it) + { + staticContents.push_back(contents.substr(index, it->first - index)); + index = it->first + it->second; + } + + staticContents.push_back(contents.substr(index)); + + return staticContents; +} + +static std::string ParseValue(const std::string& templ, const std::string& valueName) +{ + const char* spaces = " \t\n"; + std::string::size_type index = templ.find(valueName); + + if (index != std::string::npos) + { + index += valueName.length(); + index = templ.find_first_not_of(spaces, index); + + if (index != std::string::npos && templ[index] == '=') + { + ++index; + index = templ.find_first_not_of(spaces, index); + + if (index != std::string::npos && templ[index] == '\'') + { + ++index; + std::string::size_type length = templ.find_first_of('\'', index); + + if (length != std::string::npos) + { + length -= index; + return templ.substr(index, length); + } + } + } + } + + return ""; +} + +template T FromString(const std::string& string) +{ + std::istringstream stream(string); + + T value; + stream >> value; + + return value; +} + +static std::pair ParseReference(const std::string& ref) +{ + std::string id = "{ref}"; + mitk::StringProperty::Pointer property = mitk::StringProperty::New(ref.substr(2, ref.length() - 4)); + + return std::make_pair(id, property); +} + +static std::pair ParseTemplate(const std::string& templ) +{ + if (templ.length() > 4 && templ[1] == '\'') + { + return ParseReference(templ); + } + else + { + std::string id = ParseValue(templ, "id"); + + if (!id.empty()) + { + std::string type = ParseValue(templ, "type"); + + if (type.empty()) + type = "string"; + + mitk::BaseProperty::Pointer property; + std::string defaultValue = ParseValue(templ, "default"); + + if (type == "float") + { + float value = !defaultValue.empty() + ? FromString(defaultValue) + : 0.0; + + property = mitk::FloatProperty::New(value); + } + else if (type == "int") + { + int value = !defaultValue.empty() + ? FromString(defaultValue) + : 0.0; + + property = mitk::IntProperty::New(value); + } + else if (type == "string") + { + std::string value = !defaultValue.empty() + ? defaultValue + : ""; + + property = mitk::StringProperty::New(value); + } + + if (property.IsNotNull()) + return std::make_pair(id, property); + } + } + + std::string emptyString; + mitk::BaseProperty::Pointer nullPointer; + + return std::make_pair(emptyString, nullPointer); +} + +static VariableContents ParseVariableContents(const std::string& contents, const TemplateIndex& templateIndex) +{ + VariableContents variableContents; + + for (TemplateIndex::const_iterator it = templateIndex.begin(); it != templateIndex.end(); ++it) + { + std::string templ = contents.substr(it->first, it->second); + std::pair variableContent = ParseTemplate(templ); + + if (variableContent.first.empty() || variableContent.second.IsNull()) + mitkThrow() << "Could not parse " << templ << "!"; + + variableContents.push_back(variableContent); + } + + return variableContents; +} + +template +class FirstEqualTo +{ +public: + FirstEqualTo(const T1& value) + : m_Value(value) + { + } + + bool operator()(const std::pair& pair) const + { + return pair.first == m_Value; + } + +private: + T1 m_Value; +}; + +mitk::SimulationTemplate::SimulationTemplate() + : m_IsInitialized(false) +{ +} + +mitk::SimulationTemplate::~SimulationTemplate() +{ +} + +std::string mitk::SimulationTemplate::Bake() const +{ + if (!m_IsInitialized) + { + MITK_ERROR << "Simulation template is not initialized!"; + return ""; + } + + std::string contents; + + for (VariableContents::size_type i = 0; i < m_VariableContents.size(); ++i) + { + contents += m_StaticContents[i]; + + if (m_VariableContents[i].first == "{ref}") + { + VariableContents::const_iterator it = std::find_if(m_VariableContents.begin(), m_VariableContents.end(), + FirstEqualTo(m_VariableContents[i].second->GetValueAsString())); + + if (it == m_VariableContents.end()) + { + MITK_ERROR << "Template '" << m_VariableContents[i].second << "' not found!"; + return ""; + } + + contents += it->second->GetValueAsString(); + } + else + { + contents += m_VariableContents[i].second->GetValueAsString(); + } + } + + contents += m_StaticContents.back(); + + return contents; +} + +bool mitk::SimulationTemplate::Parse(const std::string& contents) +{ + if (m_IsInitialized) + return false; + + TemplateIndex templateIndex = CreateTemplateIndex(contents); + std::vector staticContents = ParseStaticContents(contents, templateIndex); + VariableContents variableContents = ParseVariableContents(contents, templateIndex); + + std::swap(m_StaticContents, staticContents); + std::swap(m_VariableContents, variableContents); + m_IsInitialized = true; + + return true; +} + +bool mitk::SimulationTemplate::RequestedRegionIsOutsideOfTheBufferedRegion() +{ + return false; +} + +void mitk::SimulationTemplate::SetProperties(mitk::DataNode::Pointer dataNode) const +{ + if (dataNode.IsNull()) + return; + + if (!m_IsInitialized) + { + MITK_ERROR << "Simulation template is not initialized!"; + return; + } + + if (dynamic_cast(dataNode->GetData()) != this) + { + MITK_ERROR << "Data node does not own this simulation template!"; + return; + } + + for(VariableContents::const_iterator it = m_VariableContents.begin(); it != m_VariableContents.end(); ++it) + { + if (it->first != "{ref}") + dataNode->SetProperty(it->first.c_str(), it->second.GetPointer()); + } +} + +void mitk::SimulationTemplate::SetRequestedRegion(itk::DataObject*) +{ +} + +void mitk::SimulationTemplate::SetRequestedRegionToLargestPossibleRegion() +{ +} + +void mitk::SimulationTemplate::UpdateOutputInformation() +{ + if (this->GetSource().IsNotNull()) + this->GetSource()->UpdateOutputInformation(); +} + +bool mitk::SimulationTemplate::VerifyRequestedRegion() +{ + return true; +} diff --git a/Modules/Simulation/mitkSimulationTemplate.h b/Modules/Simulation/mitkSimulationTemplate.h new file mode 100644 index 0000000000..75f9f81e9b --- /dev/null +++ b/Modules/Simulation/mitkSimulationTemplate.h @@ -0,0 +1,57 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkSimulationTemplate_h +#define mitkSimulationTemplate_h + +#include +#include +#include +#include +#include +#include + +namespace mitk +{ + class Simulation_EXPORT SimulationTemplate : public BaseData + { + public: + mitkClassMacro(SimulationTemplate, BaseData); + itkNewMacro(Self); + + std::string Bake() const; + bool Parse(const std::string& contents); + bool RequestedRegionIsOutsideOfTheBufferedRegion(); + void SetProperties(DataNode::Pointer dataNode) const; + void SetRequestedRegion(itk::DataObject* data); + void SetRequestedRegionToLargestPossibleRegion(); + void UpdateOutputInformation(); + bool VerifyRequestedRegion(); + + private: + SimulationTemplate(); + ~SimulationTemplate(); + + SimulationTemplate(Self&); + Self& operator=(const Self&); + + bool m_IsInitialized; + std::vector m_StaticContents; + std::vector > m_VariableContents; + }; +} + +#endif diff --git a/Modules/Simulation/mitkSimulationTemplateIOFactory.cpp b/Modules/Simulation/mitkSimulationTemplateIOFactory.cpp new file mode 100644 index 0000000000..67ddfd2373 --- /dev/null +++ b/Modules/Simulation/mitkSimulationTemplateIOFactory.cpp @@ -0,0 +1,45 @@ +/*=================================================================== + +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 "mitkSimulationTemplateIOFactory.h" +#include "mitkSimulationTemplateReader.h" +#include +#include + +mitk::SimulationTemplateIOFactory::SimulationTemplateIOFactory() +{ + + this->RegisterOverride( + "mitkIOAdapter", + "mitkSimulationTemplateReader", + "Simulation Template IO", + true, + itk::CreateObjectFunction >::New()); +} + +mitk::SimulationTemplateIOFactory::~SimulationTemplateIOFactory() +{ +} + +const char* mitk::SimulationTemplateIOFactory::GetDescription() const +{ + return "mitk::SimulationTemplateIOFactory"; +} + +const char* mitk::SimulationTemplateIOFactory::GetITKSourceVersion() const +{ + return ITK_SOURCE_VERSION; +} diff --git a/Modules/Simulation/mitkSimulationTemplateIOFactory.h b/Modules/Simulation/mitkSimulationTemplateIOFactory.h new file mode 100644 index 0000000000..b616a1001e --- /dev/null +++ b/Modules/Simulation/mitkSimulationTemplateIOFactory.h @@ -0,0 +1,44 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkSimulationTemplateIOFactory_h +#define mitkSimulationTemplateIOFactory_h + +#include +#include +#include + +namespace mitk +{ + class Simulation_EXPORT SimulationTemplateIOFactory : public itk::ObjectFactoryBase + { + public: + mitkClassMacro(SimulationTemplateIOFactory, itk::ObjectFactoryBase); + itkFactorylessNewMacro(Self); + + const char* GetDescription() const; + const char* GetITKSourceVersion() const; + + private: + SimulationTemplateIOFactory(); + ~SimulationTemplateIOFactory(); + + SimulationTemplateIOFactory(const Self&); + Self& operator=(const Self&); + }; +}; + +#endif diff --git a/Modules/Simulation/mitkSimulationTemplateReader.cpp b/Modules/Simulation/mitkSimulationTemplateReader.cpp new file mode 100644 index 0000000000..cf35e0b0e2 --- /dev/null +++ b/Modules/Simulation/mitkSimulationTemplateReader.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +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 "mitkSimulationTemplate.h" +#include "mitkSimulationTemplateReader.h" +#include +#include +#include + +static std::string ReadFile(const std::string& fileName) +{ + std::ifstream file(fileName.c_str()); + + if (!file.is_open()) + mitkThrow() << "Could not load '" << fileName << "'!"; + + std::string contents; + + file.seekg(0, std::ios::end); + contents.resize(file.tellg()); + file.seekg(0, std::ios::beg); + file.read(&contents[0], contents.size()); + + file.close(); + + if (contents.empty()) + mitkThrow() << fileName << " is empty!"; + + return contents; +} + +bool mitk::SimulationTemplateReader::CanReadFile(const std::string& filename, const std::string&, const std::string&) +{ + std::string::size_type length = filename.length(); + + if (length < 14) + return false; + + std::string ext = filename.substr(length - 13); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + + if (ext == ".scn.template" || ext == ".xml.template") + return true; + + return false; +} + +mitk::SimulationTemplateReader::SimulationTemplateReader() +{ + mitk::SimulationTemplate::Pointer output = mitk::SimulationTemplate::New(); + + this->SetNumberOfRequiredOutputs(1); + this->SetNthOutput(0, output.GetPointer()); +} + +mitk::SimulationTemplateReader::~SimulationTemplateReader() +{ +} + +void mitk::SimulationTemplateReader::GenerateData() +{ + SimulationTemplate::Pointer simulationTemplate = dynamic_cast(this->GetOutput(0)); + + std::string contents = ReadFile(m_FileName); + simulationTemplate->Parse(contents); +} + +void mitk::SimulationTemplateReader::GenerateOutputInformation() +{ +} + +const char* mitk::SimulationTemplateReader::GetFileName() const +{ + return m_FileName.c_str(); +} + +void mitk::SimulationTemplateReader::SetFileName(const char* aFileName) +{ + m_FileName = aFileName; +} + +const char* mitk::SimulationTemplateReader::GetFilePattern() const +{ + return m_FilePattern.c_str(); +} + +void mitk::SimulationTemplateReader::SetFilePattern(const char* aFilePattern) +{ + m_FilePattern = aFilePattern; +} + +const char* mitk::SimulationTemplateReader::GetFilePrefix() const +{ + return m_FilePrefix.c_str(); +} + +void mitk::SimulationTemplateReader::SetFilePrefix(const char* aFilePrefix) +{ + m_FilePrefix = aFilePrefix; +} diff --git a/Modules/Simulation/mitkSimulationReader.h b/Modules/Simulation/mitkSimulationTemplateReader.h similarity index 77% copy from Modules/Simulation/mitkSimulationReader.h copy to Modules/Simulation/mitkSimulationTemplateReader.h index 8d8783ac6a..0cbb8d7100 100644 --- a/Modules/Simulation/mitkSimulationReader.h +++ b/Modules/Simulation/mitkSimulationTemplateReader.h @@ -1,59 +1,60 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef mitkSimulationReader_h -#define mitkSimulationReader_h +#ifndef mitkSimulationTemplateReader_h +#define mitkSimulationTemplateReader_h #include #include +#include namespace mitk { - class Simulation_EXPORT SimulationReader : public BaseProcess, FileReader + class Simulation_EXPORT SimulationTemplateReader : public BaseProcess, FileReader { public: static bool CanReadFile(const std::string& filename, const std::string& filePrefix, const std::string& filePattern); - mitkClassMacro(SimulationReader, BaseProcess); + mitkClassMacro(SimulationTemplateReader, BaseProcess); itkNewMacro(Self); const char* GetFileName() const; void SetFileName(const char* aFileName); const char* GetFilePattern() const; void SetFilePattern(const char* aFilePattern); const char* GetFilePrefix() const; void SetFilePrefix(const char* aFilePrefix); protected: void GenerateData(); void GenerateOutputInformation(); private: - SimulationReader(); - ~SimulationReader(); + SimulationTemplateReader(); + ~SimulationTemplateReader(); - SimulationReader(const Self &); + SimulationTemplateReader(const Self &); Self & operator=(const Self &); std::string m_FileName; std::string m_FilePattern; std::string m_FilePrefix; }; } #endif diff --git a/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h b/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h index eeff536474..e58b73a102 100644 --- a/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h +++ b/Modules/ToFHardware/Kinect/mitkKinectDeviceFactory.h @@ -1,87 +1,92 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkKinectDeviceFactory_h #define __mitkKinectDeviceFactory_h #include "mitkKinectModuleExports.h" #include "mitkKinectDevice.h" #include "mitkAbstractToFDeviceFactory.h" #include #include namespace mitk { /** * \brief KinectDeviceFactory is an implementation of the factory pattern to generate Microsoft Kinect devices. * KinectDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new KinectDevices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_KINECTMODULE_EXPORT KinectDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: KinectDeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the Kinect. */ std::string GetFactoryName() { return std::string("Kinect Factory"); } //Interating the Device name on calling the Factory std::string GetCurrentDeviceName() { std::stringstream name; if (m_DeviceNumber>1) { name << "Kinect " << m_DeviceNumber; } else { name << "Kinect "; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a KinectDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { KinectDevice::Pointer device = KinectDevice::New(); //Set default camera intrinsics for the kinect RGB camera. //(OpenNI warps the distance data into the RGB space). mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); pathToDefaulCalibrationFile.append("/CalibrationFiles/Kinect_RGB_camera.xml"); cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + device->SetBoolProperty("HasRGBImage", true); + device->SetBoolProperty("HasAmplitudeImage", false); + device->SetBoolProperty("HasIntensityImage", false); + device->SetBoolProperty("KinectReconstructionMode", true); + return device.GetPointer(); } //Member variable as variable for our DeviceNumber int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h b/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h index da792364d4..56796f6b6b 100644 --- a/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h +++ b/Modules/ToFHardware/MesaSR4000/mitkToFCameraMESASR4000DeviceFactory.h @@ -1,85 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraMESASR4000DeviceFactory_h #define __mitkToFCameraMESASR4000DeviceFactory_h #include "mitkMESASR4000ModuleExports.h" #include "mitkToFCameraMESASR4000Device.h" #include "mitkAbstractToFDeviceFactory.h" #include #include #include namespace mitk { /** * \brief ToFPMDRawPlayerDeviceFactory is an implementation of the factory pattern to generate MESASR4000Devices. * ToFCameraMESASR4000DeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Raw Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_MESASR4000MODULE_EXPORT ToFCameraMESASR4000DeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraMESASR4000DeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the MESASR4000DeviceFactory */ std::string GetFactoryName() { return std::string("MESA SR4000 Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "MESA SR4000 "<< m_DeviceNumber; } else { name << "MESA SR4000"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDRawDataDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraMESASR4000Device::Pointer device = ToFCameraMESASR4000Device::New(); //Set default camera intrinsics for the Mesa-SR4000-camera. mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); pathToDefaulCalibrationFile.append("/CalibrationFiles/Mesa-SR4000_Camera.xml"); cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + device->SetBoolProperty("HasRGBImage", false); + device->SetBoolProperty("HasAmplitudeImage", true); + device->SetBoolProperty("HasIntensityImage", true); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h index 9c9c9c35c6..4d2e129ce1 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDCamCubeDeviceFactory.h @@ -1,87 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDCamCubeDeviceFactory_h #define __mitkToFCameraPMDCamCubeDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDCamCubeDevice.h" #include "mitkAbstractToFDeviceFactory.h" #include #include #include namespace mitk { /** * \brief ToFPMDCamBoardDeviceFactory is an implementation of the factory pattern to generate Cam Cube Devices. * ToFPMDCamCubeDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Cam Cube Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDCamCubeDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDCamCubeDeviceFactory() { this->m_DeviceNumber=1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDCamCube. */ std::string GetFactoryName() { return std::string("PMD Camcube 2.0/3.0 Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD CamCube 2.0/3.0 "<< m_DeviceNumber; } else { name << "PMD CamCube 2.0/3.0 "; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDCamCubeDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDCamCubeDevice::Pointer device = ToFCameraPMDCamCubeDevice::New(); //Set default camera intrinsics for the CamCube Amplitude Camera. mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamCube3_camera.xml"); MITK_INFO <FromXMLFile(pathToDefaulCalibrationFile); device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + device->SetBoolProperty("HasRGBImage", false); + device->SetBoolProperty("HasAmplitudeImage", true); + device->SetBoolProperty("HasIntensityImage", true); return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h index 1ec824224d..f9054dbece 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDPlayerDeviceFactory.h @@ -1,90 +1,93 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDPlayerDeviceFactory_h #define __mitkToFCameraPMDPlayerDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDPlayerDevice.h" #include "mitkAbstractToFDeviceFactory.h" #include #include #include namespace mitk { /** * \brief ToFPMDPlayerDeviceFactory is an implementation of the factory pattern to generate PMD Player Devices. * ToFPMDPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new PMD Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDPlayerDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDPlayerDeviceFactory() { this->m_DeviceNumber=1; } /*! \brief Defining the Factorie´s Name, here for the ToFPMDPlayer. */ std::string GetFactoryName() { return std::string("PMD Player Factory"); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD Player "<< m_DeviceNumber; } else { name << "PMD Player"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDPlayerDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDPlayerDevice::Pointer device = ToFCameraPMDPlayerDevice::New(); //-------------------------If no Intrinsics are specified------------------------------ //Set default camera intrinsics for the PMD-Player. mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); pathToDefaulCalibrationFile.append("/CalibrationFiles/Default_Parameters.xml"); cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); - //------------------------------------------------------------------------------------------ + device->SetBoolProperty("HasRGBImage", false); + device->SetBoolProperty("HasAmplitudeImage", true); + device->SetBoolProperty("HasIntensityImage", true); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h index f4ba0fe70b..f1b84d8004 100644 --- a/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h +++ b/Modules/ToFHardware/PMD/mitkToFCameraPMDRawDataCamCubeDeviceFactory.h @@ -1,86 +1,90 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFCameraPMDRawDataCamCubeDeviceFactory_h #define __mitkToFCameraPMDRawDataCamCubeDeviceFactory_h #include "mitkPMDModuleExports.h" #include "mitkToFCameraPMDRawDataCamCubeDevice.h" #include "mitkAbstractToFDeviceFactory.h" #include #include #include namespace mitk { /** * \brief ToFPMDRawPlayerDeviceFactory is an implementation of the factory pattern to generate Raw Player Devices. * ToFPMDRawPlayerDeviceFactory inherits from AbstractToFDeviceFactory which is a MicroService interface. * This offers users the oppertunity to generate new Raw Player Devices via a global instance of this factory. * @ingroup ToFHardware */ class MITK_PMDMODULE_EXPORT ToFCameraPMDRawDataCamCubeDeviceFactory : public itk::LightObject, public AbstractToFDeviceFactory { public: ToFCameraPMDRawDataCamCubeDeviceFactory() { this->m_DeviceNumber = 1; } /*! \brief Defining the Factorie´s Name, here for the RawDataDeviceFactory. */ std::string GetFactoryName() { return std::string("PMD RAW Data Camcube Factory "); } std::string GetCurrentDeviceName() { std::stringstream name; if(m_DeviceNumber>1) { name << "PMD Raw Data CamCube 2.0/3.0 "<< m_DeviceNumber; } else { name << "PMD Raw Data CamCube 2.0/3.0"; } m_DeviceNumber++; return name.str(); } private: /*! \brief Create an instance of a ToFPMDRawDataDevice. */ ToFCameraDevice::Pointer createToFCameraDevice() { ToFCameraPMDRawDataCamCubeDevice::Pointer device = ToFCameraPMDRawDataCamCubeDevice::New(); //Set default camera intrinsics for the RawDataCamCube-Camera. mitk::CameraIntrinsics::Pointer cameraIntrinsics = mitk::CameraIntrinsics::New(); std::string pathToDefaulCalibrationFile(MITK_TOF_DATA_DIR); pathToDefaulCalibrationFile.append("/CalibrationFiles/PMDCamCube3_camera.xml"); cameraIntrinsics->FromXMLFile(pathToDefaulCalibrationFile); device->SetProperty("CameraIntrinsics", mitk::CameraIntrinsicsProperty::New(cameraIntrinsics)); + device->SetBoolProperty("HasRGBImage", false); + device->SetBoolProperty("HasAmplitudeImage", true); + device->SetBoolProperty("HasIntensityImage", true); + return device.GetPointer(); } int m_DeviceNumber; }; } #endif diff --git a/Modules/ToFHardware/Testing/CMakeLists.txt b/Modules/ToFHardware/Testing/CMakeLists.txt index 153cd81e2e..c091fffd97 100644 --- a/Modules/ToFHardware/Testing/CMakeLists.txt +++ b/Modules/ToFHardware/Testing/CMakeLists.txt @@ -1 +1,18 @@ MITK_CREATE_MODULE_TESTS() + +#Only enabled for Windows and Mac nightlies. +#If you want to run this on linux, just enable the flag in the superbuild. +if(MITK_ENABLE_GUI_TESTING) + +mitkAddCustomModuleTest(mitkPlayerLoadAndRenderDepthDataTest_KinectDepthImage #testname +mitkPlayerLoadAndRenderDepthDataTest #testclassname +Kinect_LiverPhantom_DistanceImage.nrrd #input image +-V ${MITK_DATA_DIR}/ToF-Data/ReferenceScreenshots/Kinect_LiverPhantom_DistanceImage640x480REF.png #reference image +) + +mitkAddCustomModuleTest(mitkPlayerLoadAndRenderRGBDataTest_KinectRGBImage mitkPlayerLoadAndRenderRGBDataTest Kinect_LiverPhantom_RGBImage.nrrd -V ${MITK_DATA_DIR}/ToF-Data/ReferenceScreenshots/Kinect_LiverPhantom_RGBImage640x480REF.png) + +#rendering tests cannot run in parallel +SET_PROPERTY(TEST mitkPlayerLoadAndRenderDepthDataTest_KinectDepthImage mitkPlayerLoadAndRenderRGBDataTest_KinectRGBImage PROPERTY RUN_SERIAL TRUE) + +endif() diff --git a/Modules/ToFHardware/Testing/files.cmake b/Modules/ToFHardware/Testing/files.cmake index b7c8e3aa46..fbff7863fc 100644 --- a/Modules/ToFHardware/Testing/files.cmake +++ b/Modules/ToFHardware/Testing/files.cmake @@ -1,28 +1,16 @@ set(MODULE_TESTS #mitkThreadedToFRawDataReconstructionTest.cpp -# mitkKinectControllerTest.cpp -# mitkKinectDeviceTest.cpp -# mitkToFCameraPMDCamBoardControllerTest.cpp -# mitkToFCameraPMDCamBoardDeviceTest.cpp -# mitkToFCameraPMDRawDataCamBoardDeviceTest.cpp -# mitkToFCameraPMDRawDataCamCubeDeviceTest.cpp -# mitkToFCameraPMDCamCubeControllerTest.cpp -# mitkToFCameraPMDCamCubeDeviceTest.cpp -# mitkToFCameraPMDPlayerControllerTest.cpp -# mitkToFCameraPMDPlayerDeviceTest.cpp -# mitkToFCameraPMDControllerTest.cpp -# mitkToFCameraPMDDeviceTest.cpp -# mitkToFCameraPMDRawDataDeviceTest.cpp - #mitkToFCameraPMDMITKPlayerControllerTest.cpp - #mitkToFCameraPMDMITKPlayerDeviceTest.cpp -# mitkToFCameraPMDO3ControllerTest.cpp -# mitkToFCameraPMDO3DeviceTest.cpp mitkToFImageCsvWriterTest.cpp mitkToFImageGrabberTest.cpp #mitkToFImageRecorderTest.cpp #mitkToFImageRecorderFilterTest.cpp mitkToFImageWriterTest.cpp mitkToFNrrdImageWriterTest.cpp mitkToFOpenCVImageGrabberTest.cpp ) +set(MODULE_CUSTOM_TESTS + mitkPlayerLoadAndRenderDepthDataTest.cpp + mitkPlayerLoadAndRenderRGBDataTest.cpp +) + diff --git a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp new file mode 100644 index 0000000000..0790a6e519 --- /dev/null +++ b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderDepthDataTest.cpp @@ -0,0 +1,106 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//MITK +#include "mitkTestingMacros.h" +#include "mitkRenderingTestHelper.h" +#include "mitkToFCameraMITKPlayerDevice.h" + +//VTK +#include + +#include +#include +#include + + +int mitkPlayerLoadAndRenderDepthDataTest(int argc, char* argv[]) +{ + MITK_TEST_BEGIN("mitkPlayerLoadAndRenderDepthDataTest"); + + try + { + mitk::ToFCameraMITKPlayerDevice::Pointer playerDevice = mitk::ToFCameraMITKPlayerDevice::New(); + + MITK_TEST_CONDITION_REQUIRED(argc >=2, "Testing if enough input parameters are set. Usage: Testname, ImageName (must be in MITK_TOF_DATA_DIR), -V /path/to/reference/screenshot"); + std::string dirname = MITK_TOF_DATA_DIR; + std::string distanceFileName = dirname + "/" + argv[1]; + playerDevice->SetProperty("DistanceImageFileName",mitk::StringProperty::New(distanceFileName)); + + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"The device (player) should not be active before starting."); + MITK_TEST_CONDITION_REQUIRED(playerDevice->ConnectCamera()==true,"ConnectCamera() should return true in case of success."); + MITK_TEST_OUTPUT(<< "Device connected"); + playerDevice->StartCamera(); + MITK_TEST_OUTPUT(<< "Device started"); + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==true,"After starting the device, the device should be active."); + + //initialize an array with the correct size + unsigned int captureWidth = playerDevice->GetCaptureWidth(); + unsigned int captureHeight = playerDevice->GetCaptureHeight(); + unsigned int numberOfPixels = captureWidth*captureHeight; + float* distances = new float[numberOfPixels]; + int imageSequence = 0; + + //fill the array with the device output + playerDevice->GetDistances(distances,imageSequence); + + //initialize an image and fill it with the array + unsigned int dimension[2]; + dimension[0] = captureWidth; + dimension[1] = captureHeight; + mitk::Image::Pointer mitkDepthImage = mitk::Image::New(); + mitkDepthImage->Initialize(mitk::PixelType(mitk::MakeScalarPixelType()), 2, dimension,1); + mitkDepthImage->SetSlice(distances); + + //create a node to pass it to the mitkRenderingTestHelper + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(mitkDepthImage); + + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //Set the opacity for all images + //for now this test renders in sagittal view direction + renderingHelper.AddNodeToStorage(node); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/output.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + //Wait some time to avoid threading issues. + itksys::SystemTools::Delay(1000); + playerDevice->StopCamera(); + MITK_TEST_OUTPUT(<< "Device stopped"); + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"After stopping the device, the device should be inactive."); + MITK_TEST_CONDITION_REQUIRED(playerDevice->DisconnectCamera()==true, "DisconnectCamera() should return true in case of success."); + MITK_TEST_OUTPUT(<< "Device disconnected"); + delete[] distances; + } + catch(std::exception &e) + { + MITK_ERROR << "Unknown exception occured: " << e.what(); + } + + MITK_TEST_END(); +} diff --git a/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp new file mode 100644 index 0000000000..0cce6d864f --- /dev/null +++ b/Modules/ToFHardware/Testing/mitkPlayerLoadAndRenderRGBDataTest.cpp @@ -0,0 +1,107 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//MITK +#include "mitkTestingMacros.h" +#include "mitkRenderingTestHelper.h" +#include "mitkToFCameraMITKPlayerDevice.h" + +//VTK +#include + +#include +#include +#include + + +int mitkPlayerLoadAndRenderRGBDataTest(int argc, char* argv[]) +{ + MITK_TEST_BEGIN("mitkPlayerLoadAndRenderRGBDataTest"); + + try + { + mitk::ToFCameraMITKPlayerDevice::Pointer playerDevice = mitk::ToFCameraMITKPlayerDevice::New(); + + MITK_TEST_CONDITION_REQUIRED(argc >=2, "Testing if enough input parameters are set. Usage: Testname, ImageName (must be in MITK_TOF_DATA_DIR), -V /path/to/reference/screenshot"); + std::string dirname = MITK_TOF_DATA_DIR; + std::string rgbFileName = dirname + "/" + argv[1]; + playerDevice->SetProperty("RGBImageFileName",mitk::StringProperty::New(rgbFileName)); + + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"The device (player) should not be active before starting."); + MITK_TEST_CONDITION_REQUIRED(playerDevice->ConnectCamera()==true,"ConnectCamera() should return true in case of success."); + MITK_TEST_OUTPUT(<< "Device connected"); + playerDevice->StartCamera(); + MITK_TEST_OUTPUT(<< "Device started"); + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==true,"After starting the device, the device should be active."); + + //initialize an array with the correct size + unsigned int captureWidth = playerDevice->GetCaptureWidth(); + unsigned int captureHeight = playerDevice->GetCaptureHeight(); + unsigned int numberOfPixels = captureWidth*captureHeight; + unsigned char* rgbDataArray = new unsigned char[numberOfPixels*3]; + int imageSequence = 0; + + //fill the array with the device output + playerDevice->GetRgb(rgbDataArray, imageSequence); + + //initialize an image and fill it with the array + unsigned int dimension[2]; + dimension[0] = captureWidth; + dimension[1] = captureHeight; + mitk::Image::Pointer rgbImage = mitk::Image::New(); + rgbImage->Initialize(mitk::PixelType(mitk::MakePixelType, 3>()), 2, dimension,1); + rgbImage->SetSlice(rgbDataArray); + + //create a node to pass it to the mitkRenderingTestHelper + mitk::DataNode::Pointer node = mitk::DataNode::New(); + node->SetData(rgbImage); + + // load all arguments into a datastorage, take last argument as reference rendering + // setup a renderwindow of fixed size X*Y + // render the datastorage + // compare rendering to reference image + mitkRenderingTestHelper renderingHelper(640, 480, argc, argv); + //Set the opacity for all images + //for now this test renders in sagittal view direction + renderingHelper.AddNodeToStorage(node); + renderingHelper.Render(); + + //use this to generate a reference screenshot or save the file: + bool generateReferenceScreenshot = false; + if(generateReferenceScreenshot) + { + renderingHelper.SaveReferenceScreenShot("/home/kilgus/Pictures/output.png"); + } + + //### Usage of CompareRenderWindowAgainstReference: See docu of mitkRrenderingTestHelper + MITK_TEST_CONDITION( renderingHelper.CompareRenderWindowAgainstReference(argc, argv) == true, "CompareRenderWindowAgainstReference test result positive?" ); + + //Wait some time to avoid threading issues. + itksys::SystemTools::Delay(1000); + playerDevice->StopCamera(); + MITK_TEST_OUTPUT(<< "Device stopped"); + MITK_TEST_CONDITION_REQUIRED(playerDevice->IsCameraActive()==false,"After stopping the device, the device should be inactive."); + MITK_TEST_CONDITION_REQUIRED(playerDevice->DisconnectCamera()==true, "DisconnectCamera() should return true in case of success."); + MITK_TEST_OUTPUT(<< "Device disconnected"); + delete[] rgbDataArray; + } + catch(std::exception &e) + { + MITK_ERROR << "Unknown exception occured: " << e.what(); + } + + MITK_TEST_END(); +} diff --git a/Modules/ToFHardware/mitkToFCameraDevice.cpp b/Modules/ToFHardware/mitkToFCameraDevice.cpp index f56d85b4e8..490a4bb78a 100644 --- a/Modules/ToFHardware/mitkToFCameraDevice.cpp +++ b/Modules/ToFHardware/mitkToFCameraDevice.cpp @@ -1,188 +1,195 @@ /*=================================================================== 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 "mitkToFCameraDevice.h" #include //Microservices #include #include "mitkModuleContext.h" namespace mitk { ToFCameraDevice::ToFCameraDevice():m_BufferSize(1),m_MaxBufferSize(100),m_CurrentPos(-1),m_FreePos(0), m_CaptureWidth(204),m_CaptureHeight(204),m_PixelNumber(41616),m_SourceDataSize(0), m_ThreadID(0),m_CameraActive(false),m_CameraConnected(false),m_ImageSequence(0) { this->m_AmplitudeArray = NULL; this->m_IntensityArray = NULL; this->m_DistanceArray = NULL; this->m_PropertyList = mitk::PropertyList::New(); + //By default, all devices have no further images (just a distance image) + //If a device provides more data (e.g. RGB, Intensity, Amplitde images, + //the property has to be true. + this->m_PropertyList->SetBoolProperty("HasRGBImage", false); + this->m_PropertyList->SetBoolProperty("HasIntensityImage", false); + this->m_PropertyList->SetBoolProperty("HasAmplitudeImage", false); + this->m_MultiThreader = itk::MultiThreader::New(); this->m_ImageMutex = itk::FastMutexLock::New(); this->m_CameraActiveMutex = itk::FastMutexLock::New(); this->m_RGBImageWidth = this->m_CaptureWidth; this->m_RGBImageHeight = this->m_CaptureHeight; this->m_RGBPixelNumber = this->m_RGBImageWidth* this->m_RGBImageHeight; } ToFCameraDevice::~ToFCameraDevice() { } void ToFCameraDevice::SetBoolProperty( const char* propertyKey, bool boolValue ) { SetProperty(propertyKey, mitk::BoolProperty::New(boolValue)); } void ToFCameraDevice::SetIntProperty( const char* propertyKey, int intValue ) { SetProperty(propertyKey, mitk::IntProperty::New(intValue)); } void ToFCameraDevice::SetFloatProperty( const char* propertyKey, float floatValue ) { SetProperty(propertyKey, mitk::FloatProperty::New(floatValue)); } void ToFCameraDevice::SetStringProperty( const char* propertyKey, const char* stringValue ) { SetProperty(propertyKey, mitk::StringProperty::New(stringValue)); } void ToFCameraDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { this->m_PropertyList->SetProperty(propertyKey, propertyValue); } BaseProperty* ToFCameraDevice::GetProperty(const char *propertyKey) { return this->m_PropertyList->GetProperty(propertyKey); } bool ToFCameraDevice::GetBoolProperty(const char *propertyKey, bool& boolValue) { mitk::BoolProperty::Pointer boolprop = dynamic_cast(this->GetProperty(propertyKey)); if(boolprop.IsNull()) return false; boolValue = boolprop->GetValue(); return true; } bool ToFCameraDevice::GetStringProperty(const char *propertyKey, std::string& string) { mitk::StringProperty::Pointer stringProp = dynamic_cast(this->GetProperty(propertyKey)); if(stringProp.IsNull()) { return false; } else { string = stringProp->GetValue(); return true; } } bool ToFCameraDevice::GetIntProperty(const char *propertyKey, int& integer) { mitk::IntProperty::Pointer intProp = dynamic_cast(this->GetProperty(propertyKey)); if(intProp.IsNull()) { return false; } else { integer = intProp->GetValue(); return true; } } void ToFCameraDevice::CleanupPixelArrays() { if (m_IntensityArray) { delete [] m_IntensityArray; } if (m_DistanceArray) { delete [] m_DistanceArray; } if (m_AmplitudeArray) { delete [] m_AmplitudeArray; } } void ToFCameraDevice::AllocatePixelArrays() { // free memory if it was already allocated CleanupPixelArrays(); // allocate buffer this->m_IntensityArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_IntensityArray[i]=0.0;} this->m_DistanceArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_DistanceArray[i]=0.0;} this->m_AmplitudeArray = new float[this->m_PixelNumber]; for(int i=0; im_PixelNumber; i++) {this->m_AmplitudeArray[i]=0.0;} } int ToFCameraDevice::GetRGBCaptureWidth() { return this->m_RGBImageWidth; } int ToFCameraDevice::GetRGBCaptureHeight() { return this->m_RGBImageHeight; } void ToFCameraDevice::StopCamera() { m_CameraActiveMutex->Lock(); m_CameraActive = false; m_CameraActiveMutex->Unlock(); itksys::SystemTools::Delay(100); if (m_MultiThreader.IsNotNull()) { m_MultiThreader->TerminateThread(m_ThreadID); } // wait a little to make sure that the thread is terminated itksys::SystemTools::Delay(100); } bool ToFCameraDevice::IsCameraActive() { m_CameraActiveMutex->Lock(); bool ok = m_CameraActive; m_CameraActiveMutex->Unlock(); return ok; } bool ToFCameraDevice::ConnectCamera() { // Prepare connection, fail if this fails. if (! this->OnConnectCamera()) return false; // Get Context and Module mitk::ModuleContext* context = GetModuleContext(); return true; } bool ToFCameraDevice::IsCameraConnected() { return m_CameraConnected; } } diff --git a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp index 5782ec28fd..02c02a5002 100644 --- a/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp +++ b/Modules/ToFHardware/mitkToFCameraMITKPlayerDevice.cpp @@ -1,399 +1,402 @@ /*=================================================================== 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 "mitkToFCameraMITKPlayerDevice.h" #include "mitkToFCameraMITKPlayerController.h" #include "mitkRealTimeClock.h" #include "itkMultiThreader.h" #include namespace mitk { ToFCameraMITKPlayerDevice::ToFCameraMITKPlayerDevice() : m_DistanceDataBuffer(NULL), m_AmplitudeDataBuffer(NULL), m_IntensityDataBuffer(NULL), m_RGBDataBuffer(NULL) { m_Controller = ToFCameraMITKPlayerController::New(); } ToFCameraMITKPlayerDevice::~ToFCameraMITKPlayerDevice() { DisconnectCamera(); CleanUpDataBuffers(); } bool ToFCameraMITKPlayerDevice::OnConnectCamera() { bool ok = m_Controller->OpenCameraConnection(); if (ok) { this->m_CaptureWidth = m_Controller->GetCaptureWidth(); this->m_CaptureHeight = m_Controller->GetCaptureHeight(); this->m_RGBImageWidth = m_Controller->GetCaptureWidth(); this->m_RGBImageHeight = m_Controller->GetCaptureHeight(); this->m_PixelNumber = this->m_CaptureWidth * this->m_CaptureHeight; AllocatePixelArrays(); AllocateDataBuffers(); m_CameraConnected = true; } return ok; } bool ToFCameraMITKPlayerDevice::DisconnectCamera() { bool ok = m_Controller->CloseCameraConnection(); if (ok) { m_CameraConnected = false; } return ok; } void ToFCameraMITKPlayerDevice::StartCamera() { if (m_CameraConnected) { // get the first image this->m_Controller->UpdateCamera(); this->m_ImageMutex->Lock(); this->m_Controller->GetDistances(this->m_DistanceDataBuffer[this->m_FreePos]); this->m_Controller->GetAmplitudes(this->m_AmplitudeDataBuffer[this->m_FreePos]); this->m_Controller->GetIntensities(this->m_IntensityDataBuffer[this->m_FreePos]); this->m_Controller->GetRgb(this->m_RGBDataBuffer[this->m_FreePos]); this->m_FreePos = (this->m_FreePos+1) % this->m_BufferSize; this->m_CurrentPos = (this->m_CurrentPos+1) % this->m_BufferSize; this->m_ImageSequence++; this->m_ImageMutex->Unlock(); this->m_CameraActiveMutex->Lock(); this->m_CameraActive = true; this->m_CameraActiveMutex->Unlock(); this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); // wait a little to make sure that the thread is started itksys::SystemTools::Delay(10); } else { MITK_INFO<<"Camera not connected"; } } void ToFCameraMITKPlayerDevice::UpdateCamera() { m_Controller->UpdateCamera(); } ITK_THREAD_RETURN_TYPE ToFCameraMITKPlayerDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == NULL) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == NULL) { return ITK_THREAD_RETURN_VALUE; } ToFCameraMITKPlayerDevice* toFCameraDevice = (ToFCameraMITKPlayerDevice*)pInfo->UserData; if (toFCameraDevice!=NULL) { mitk::RealTimeClock::Pointer realTimeClock; realTimeClock = mitk::RealTimeClock::New(); int n = 100; double t1, t2; t1 = realTimeClock->GetCurrentStamp(); bool overflow = false; bool printStatus = false; while (toFCameraDevice->IsCameraActive()) { // update the ToF camera toFCameraDevice->UpdateCamera(); // get image data from controller and write it to the according buffer toFCameraDevice->m_Controller->GetDistances(toFCameraDevice->m_DistanceDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetAmplitudes(toFCameraDevice->m_AmplitudeDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetIntensities(toFCameraDevice->m_IntensityDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->m_Controller->GetRgb(toFCameraDevice->m_RGBDataBuffer[toFCameraDevice->m_FreePos]); toFCameraDevice->Modified(); /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ toFCameraDevice->m_ImageMutex->Lock(); toFCameraDevice->m_FreePos = (toFCameraDevice->m_FreePos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; toFCameraDevice->m_ImageSequence++; if (toFCameraDevice->m_FreePos == toFCameraDevice->m_CurrentPos) { // buffer overflow //MITK_INFO << "Buffer overflow!! "; //toFCameraDevice->m_CurrentPos = (toFCameraDevice->m_CurrentPos+1) % toFCameraDevice->m_BufferSize; //toFCameraDevice->m_ImageSequence++; overflow = true; } if (toFCameraDevice->m_ImageSequence % n == 0) { printStatus = true; } toFCameraDevice->m_ImageMutex->Unlock(); if (overflow) { //itksys::SystemTools::Delay(10); overflow = false; } /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! END TODO Buffer Handling currently only works for buffer size 1 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ // print current framerate if (printStatus) { t2 = realTimeClock->GetCurrentStamp() - t1; MITK_INFO << " Framerate (fps): " << n / (t2/1000) << " Sequence: " << toFCameraDevice->m_ImageSequence; t1 = realTimeClock->GetCurrentStamp(); printStatus = false; } } // end of while loop } return ITK_THREAD_RETURN_VALUE; } // TODO: Buffer size currently set to 1. Once Buffer handling is working correctly, method may be reactivated // void ToFCameraMITKPlayerDevice::ResetBuffer(int bufferSize) // { // this->m_BufferSize = bufferSize; // this->m_CurrentPos = -1; // this->m_FreePos = 0; // } void ToFCameraMITKPlayerDevice::GetAmplitudes(float* amplitudeArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write amplitude image data to float array for (int i=0; im_PixelNumber; i++) { amplitudeArray[i] = this->m_AmplitudeDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetIntensities(float* intensityArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write intensity image data to float array for (int i=0; im_PixelNumber; i++) { intensityArray[i] = this->m_IntensityDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetDistances(float* distanceArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write distance image data to float array for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetRgb(unsigned char* rgbArray, int& imageSequence) { m_ImageMutex->Lock(); /*!!!!!!!!!!!!!!!!!!!!!! TODO Buffer handling??? !!!!!!!!!!!!!!!!!!!!!!!!*/ // write intensity image data to unsigned char array for (int i=0; im_PixelNumber*3; i++) { rgbArray[i] = this->m_RGBDataBuffer[this->m_CurrentPos][i]; } imageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::GetAllImages(float* distanceArray, float* amplitudeArray, float* intensityArray, char* /*sourceDataArray*/, int requiredImageSequence, int& capturedImageSequence, unsigned char* rgbDataArray) { /*!!!!!!!!!!!!!!!!!!!!!! TODO Document this method! !!!!!!!!!!!!!!!!!!!!!!!!*/ m_ImageMutex->Lock(); //check for empty buffer if (this->m_ImageSequence < 0) { // buffer empty MITK_INFO << "Buffer empty!! "; capturedImageSequence = this->m_ImageSequence; m_ImageMutex->Unlock(); return; } // determine position of image in buffer int pos = 0; if ((requiredImageSequence < 0) || (requiredImageSequence > this->m_ImageSequence)) { capturedImageSequence = this->m_ImageSequence; pos = this->m_CurrentPos; } else if (requiredImageSequence <= this->m_ImageSequence - this->m_BufferSize) { capturedImageSequence = (this->m_ImageSequence - this->m_BufferSize) + 1; pos = (this->m_CurrentPos + 1) % this->m_BufferSize; } else // (requiredImageSequence > this->m_ImageSequence - this->m_BufferSize) && (requiredImageSequence <= this->m_ImageSequence) { capturedImageSequence = requiredImageSequence; pos = (this->m_CurrentPos + (10-(this->m_ImageSequence - requiredImageSequence))) % this->m_BufferSize; } if(this->m_DistanceDataBuffer&&this->m_AmplitudeDataBuffer&&this->m_IntensityDataBuffer&&this->m_RGBDataBuffer) { // write image data to float arrays for (int i=0; im_PixelNumber; i++) { distanceArray[i] = this->m_DistanceDataBuffer[pos][i]; amplitudeArray[i] = this->m_AmplitudeDataBuffer[pos][i]; intensityArray[i] = this->m_IntensityDataBuffer[pos][i]; if (rgbDataArray) { rgbDataArray[i] = this->m_RGBDataBuffer[pos][i]; } } if (rgbDataArray) { for (int j=this->m_PixelNumber; jm_PixelNumber*3; j++) { rgbDataArray[j] = this->m_RGBDataBuffer[pos][j]; } } } m_ImageMutex->Unlock(); } void ToFCameraMITKPlayerDevice::SetInputFileName(std::string inputFileName) { this->m_InputFileName = inputFileName; this->m_Controller->SetInputFileName(inputFileName); } void ToFCameraMITKPlayerDevice::SetProperty( const char *propertyKey, BaseProperty* propertyValue ) { this->m_PropertyList->SetProperty(propertyKey, propertyValue); ToFCameraMITKPlayerController::Pointer myController = dynamic_cast(this->m_Controller.GetPointer()); std::string strValue; GetStringProperty(propertyKey, strValue); if (strcmp(propertyKey, "DistanceImageFileName") == 0) { myController->SetDistanceImageFileName(strValue); } else if (strcmp(propertyKey, "AmplitudeImageFileName") == 0) { + this->m_PropertyList->SetBoolProperty("HasAmplitudeImage", true); myController->SetAmplitudeImageFileName(strValue); } else if (strcmp(propertyKey, "IntensityImageFileName") == 0) { + this->m_PropertyList->SetBoolProperty("HasIntensityImage", true); myController->SetIntensityImageFileName(strValue); } else if (strcmp(propertyKey, "RGBImageFileName") == 0) { + this->m_PropertyList->SetBoolProperty("HasRGBImage", true); myController->SetRGBImageFileName(strValue); } } void ToFCameraMITKPlayerDevice::CleanUpDataBuffers() { if (m_DistanceDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_DistanceDataBuffer[i]; } delete[] this->m_DistanceDataBuffer; } if (m_AmplitudeDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_AmplitudeDataBuffer[i]; } delete[] this->m_AmplitudeDataBuffer; } if (m_IntensityDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_IntensityDataBuffer[i]; } delete[] this->m_IntensityDataBuffer; } if (m_RGBDataBuffer) { for(int i=0; im_MaxBufferSize; i++) { delete[] this->m_RGBDataBuffer[i]; } delete[] this->m_RGBDataBuffer; } } void ToFCameraMITKPlayerDevice::AllocateDataBuffers() { // free memory if it was already allocated this->CleanUpDataBuffers(); // allocate buffers this->m_DistanceDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_DistanceDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_AmplitudeDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_AmplitudeDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_IntensityDataBuffer = new float*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_IntensityDataBuffer[i] = new float[this->m_PixelNumber]; } this->m_RGBDataBuffer = new unsigned char*[this->m_MaxBufferSize]; for(int i=0; im_MaxBufferSize; i++) { this->m_RGBDataBuffer[i] = new unsigned char[this->m_PixelNumber*3]; } } } diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 4e4182cfbb..0ee96249d6 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,46 +1,48 @@ # Plug-ins must be ordered according to their dependencies set(MITK_EXT_PLUGINS org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.diffusionimaging:OFF + org.mitk.simulation:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF + org.mitk.gui.qt.properties:OFF org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.dtiatlasapp:OFF org.mitk.gui.qt.examples:OFF org.mitk.gui.qt.examplesopencv:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.meshdecimation:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.registration:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF ) diff --git a/Plugins/org.mitk.gui.qt.datamanager/files.cmake b/Plugins/org.mitk.gui.qt.datamanager/files.cmake index 9fdc79856e..c4a92460d6 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/files.cmake +++ b/Plugins/org.mitk.gui.qt.datamanager/files.cmake @@ -1,52 +1,43 @@ set(SRC_CPP_FILES berrySingleNodeSelection.cpp QmitkDataManagerView.cpp QmitkDataManagerPreferencePage.cpp QmitkDataManagerHotkeysPrefPage.cpp ) set(INTERNAL_CPP_FILES mitkPluginActivator.cpp - QmitkLineEdit.cpp QmitkPropertyListView.cpp - QmitkPropertyTreeItem.cpp - QmitkPropertyTreeFilterProxyModel.cpp - QmitkPropertyTreeModel.cpp - QmitkPropertyTreeView.cpp QmitkNodeTableViewKeyFilter.cpp QmitkInfoDialog.cpp ) set(MOC_H_FILES src/QmitkDataManagerView.h src/QmitkDataManagerPreferencePage.h src/QmitkDataManagerHotkeysPrefPage.h - src/internal/QmitkLineEdit.h src/internal/QmitkNodeTableViewKeyFilter.h src/internal/QmitkPropertyListView.h - src/internal/QmitkPropertyTreeFilterProxyModel.h - src/internal/QmitkPropertyTreeModel.h - src/internal/QmitkPropertyTreeView.h src/internal/QmitkInfoDialog.h src/internal/mitkPluginActivator.h ) set(CPP_FILES ) set(CACHED_RESOURCE_FILES plugin.xml resources/DataManager_48.png resources/propertylist.png ) set(QRC_FILES resources/datamanager.qrc ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp index 30a48891bd..b4f8ae1be8 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.cpp @@ -1,97 +1,102 @@ /*=================================================================== 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 "QmitkDataManagerPreferencePage.h" #include "QmitkDataManagerView.h" #include #include #include #include #include #include QmitkDataManagerPreferencePage::QmitkDataManagerPreferencePage() : m_MainControl(0) { } void QmitkDataManagerPreferencePage::Init(berry::IWorkbench::Pointer ) { } void QmitkDataManagerPreferencePage::CreateQtControl(QWidget* parent) { berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); m_DataManagerPreferencesNode = prefService->GetSystemPreferences()->Node(QmitkDataManagerView::VIEW_ID); m_MainControl = new QWidget(parent); m_EnableSingleEditing = new QCheckBox; m_PlaceNewNodesOnTop = new QCheckBox; m_ShowHelperObjects = new QCheckBox; m_ShowNodesContainingNoData = new QCheckBox; + m_GlobalReinitOnNodeDelete = new QCheckBox; m_UseSurfaceDecimation = new QCheckBox; QFormLayout *formLayout = new QFormLayout; formLayout->addRow("&Single click property editing:", m_EnableSingleEditing); formLayout->addRow("&Place new nodes on top:", m_PlaceNewNodesOnTop); formLayout->addRow("&Show helper objects:", m_ShowHelperObjects); formLayout->addRow("&Show nodes containing no data", m_ShowNodesContainingNoData); + formLayout->addRow("&Call global reinit if node is deleted", m_GlobalReinitOnNodeDelete); formLayout->addRow("&Use surface decimation:", m_UseSurfaceDecimation); m_MainControl->setLayout(formLayout); this->Update(); } QWidget* QmitkDataManagerPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkDataManagerPreferencePage::PerformOk() { m_DataManagerPreferencesNode->PutBool("Single click property editing" , m_EnableSingleEditing->isChecked()); m_DataManagerPreferencesNode->PutBool("Place new nodes on top" , m_PlaceNewNodesOnTop->isChecked()); m_DataManagerPreferencesNode->PutBool("Show helper objects" , m_ShowHelperObjects->isChecked()); m_DataManagerPreferencesNode->PutBool("Show nodes containing no data" , m_ShowNodesContainingNoData->isChecked()); + m_DataManagerPreferencesNode->PutBool("Call global reinit if node is deleted" + , m_GlobalReinitOnNodeDelete->isChecked()); m_DataManagerPreferencesNode->PutBool("Use surface decimation" , m_UseSurfaceDecimation->isChecked()); return true; } void QmitkDataManagerPreferencePage::PerformCancel() { } void QmitkDataManagerPreferencePage::Update() { m_EnableSingleEditing->setChecked(m_DataManagerPreferencesNode->GetBool("Single click property editing", true)); m_PlaceNewNodesOnTop->setChecked(m_DataManagerPreferencesNode->GetBool("Place new nodes on top", true)); m_ShowHelperObjects->setChecked(m_DataManagerPreferencesNode->GetBool("Show helper objects", false)); m_ShowNodesContainingNoData->setChecked(m_DataManagerPreferencesNode->GetBool("Show nodes containing no data", false)); m_UseSurfaceDecimation->setChecked(m_DataManagerPreferencesNode->GetBool("Use surface decimation", true)); + m_GlobalReinitOnNodeDelete->setChecked(m_DataManagerPreferencesNode->GetBool("Call global reinit if node is deleted", true)); } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h index 41c1d47666..149b161c9f 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerPreferencePage.h @@ -1,67 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKDATAMANAGERPREFERENCEPAGE_H_ #define QMITKDATAMANAGERPREFERENCEPAGE_H_ #include "berryIQtPreferencePage.h" #include #include class QWidget; class QCheckBox; struct MITK_QT_DATAMANAGER QmitkDataManagerPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkDataManagerPreferencePage(); void Init(berry::IWorkbench::Pointer workbench); void CreateQtControl(QWidget* widget); QWidget* GetQtControl() const; /// /// \see IPreferencePage::PerformOk() /// virtual bool PerformOk(); /// /// \see IPreferencePage::PerformCancel() /// virtual void PerformCancel(); /// /// \see IPreferencePage::Update() /// virtual void Update(); protected: QWidget* m_MainControl; QCheckBox* m_EnableSingleEditing; QCheckBox* m_PlaceNewNodesOnTop; QCheckBox* m_ShowHelperObjects; QCheckBox* m_ShowNodesContainingNoData; + QCheckBox* m_GlobalReinitOnNodeDelete; QCheckBox* m_UseSurfaceDecimation; berry::IPreferences::Pointer m_DataManagerPreferencesNode; }; #endif /* QMITKDATAMANAGERPREFERENCEPAGE_H_ */ diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp index 5c23ba5cb3..1559bf6db5 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.cpp @@ -1,942 +1,950 @@ /*=================================================================== 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 "QmitkDataManagerView.h" #include //# Own Includes //## mitk #include "mitkDataStorageEditorInput.h" #include "mitkIDataStorageReference.h" #include "mitkNodePredicateDataType.h" #include "mitkCoreObjectFactory.h" #include "mitkPACSPlugin.h" #include "mitkDataNodeFactory.h" #include "mitkColorProperty.h" #include "mitkCommon.h" #include "mitkDelegateManager.h" #include "mitkNodePredicateData.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkEnumerationProperty.h" #include "mitkProperties.h" #include #include #include #include //## Qmitk #include #include #include #include #include #include #include #include "src/internal/QmitkNodeTableViewKeyFilter.h" #include "src/internal/QmitkInfoDialog.h" //## Berry #include #include #include #include #include #include //# Toolkit Includes #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 "mitkDataNodeObject.h" #include "mitkIContextMenuAction.h" #include "berryIExtensionPointService.h" const std::string QmitkDataManagerView::VIEW_ID = "org.mitk.views.datamanager"; QmitkDataManagerView::QmitkDataManagerView() + : m_GlobalReinitOnNodeDelete(true) { } QmitkDataManagerView::~QmitkDataManagerView() { //Remove all registered actions from each descriptor for (std::vector< std::pair< QmitkNodeDescriptor*, QAction* > >::iterator it = m_DescriptorActionList.begin();it != m_DescriptorActionList.end(); it++) { // first== the NodeDescriptor; second== the registered QAction (it->first)->RemoveAction(it->second); } } void QmitkDataManagerView::CreateQtPartControl(QWidget* parent) { m_CurrentRowCount = 0; m_Parent = parent; //# Preferences berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node(VIEW_ID)) .Cast(); assert( prefs ); prefs->OnChanged.AddListener( berry::MessageDelegate1( this , &QmitkDataManagerView::OnPreferencesChanged ) ); //# GUI m_NodeTreeModel = new QmitkDataStorageTreeModel(this->GetDataStorage()); m_NodeTreeModel->setParent( parent ); m_NodeTreeModel->SetPlaceNewNodesOnTop( prefs->GetBool("Place new nodes on top", true) ); m_NodeTreeModel->SetShowHelperObjects( prefs->GetBool("Show helper objects", false) ); m_NodeTreeModel->SetShowNodesContainingNoData( prefs->GetBool("Show nodes containing no data", false) ); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); //# Tree View (experimental) m_NodeTreeView = new QTreeView; m_NodeTreeView->setSelectionMode( QAbstractItemView::ExtendedSelection ); m_NodeTreeView->setSelectionBehavior( QAbstractItemView::SelectRows ); m_NodeTreeView->setAlternatingRowColors(true); m_NodeTreeView->setDragEnabled(true); m_NodeTreeView->setDropIndicatorShown(true); m_NodeTreeView->setAcceptDrops(true); m_NodeTreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_NodeTreeView->setModel(m_NodeTreeModel); m_NodeTreeView->setTextElideMode(Qt::ElideMiddle); m_NodeTreeView->installEventFilter(new QmitkNodeTableViewKeyFilter(this)); QObject::connect( m_NodeTreeView, SIGNAL(customContextMenuRequested(const QPoint&)) , this, SLOT(NodeTableViewContextMenuRequested(const QPoint&)) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsInserted (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsInserted ( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeModel, SIGNAL(rowsRemoved (const QModelIndex&, int, int)) , this, SLOT(NodeTreeViewRowsRemoved( const QModelIndex&, int, int )) ); QObject::connect( m_NodeTreeView->selectionModel() , SIGNAL( selectionChanged ( const QItemSelection &, const QItemSelection & ) ) , this , SLOT( NodeSelectionChanged ( const QItemSelection &, const QItemSelection & ) ) ); //# m_NodeMenu m_NodeMenu = new QMenu(m_NodeTreeView); // # Actions berry::IEditorRegistry* editorRegistry = berry::PlatformUI::GetWorkbench()->GetEditorRegistry(); std::list editors = editorRegistry->GetEditors("*.mitk"); if (editors.size() > 1) { m_ShowInMapper = new QSignalMapper(this); foreach(berry::IEditorDescriptor::Pointer descriptor, editors) { QAction* action = new QAction(QString::fromStdString(descriptor->GetLabel()), this); m_ShowInActions << action; m_ShowInMapper->connect(action, SIGNAL(triggered()), m_ShowInMapper, SLOT(map())); m_ShowInMapper->setMapping(action, QString::fromStdString(descriptor->GetId())); } connect(m_ShowInMapper, SIGNAL(mapped(QString)), this, SLOT(ShowIn(QString))); } QmitkNodeDescriptor* unknownDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetUnknownDataNodeDescriptor(); QmitkNodeDescriptor* imageDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Image"); QmitkNodeDescriptor* surfaceDataNodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor("Surface"); QAction* globalReinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Global Reinit", this); QObject::connect( globalReinitAction, SIGNAL( triggered(bool) ) , this, SLOT( GlobalReinit(bool) ) ); unknownDataNodeDescriptor->AddAction(globalReinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, globalReinitAction)); QAction* saveAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Save_48.png"), "Save...", this); QObject::connect( saveAction, SIGNAL( triggered(bool) ) , this, SLOT( SaveSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(saveAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,saveAction)); QAction* removeAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Remove_48.png"), "Remove", this); QObject::connect( removeAction, SIGNAL( triggered(bool) ) , this, SLOT( RemoveSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(removeAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,removeAction)); QAction* reinitAction = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/Refresh_48.png"), "Reinit", this); QObject::connect( reinitAction, SIGNAL( triggered(bool) ) , this, SLOT( ReinitSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(reinitAction); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,reinitAction)); // find contextMenuAction extension points and add them to the node descriptor berry::IExtensionPointService::Pointer extensionPointService = berry::Platform::GetExtensionPointService(); berry::IConfigurationElement::vector cmActions( extensionPointService->GetConfigurationElementsFor("org.mitk.gui.qt.datamanager.contextMenuActions") ); berry::IConfigurationElement::vector::iterator cmActionsIt; std::string cmNodeDescriptorName; std::string cmLabel; std::string cmIcon; std::string cmClass; QmitkNodeDescriptor* tmpDescriptor; QAction* contextMenuAction; QVariant cmActionDataIt; m_ConfElements.clear(); int i=1; for (cmActionsIt = cmActions.begin() ; cmActionsIt != cmActions.end() ; ++cmActionsIt) { cmIcon.erase(); if((*cmActionsIt)->GetAttribute("nodeDescriptorName", cmNodeDescriptorName) && (*cmActionsIt)->GetAttribute("label", cmLabel) && (*cmActionsIt)->GetAttribute("class", cmClass)) { (*cmActionsIt)->GetAttribute("icon", cmIcon); // create context menu entry here tmpDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(QString::fromStdString(cmNodeDescriptorName)); if(!tmpDescriptor) { MITK_WARN << "cannot add action \"" << cmLabel << "\" because descriptor " << cmNodeDescriptorName << " does not exist"; continue; } contextMenuAction = new QAction( QString::fromStdString(cmLabel), parent); tmpDescriptor->AddAction(contextMenuAction); m_DescriptorActionList.push_back(std::pair(tmpDescriptor,contextMenuAction)); m_ConfElements[contextMenuAction] = *cmActionsIt; cmActionDataIt.setValue(i); contextMenuAction->setData( cmActionDataIt ); connect( contextMenuAction, SIGNAL( triggered(bool) ) , this, SLOT( ContextMenuActionTriggered(bool) ) ); ++i; } } m_OpacitySlider = new QSlider; m_OpacitySlider->setMinimum(0); m_OpacitySlider->setMaximum(100); m_OpacitySlider->setOrientation(Qt::Horizontal); QObject::connect( m_OpacitySlider, SIGNAL( valueChanged(int) ) , this, SLOT( OpacityChanged(int) ) ); QLabel* _OpacityLabel = new QLabel("Opacity: "); QHBoxLayout* _OpacityWidgetLayout = new QHBoxLayout; _OpacityWidgetLayout->setContentsMargins(4,4,4,4); _OpacityWidgetLayout->addWidget(_OpacityLabel); _OpacityWidgetLayout->addWidget(m_OpacitySlider); QWidget* _OpacityWidget = new QWidget; _OpacityWidget->setLayout(_OpacityWidgetLayout); QWidgetAction* opacityAction = new QWidgetAction(this); opacityAction ->setDefaultWidget(_OpacityWidget); QObject::connect( opacityAction , SIGNAL( changed() ) , this, SLOT( OpacityActionChanged() ) ); unknownDataNodeDescriptor->AddAction(opacityAction , false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,opacityAction)); m_ColorButton = new QPushButton; m_ColorButton->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum); //m_ColorButton->setText("Change color"); QObject::connect( m_ColorButton, SIGNAL( clicked() ) , this, SLOT( ColorChanged() ) ); QLabel* _ColorLabel = new QLabel("Color: "); _ColorLabel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum); QHBoxLayout* _ColorWidgetLayout = new QHBoxLayout; _ColorWidgetLayout->setContentsMargins(4,4,4,4); _ColorWidgetLayout->addWidget(_ColorLabel); _ColorWidgetLayout->addWidget(m_ColorButton); QWidget* _ColorWidget = new QWidget; _ColorWidget->setLayout(_ColorWidgetLayout); QWidgetAction* colorAction = new QWidgetAction(this); colorAction->setDefaultWidget(_ColorWidget); QObject::connect( colorAction, SIGNAL( changed() ) , this, SLOT( ColorActionChanged() ) ); unknownDataNodeDescriptor->AddAction(colorAction, false); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,colorAction)); m_TextureInterpolation = new QAction("Texture Interpolation", this); m_TextureInterpolation->setCheckable ( true ); QObject::connect( m_TextureInterpolation, SIGNAL( changed() ) , this, SLOT( TextureInterpolationChanged() ) ); QObject::connect( m_TextureInterpolation, SIGNAL( toggled(bool) ) , this, SLOT( TextureInterpolationToggled(bool) ) ); imageDataNodeDescriptor->AddAction(m_TextureInterpolation, false); m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,m_TextureInterpolation)); m_SurfaceRepresentation = new QAction("Surface Representation", this); m_SurfaceRepresentation->setMenu(new QMenu); QObject::connect( m_SurfaceRepresentation->menu(), SIGNAL( aboutToShow() ) , this, SLOT( SurfaceRepresentationMenuAboutToShow() ) ); surfaceDataNodeDescriptor->AddAction(m_SurfaceRepresentation, false); m_DescriptorActionList.push_back(std::pair(surfaceDataNodeDescriptor, m_SurfaceRepresentation)); QAction* showOnlySelectedNodes = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowSelectedNode_48.png") , "Show only selected nodes", this); QObject::connect( showOnlySelectedNodes, SIGNAL( triggered(bool) ) , this, SLOT( ShowOnlySelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(showOnlySelectedNodes); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor, showOnlySelectedNodes)); QAction* toggleSelectedVisibility = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/InvertShowSelectedNode_48.png") , "Toggle visibility", this); QObject::connect( toggleSelectedVisibility, SIGNAL( triggered(bool) ) , this, SLOT( ToggleVisibilityOfSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(toggleSelectedVisibility); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,toggleSelectedVisibility)); QAction* actionShowInfoDialog = new QAction(QIcon(":/org.mitk.gui.qt.datamanager/ShowDataInfo_48.png") , "Details...", this); QObject::connect( actionShowInfoDialog, SIGNAL( triggered(bool) ) , this, SLOT( ShowInfoDialogForSelectedNodes(bool) ) ); unknownDataNodeDescriptor->AddAction(actionShowInfoDialog); m_DescriptorActionList.push_back(std::pair(unknownDataNodeDescriptor,actionShowInfoDialog)); //obsolete... //QAction* otsuFilterAction = new QAction("Apply Otsu Filter", this); //QObject::connect( otsuFilterAction, SIGNAL( triggered(bool) ) // , this, SLOT( OtsuFilter(bool) ) ); // //Otsu filter does not work properly, remove it temporarily // imageDataNodeDescriptor->AddAction(otsuFilterAction); // m_DescriptorActionList.push_back(std::pair(imageDataNodeDescriptor,otsuFilterAction)); QGridLayout* _DndFrameWidgetLayout = new QGridLayout; _DndFrameWidgetLayout->addWidget(m_NodeTreeView, 0, 0); _DndFrameWidgetLayout->setContentsMargins(0,0,0,0); m_DndFrameWidget = new QmitkDnDFrameWidget(m_Parent); m_DndFrameWidget->setLayout(_DndFrameWidgetLayout); QVBoxLayout* layout = new QVBoxLayout(parent); layout->addWidget(m_DndFrameWidget); layout->setContentsMargins(0,0,0,0); m_Parent->setLayout(layout); } void QmitkDataManagerView::SetFocus() { } void QmitkDataManagerView::ContextMenuActionTriggered( bool ) { QAction* action = qobject_cast ( sender() ); std::map::iterator it = m_ConfElements.find( action ); if( it == m_ConfElements.end() ) { MITK_WARN << "associated conf element for action " << action->text().toStdString() << " not found"; return; } berry::IConfigurationElement::Pointer confElem = it->second; mitk::IContextMenuAction* contextMenuAction = confElem->CreateExecutableExtension("class"); std::string className; std::string smoothed; confElem->GetAttribute("class", className); confElem->GetAttribute("smoothed", smoothed); if(className == "QmitkThresholdAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); } else if(className == "QmitkOtsuAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); } else if(className == "QmitkCreatePolygonModelAction") { contextMenuAction->SetDataStorage(this->GetDataStorage()); if(smoothed == "false") { contextMenuAction->SetSmoothed(false); } else { contextMenuAction->SetSmoothed(true); } contextMenuAction->SetDecimated(m_SurfaceDecimation); } else if(className == "QmitkStatisticsAction") { contextMenuAction->SetFunctionality(this); } + else if(className == "QmitkCreateSimulationAction") + { + contextMenuAction->SetDataStorage(this->GetDataStorage()); + } contextMenuAction->Run( this->GetCurrentSelection() ); // run the action } void QmitkDataManagerView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if( m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() != prefs->GetBool("Place new nodes on top", true) ) m_NodeTreeModel->SetPlaceNewNodesOnTop( !m_NodeTreeModel->GetPlaceNewNodesOnTopFlag() ); if( m_NodeTreeModel->GetShowHelperObjectsFlag()!= prefs->GetBool("Show helper objects", false) ) m_NodeTreeModel->SetShowHelperObjects( !m_NodeTreeModel->GetShowHelperObjectsFlag() ); if( m_NodeTreeModel->GetShowNodesContainingNoDataFlag()!= prefs->GetBool("Show nodes containing no data", false) ) m_NodeTreeModel->SetShowNodesContainingNoData( !m_NodeTreeModel->GetShowNodesContainingNoDataFlag() ); + m_GlobalReinitOnNodeDelete = prefs->GetBool("Call global reinit if node is deleted", true); + m_NodeTreeView->expandAll(); m_SurfaceDecimation = prefs->GetBool("Use surface decimation", false); this->GlobalReinit(); } void QmitkDataManagerView::NodeTableViewContextMenuRequested( const QPoint & pos ) { QModelIndex selected = m_NodeTreeView->indexAt ( pos ); mitk::DataNode::Pointer node = m_NodeTreeModel->GetNode(selected); QList selectedNodes = this->GetCurrentSelection(); if(!selectedNodes.isEmpty()) { m_NodeMenu->clear(); QList actions; if(selectedNodes.size() == 1 ) { actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(node); for(QList::iterator it = actions.begin(); it != actions.end(); ++it) { (*it)->setData(QVariant::fromValue(node.GetPointer())); } } else actions = QmitkNodeDescriptorManager::GetInstance()->GetActions(selectedNodes); if (!m_ShowInActions.isEmpty()) { QMenu* showInMenu = m_NodeMenu->addMenu("Show In"); showInMenu->addActions(m_ShowInActions); } m_NodeMenu->addActions(actions); m_NodeMenu->popup(QCursor::pos()); } } void QmitkDataManagerView::OpacityChanged(int value) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { float opacity = static_cast(value)/100.0f; node->SetFloatProperty("opacity", opacity); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::OpacityActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { float opacity = 0.0; if(node->GetFloatProperty("opacity", opacity)) { m_OpacitySlider->setValue(static_cast(opacity*100)); } } } void QmitkDataManagerView::ColorChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { QColor color = QColorDialog::getColor(); m_ColorButton->setAutoFillBackground(true); node->SetProperty("color",mitk::ColorProperty::New(color.red()/255.0,color.green()/255.0,color.blue()/255.0)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::ColorActionChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { mitk::Color color; mitk::ColorProperty::Pointer colorProp; node->GetProperty(colorProp,"color"); if(colorProp.IsNull()) return; color = colorProp->GetValue(); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(color[0]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[1]*255)); styleSheet.append(","); styleSheet.append(QString::number(color[2]*255)); styleSheet.append(")"); m_ColorButton->setStyleSheet(styleSheet); } } void QmitkDataManagerView::TextureInterpolationChanged() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { bool textureInterpolation = false; node->GetBoolProperty("texture interpolation", textureInterpolation); m_TextureInterpolation->setChecked(textureInterpolation); } } void QmitkDataManagerView::TextureInterpolationToggled( bool checked ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(node) { node->SetBoolProperty("texture interpolation", checked); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkDataManagerView::SurfaceRepresentationMenuAboutToShow() { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; // clear menu m_SurfaceRepresentation->menu()->clear(); QAction* tmp; // create menu entries for(mitk::EnumerationProperty::EnumConstIterator it=representationProp->Begin(); it!=representationProp->End() ; it++) { tmp = m_SurfaceRepresentation->menu()->addAction(QString::fromStdString(it->second)); tmp->setCheckable(true); if(it->second == representationProp->GetValueAsString()) { tmp->setChecked(true); } QObject::connect( tmp, SIGNAL( triggered(bool) ) , this, SLOT( SurfaceRepresentationActionToggled(bool) ) ); } } void QmitkDataManagerView::SurfaceRepresentationActionToggled( bool /*checked*/ ) { mitk::DataNode* node = m_NodeTreeModel->GetNode(m_NodeTreeView->selectionModel()->currentIndex()); if(!node) return; mitk::EnumerationProperty* representationProp = dynamic_cast (node->GetProperty("material.representation")); if(!representationProp) return; QAction* senderAction = qobject_cast ( QObject::sender() ); if(!senderAction) return; std::string activatedItem = senderAction->text().toStdString(); if ( activatedItem != representationProp->GetValueAsString() ) { if ( representationProp->IsValidEnumerationValue( activatedItem ) ) { representationProp->SetValue( activatedItem ); representationProp->InvokeEvent( itk::ModifiedEvent() ); representationProp->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkDataManagerView::SaveSelectedNodes( bool ) { QModelIndexList indexesOfSelectedRows = m_NodeTreeView->selectionModel()->selectedRows(); mitk::DataNode* node = 0; unsigned int indexesOfSelectedRowsSize = indexesOfSelectedRows.size(); for (unsigned int i = 0; iGetNode(indexesOfSelectedRows.at(i)); // if node is not defined or if the node contains geometry data do not remove it if ( node != 0 ) { mitk::BaseData::Pointer data = node->GetData(); if (data.IsNotNull()) { QString error; try { mitk::QmitkIOUtil::SaveBaseDataWithDialog( data.GetPointer(), node->GetName().c_str(), m_Parent ); } catch(std::exception& e) { error = e.what(); } catch(...) { error = "Unknown error occured"; } if( !error.isEmpty() ) QMessageBox::critical( m_Parent, "Error saving...", error ); } } } } void QmitkDataManagerView::ReinitSelectedNodes( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); QList selectedNodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, selectedNodes) { mitk::BaseData::Pointer basedata = node->GetData(); if ( basedata.IsNotNull() && basedata->GetTimeSlicedGeometry()->IsValid() ) { renderWindow->GetRenderingManager()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); renderWindow->GetRenderingManager()->RequestUpdateAll(); } } } void QmitkDataManagerView::RemoveSelectedNodes( bool ) { QModelIndexList indexesOfSelectedRows = m_NodeTreeView->selectionModel()->selectedRows(); if(indexesOfSelectedRows.size() < 1) { return; } std::vector selectedNodes; mitk::DataNode* node = 0; QString question = tr("Do you really want to remove "); for (QModelIndexList::iterator it = indexesOfSelectedRows.begin() ; it != indexesOfSelectedRows.end(); it++) { node = m_NodeTreeModel->GetNode(*it); // if node is not defined or if the node contains geometry data do not remove it if ( node != 0 /*& strcmp(node->GetData()->GetNameOfClass(), "Geometry2DData") != 0*/ ) { selectedNodes.push_back(node); question.append(QString::fromStdString(node->GetName())); question.append(", "); } } // remove the last two characters = ", " question = question.remove(question.size()-2, 2); question.append(" from data storage?"); QMessageBox::StandardButton answerButton = QMessageBox::question( m_Parent , tr("DataManager") , question , QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if(answerButton == QMessageBox::Yes) { for (std::vector::iterator it = selectedNodes.begin() ; it != selectedNodes.end(); it++) { node = *it; this->GetDataStorage()->Remove(node); - this->GlobalReinit(false); + if (m_GlobalReinitOnNodeDelete) + this->GlobalReinit(false); } } } void QmitkDataManagerView::MakeAllNodesInvisible( bool ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { node->SetVisibility(false); } - //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowOnlySelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QList allNodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, allNodes) { node->SetVisibility(selectedNodes.contains(node)); } - //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ToggleVisibilityOfSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); bool isVisible = false; foreach(mitk::DataNode::Pointer node, selectedNodes) { isVisible = false; node->GetBoolProperty("visible", isVisible); node->SetVisibility(!isVisible); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowInfoDialogForSelectedNodes( bool ) { QList selectedNodes = this->GetCurrentSelection(); QmitkInfoDialog _QmitkInfoDialog(selectedNodes, this->m_Parent); _QmitkInfoDialog.exec(); } void QmitkDataManagerView::Load( bool ) { QStringList fileNames = QFileDialog::getOpenFileNames(NULL, "Load data", "", mitk::CoreObjectFactory::GetInstance()->GetFileExtensions()); for ( QStringList::Iterator it = fileNames.begin(); it != fileNames.end(); ++it ) { FileOpen((*it).toAscii(), 0); } } void QmitkDataManagerView::FileOpen( const char * fileName, mitk::DataNode* parentNode ) { mitk::DataNodeFactory::Pointer factory = mitk::DataNodeFactory::New(); try { factory->SetFileName( fileName ); QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); factory->Update(); for ( unsigned int i = 0 ; i < factory->GetNumberOfOutputs( ); ++i ) { mitk::DataNode::Pointer node = factory->GetOutput( i ); if ( ( node.IsNotNull() ) && ( node->GetData() != NULL ) ) { this->GetDataStorage()->Add(node, parentNode); mitk::BaseData::Pointer basedata = node->GetData(); mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } catch ( itk::ExceptionObject & ex ) { itkGenericOutputMacro( << "Exception during file open: " << ex ); } QApplication::restoreOverrideCursor(); } QItemSelectionModel *QmitkDataManagerView::GetDataNodeSelectionModel() const { return m_NodeTreeView->selectionModel(); } void QmitkDataManagerView::GlobalReinit( bool ) { mitk::IRenderWindowPart* renderWindow = this->GetRenderWindowPart(); if (renderWindow == NULL) renderWindow = this->OpenRenderWindowPart(false); // no render window available if (renderWindow == NULL) return; // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox" , mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry renderWindow->GetRenderingManager()->InitializeViews(bounds); } void QmitkDataManagerView::OtsuFilter( bool ) { QList selectedNodes = this->GetCurrentSelection(); mitk::Image::Pointer mitkImage = 0; foreach(mitk::DataNode::Pointer node, selectedNodes) { mitkImage = dynamic_cast( node->GetData() ); if(mitkImage.IsNull()) continue; try { // get selected mitk image const unsigned short dim = 3; typedef short InputPixelType; typedef unsigned char OutputPixelType; typedef itk::Image< InputPixelType, dim > InputImageType; typedef itk::Image< OutputPixelType, dim > OutputImageType; typedef itk::OtsuThresholdImageFilter< InputImageType, OutputImageType > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetOutsideValue( 1 ); filter->SetInsideValue( 0 ); InputImageType::Pointer itkImage; mitk::CastToItkImage(mitkImage, itkImage); filter->SetInput( itkImage ); filter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = node->GetName(); nameOfResultImage.append("Otsu"); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); resultNode->SetData( mitk::ImportItkImage ( filter->GetOutput() ) ); this->GetDataStorage()->Add(resultNode, node); } catch( std::exception& err ) { MITK_ERROR(this->GetClassName()) << err.what(); } } } void QmitkDataManagerView::NodeTreeViewRowsRemoved ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { m_CurrentRowCount = m_NodeTreeModel->rowCount(); } void QmitkDataManagerView::NodeTreeViewRowsInserted( const QModelIndex & parent, int, int ) { m_NodeTreeView->setExpanded(parent, true); // a new row was inserted if( m_CurrentRowCount == 0 && m_NodeTreeModel->rowCount() == 1 ) { this->OpenRenderWindowPart(); m_CurrentRowCount = m_NodeTreeModel->rowCount(); /* std::vector nodes = m_NodeTreeModel->GetNodeSet(); if(nodes.size() == 1) { QModelIndex treeIndex = m_NodeTreeModel->GetIndex(nodes.front()); m_NodeTreeView->selectionModel()->setCurrentIndex( treeIndex, QItemSelectionModel::ClearAndSelect ); } */ } } void QmitkDataManagerView::NodeSelectionChanged( const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/ ) { QList nodes = m_NodeTreeModel->GetNodeSet(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", false); } nodes.clear(); nodes = this->GetCurrentSelection(); foreach(mitk::DataNode::Pointer node, nodes) { if ( node.IsNotNull() ) node->SetBoolProperty("selected", true); } //changing the selection does NOT require any rendering processes! //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataManagerView::ShowIn(const QString &editorId) { berry::IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); berry::IEditorInput::Pointer input(new mitk::DataStorageEditorInput(this->GetDataStorageReference())); page->OpenEditor(input, editorId.toStdString(), false, berry::IWorkbenchPage::MATCH_ID); } mitk::IRenderWindowPart* QmitkDataManagerView::OpenRenderWindowPart(bool activatedEditor) { if (activatedEditor) { return this->GetRenderWindowPart(QmitkAbstractView::ACTIVATE | QmitkAbstractView::OPEN); } else { return this->GetRenderWindowPart(QmitkAbstractView::BRING_TO_FRONT | QmitkAbstractView::OPEN); } } diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h index df68129a89..bb4b25ed30 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h +++ b/Plugins/org.mitk.gui.qt.datamanager/src/QmitkDataManagerView.h @@ -1,246 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKDATAMANAGERVIEW_H_ #define QMITKDATAMANAGERVIEW_H_ // BlueBerry includes #include /// Qmitk #include #include /// Qt #include #include // Forward declarations class QMenu; class QAction; class QComboBox; class QWidgetAction; class QSlider; class QModelIndex; class QTreeView; class QPushButton; class QToolBar; class QMenu; class QSignalMapper; class QmitkDnDFrameWidget; class QmitkDataStorageTreeModel; /// /// \ingroup org_mitk_gui_qt_datamanager_internal /// /// \brief A View class that can show all data tree nodes of a certain DataStorage /// /// \TODO: complete PACS support, in save dialog show regular filename /// class MITK_QT_DATAMANAGER QmitkDataManagerView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; // = "org.mitk.extapp.defaultperspective" /// /// \brief Standard ctor. /// QmitkDataManagerView(); /// /// \brief Standard dtor. /// virtual ~QmitkDataManagerView(); public slots: /// /// Invoked when the opacity slider changed /// void OpacityChanged(int value); /// /// Invoked when the opacity action changed /// In this function the the opacity slider is set to the selected nodes opacity value /// void OpacityActionChanged(); /// /// Invoked when the color button is pressed /// void ColorChanged(); /// /// Invoked when the color action changed /// void ColorActionChanged(); /// /// Invoked when the color button is pressed /// void TextureInterpolationChanged(); /// /// Invoked when the color action changed /// void TextureInterpolationToggled ( bool checked ); /// /// SurfaceRepresentationActionToggled /// void SurfaceRepresentationMenuAboutToShow (); ///public /// SurfaceRepresentationActionToggled /// void SurfaceRepresentationActionToggled ( bool checked ); /// /// \brief Shows a node context menu. /// void NodeTableViewContextMenuRequested( const QPoint & index ); /// /// \brief Invoked when an element should be saved. /// void SaveSelectedNodes( bool checked = false ); /// /// \brief Invoked when an element should be removed. /// void RemoveSelectedNodes( bool checked = false ); /// /// \brief Invoked when an element should be reinitiliased. /// void ReinitSelectedNodes( bool checked = false ); /// /// \brief Invoked when the visibility of the selected nodes should be toggled. /// void MakeAllNodesInvisible ( bool checked = false ); /// /// \brief Makes all selected nodes visible, all other nodes invisible. /// void ShowOnlySelectedNodes ( bool checked = false ); /// /// \brief Invoked when the visibility of the selected nodes should be toggled. /// void ToggleVisibilityOfSelectedNodes ( bool checked = false ); /// /// \brief Invoked when infos of the selected nodes should be shown in a dialog. /// void ShowInfoDialogForSelectedNodes ( bool checked = false ); /// /// \brief Shows a load dialog. /// void Load ( bool checked = false ); /// /// \brief Reinits everything. /// void GlobalReinit ( bool checked = false ); /// /// Invoked when the preferences were changed /// void OnPreferencesChanged(const berry::IBerryPreferences*); /// /// \brief will be toggled when a extension point context menu action is toggled /// this is a proxy method which will load the corresponding extension class /// and run IContextMenuAction /// void ContextMenuActionTriggered( bool ); /// Invoked when the median action is invoked void OtsuFilter( bool checked = false ); /// When rows are inserted auto expand them void NodeTreeViewRowsInserted ( const QModelIndex & parent, int start, int end ); /// will setup m_CurrentRowCount void NodeTreeViewRowsRemoved ( const QModelIndex & parent, int start, int end ); /// Whenever the selection changes set the "selected" property respectively void NodeSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); /// Opens the editor with the given id using the current data storage void ShowIn(const QString& editorId); protected: /// /// \brief Create the view here. /// virtual void CreateQtPartControl(QWidget* parent); void SetFocus(); /// /// \brief Shows a file open dialog. /// void FileOpen( const char * fileName, mitk::DataNode* parentNode ); protected: QWidget* m_Parent; QmitkDnDFrameWidget* m_DndFrameWidget; /// /// \brief A plain widget as the base pane. /// QmitkDataStorageTreeModel* m_NodeTreeModel; /// /// Holds the preferences for the datamanager. /// berry::IBerryPreferences::Pointer m_DataManagerPreferencesNode; /// /// saves the configuration elements for the context menu actions from extension points /// std::map m_ConfElements; /// /// \brief The Table view to show the selected nodes. /// QTreeView* m_NodeTreeView; /// /// \brief The context menu that shows up when right clicking on a node. /// QMenu* m_NodeMenu; /// /// \brief flag indicating whether a surface created from a selected decimation is decimated with vtkQuadricDecimation or not /// bool m_SurfaceDecimation; ///# A list of ALL actions for the Context Menu std::vector< std::pair< QmitkNodeDescriptor*, QAction* > > m_DescriptorActionList; /// A Slider widget to change the opacity of a node QSlider* m_OpacitySlider; /// button to change the color of a node QPushButton* m_ColorButton; /// TextureInterpolation action QAction* m_TextureInterpolation; /// SurfaceRepresentation action QAction* m_SurfaceRepresentation; /// Maps "Show in" actions to editor ids QSignalMapper* m_ShowInMapper; /// A list of "Show in" actions QList m_ShowInActions; /// saves the current amount of rows shown in the datamanager size_t m_CurrentRowCount; + /// if true, GlobalReinit() is called if a node is deleted + bool m_GlobalReinitOnNodeDelete; + private: QItemSelectionModel* GetDataNodeSelectionModel() const; /// Reopen multi widget editor if it has been closed mitk::IRenderWindowPart *OpenRenderWindowPart(bool activatedEditor = true); }; #endif /*QMITKDATAMANAGERVIEW_H_*/ diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.cpp deleted file mode 100644 index 5ba5087943..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkLineEdit.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/*=================================================================== - -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 "QmitkLineEdit.h" -#include - -QmitkLineEdit::QmitkLineEdit(QWidget *parent) - : QLineEdit(parent) -{ - initialize(); -} - -QmitkLineEdit::QmitkLineEdit(const QString &defaultText, QWidget *parent) - : QLineEdit(parent), - m_DefaultText(defaultText) -{ - initialize(); -} - -QmitkLineEdit::~QmitkLineEdit() -{ -} - -void QmitkLineEdit::initialize() -{ - m_DefaultPalette.setColor(QPalette::Text, QApplication::palette().color(QPalette::Disabled, QPalette::Text)); - - showDefaultText(true); - - connect(this, SIGNAL(focusChanged(bool)), this, SLOT(onFocusChanged(bool))); - connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString))); -} - -QString QmitkLineEdit::defaultText() const -{ - return m_DefaultText; -} - -void QmitkLineEdit::setDefaultText(const QString &defaultText) -{ - m_DefaultText = defaultText; -} - -void QmitkLineEdit::focusInEvent(QFocusEvent *event) -{ - QLineEdit::focusInEvent(event); - emit(focusChanged(true)); -} - -void QmitkLineEdit::focusOutEvent(QFocusEvent *event) -{ - QLineEdit::focusOutEvent(event); - emit(focusChanged(false)); -} - -void QmitkLineEdit::onFocusChanged(bool hasFocus) -{ - if (hasFocus) - { - if (text() == m_DefaultText && palette() == m_DefaultPalette) - showDefaultText(false); - } - else - { - if (text().isEmpty()) - showDefaultText(true); - } -} - -void QmitkLineEdit::onTextChanged(const QString &text) -{ - if (palette() == m_DefaultPalette) - setPalette(m_Palette); -} - -void QmitkLineEdit::showDefaultText(bool show) -{ - blockSignals(true); - - if (show) - { - setPalette(m_DefaultPalette); - setText(m_DefaultText); - } - else - { - setPalette(m_Palette); - clear(); - } - - blockSignals(false); -} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.cpp deleted file mode 100644 index d3b5871978..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/*=================================================================== - -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 "QmitkPropertyTreeFilterProxyModel.h" -#include - -QmitkPropertyTreeFilterProxyModel::QmitkPropertyTreeFilterProxyModel(QObject *parent) -: QSortFilterProxyModel(parent) -{ -} - -QmitkPropertyTreeFilterProxyModel::~QmitkPropertyTreeFilterProxyModel() -{ -} - -bool QmitkPropertyTreeFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const -{ - return filterAcceptsAnyChildRows(sourceModel()->index(sourceRow, 0, sourceParent)); -} - -bool QmitkPropertyTreeFilterProxyModel::filterAcceptsAnyChildRows(const QModelIndex &sourceParent) const -{ - QString propertyName = sourceModel()->data(sourceParent).toString(); - - if (propertyName.contains(filterRegExp())) - return true; - - if (sourceModel()->hasChildren(sourceParent)) - { - for (int row = 0; row < sourceModel()->rowCount(sourceParent); ++row) - { - if (filterAcceptsAnyChildRows(sourceModel()->index(row, 0, sourceParent))) - return true; - } - } - - return false; -} - -bool QmitkPropertyTreeFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - return sourceModel()->data(left).toString().compare(sourceModel()->data(right).toString(), Qt::CaseInsensitive) > 0; -} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.cpp deleted file mode 100644 index 588a741ddc..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/*=================================================================== - -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 "QmitkPropertyTreeItem.h" -#include - -QmitkPropertyTreeItem::QmitkPropertyTreeItem(const QList &data) -: m_Data(data), - m_Parent(NULL) -{ -} - -QmitkPropertyTreeItem::~QmitkPropertyTreeItem() -{ - qDeleteAll(m_Children); -} - -void QmitkPropertyTreeItem::AppendChild(QmitkPropertyTreeItem *child) -{ - if (child == NULL) - return; - - // If property name contains no full stop we can append the property directly. - if (!child->GetData(0).toString().contains('.')) - { - m_Children.append(child); - child->m_Parent = this; - } - else - { - // Property name contains full stop(s). We split the name appropriately. - QStringList names = child->GetData(0).toString().split('.'); - - // Traverse the subtree and insert items if they are not already present. - QmitkPropertyTreeItem *parent_ = this; - - for (int i = 0; i < names.count(); ++i) - { - // Subtree present/recently created, append actual property as a leaf item - if (i == names.count() - 1) - { - QList data; - data << names[i] << child->m_Data[1]; - parent_->AppendChild(new QmitkPropertyTreeItem(data)); - - delete child; - child = NULL; - } - else - { - QmitkPropertyTreeItem *child_ = NULL; - - for (int j = 0; j < parent_->m_Children.count(); ++j) - { - if (parent_->m_Children[j]->GetData(0).toString() == names[i]) - { - child_ = parent_->m_Children[j]; - break; - } - } - - if (child_ == NULL) - { - QList data; - data << names[i] << QVariant(); - child_ = new QmitkPropertyTreeItem(data); - parent_->AppendChild(child_); - } - - parent_ = child_; - } - } - } -} - -QmitkPropertyTreeItem * QmitkPropertyTreeItem::GetChild(int row) -{ - return m_Children.value(row); -} - -int QmitkPropertyTreeItem::GetChildCount() const -{ - return m_Children.count(); -} - -int QmitkPropertyTreeItem::GetColumnCount() const -{ - return m_Data.count(); -} - -QVariant QmitkPropertyTreeItem::GetData(int column) const -{ - return m_Data.value(column); -} - -QmitkPropertyTreeItem * QmitkPropertyTreeItem::GetParent() -{ - return m_Parent; -} - -int QmitkPropertyTreeItem::GetRow() const -{ - if (m_Parent != NULL) - return m_Parent->m_Children.indexOf(const_cast(this)); - - return 0; -} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp deleted file mode 100644 index 079220af99..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/*=================================================================== - -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 "QmitkPropertyTreeItem.h" -#include "QmitkPropertyTreeModel.h" -#include -#include -#include -#include -#include -#include - -QmitkPropertyTreeModel::QmitkPropertyTreeModel(QObject *parent) -: QAbstractItemModel(parent), - m_Properties(NULL), - m_RootItem(NULL) -{ - CreateRootItem(); -} - -void QmitkPropertyTreeModel::SetProperties(mitk::PropertyList *properties) -{ - if (properties == m_Properties) - return; - - beginResetModel(); - - if (m_RootItem != NULL) - { - delete m_RootItem; - m_RootItem = NULL; - m_Properties = NULL; - } - - CreateRootItem(); - - if (properties != NULL && !properties->IsEmpty()) - { - m_Properties = properties; - - std::map::const_iterator end = properties->GetMap()->end(); - - for (std::map::const_iterator iter = properties->GetMap()->begin(); iter != end; ++iter) - { - QList data; - data << iter->first.c_str() << QVariant::fromValue((reinterpret_cast(iter->second.GetPointer()))); - m_RootItem->AppendChild(new QmitkPropertyTreeItem(data)); - } - } - - endResetModel(); -} - -void QmitkPropertyTreeModel::CreateRootItem() -{ - if (m_RootItem == NULL) - { - QList rootData; - rootData << "Property" << "Value"; - m_RootItem = new QmitkPropertyTreeItem(rootData); - } -} - -QmitkPropertyTreeModel::~QmitkPropertyTreeModel() -{ - delete m_RootItem; -} - -int QmitkPropertyTreeModel::columnCount(const QModelIndex &parent) const -{ - if (parent.isValid()) - return static_cast(parent.internalPointer())->GetColumnCount(); - else - return m_RootItem->GetColumnCount(); -} - -QVariant QmitkPropertyTreeModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.column() == 0 && role == Qt::DisplayRole) - return static_cast(index.internalPointer())->GetData(index.column()); - - if (index.column() == 1 && static_cast(index.internalPointer())->GetData(index.column()).isValid()) - { - mitk::BaseProperty *property = reinterpret_cast(static_cast(index.internalPointer())->GetData(index.column()).value()); - - if (mitk::ColorProperty *colorProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole || role == Qt::EditRole) - { - mitk::Color mitkColor = colorProperty->GetColor(); - QColor qtColor(static_cast(mitkColor.GetRed() * 255), static_cast(mitkColor.GetGreen() * 255), static_cast(mitkColor.GetBlue() * 255)); - return QVariant::fromValue(qtColor); - } - } - else if (mitk::BoolProperty *boolProperty = dynamic_cast(property)) - { - if (role == Qt::CheckStateRole) - return boolProperty->GetValue() ? Qt::Checked : Qt::Unchecked; - } - else if (mitk::StringProperty *stringProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole || role == Qt::EditRole) - return QString(stringProperty->GetValue()); - } - else if (mitk::IntProperty *intProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole || role == Qt::EditRole) - return intProperty->GetValue(); - } - else if (mitk::FloatProperty *floatProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole || role == Qt::EditRole) - return floatProperty->GetValue(); - } - else if (mitk::DoubleProperty *doubleProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole || role == Qt::EditRole) - return doubleProperty->GetValue(); - } - else if (mitk::EnumerationProperty *enumProperty = dynamic_cast(property)) - { - if (role == Qt::DisplayRole) - { - return QString::fromStdString(enumProperty->GetValueAsString()); - } - else if (role == Qt::EditRole) - { - QStringList values; - - for (mitk::EnumerationProperty::EnumConstIterator iter = enumProperty->Begin(); iter != enumProperty->End(); ++iter) - values << QString::fromStdString(iter->second); - - return QVariant(values); - } - } - else - { - if (role == Qt::DisplayRole) - return QString::fromStdString(property->GetValueAsString()); - } - } - - return QVariant(); -} - -Qt::ItemFlags QmitkPropertyTreeModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = QAbstractItemModel::flags(index); - - if (index.column() == 1) - { - if (index.data(Qt::EditRole).isValid()) - flags |= Qt::ItemIsEditable; - - if (index.data(Qt::CheckStateRole).isValid()) - flags |= Qt::ItemIsUserCheckable; - } - - return flags; -} - -QVariant QmitkPropertyTreeModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return m_RootItem->GetData(section); - - return QVariant(); -} - -QModelIndex QmitkPropertyTreeModel::index(int row, int column, const QModelIndex &parent) const -{ - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - QmitkPropertyTreeItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem; - QmitkPropertyTreeItem *childItem = parentItem->GetChild(row); - - if (childItem != NULL) - return createIndex(row, column, childItem); - else - return QModelIndex(); -} - -QModelIndex QmitkPropertyTreeModel::parent(const QModelIndex &child) const -{ - if (!child.isValid()) - return QModelIndex(); - - QmitkPropertyTreeItem *parentItem = static_cast(child.internalPointer())->GetParent(); - - if (parentItem == m_RootItem) - return QModelIndex(); - - return createIndex(parentItem->GetRow(), 0, parentItem); -} - -int QmitkPropertyTreeModel::rowCount(const QModelIndex &parent) const -{ - if (parent.column() > 0) - return 0; - - QmitkPropertyTreeItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : m_RootItem; - - return parentItem->GetChildCount(); -} - -bool QmitkPropertyTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - if (index.isValid() && (role == Qt::EditRole || role == Qt::CheckStateRole)) - { - if (index.column() == 1) - { - mitk::BaseProperty *property = reinterpret_cast(static_cast(index.internalPointer())->GetData(index.column()).value()); - - if (mitk::ColorProperty *colorProperty = dynamic_cast(property)) - { - QColor qtColor = value.value(); - - if (!qtColor.isValid()) - return false; - - mitk::Color mitkColor = colorProperty->GetColor(); - mitkColor.SetRed(qtColor.red() / 255.0); - mitkColor.SetGreen(qtColor.green() / 255.0); - mitkColor.SetBlue(qtColor.blue() / 255.0); - colorProperty->SetColor(mitkColor); - - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - else if (mitk::BoolProperty *boolProperty = dynamic_cast(property)) - { - boolProperty->SetValue(value.toInt() == Qt::Checked ? true : false); - - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - else if (mitk::StringProperty *stringProperty = dynamic_cast(property)) - { - stringProperty->SetValue(value.toString().toStdString()); - - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - else if (mitk::IntProperty *intProperty = dynamic_cast(property)) - { - int intValue = value.toInt(); - - if (intValue != intProperty->GetValue()) - { - intProperty->SetValue(intValue); - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - else if (mitk::FloatProperty *floatProperty = dynamic_cast(property)) - { - float floatValue = value.toFloat(); - - if (abs(floatValue - floatProperty->GetValue()) >= mitk::eps) - { - floatProperty->SetValue(floatValue); - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - else if (mitk::EnumerationProperty *enumProperty = dynamic_cast(property)) - { - std::string activatedItem = value.toString().toStdString(); - - if (activatedItem != enumProperty->GetValueAsString()) - { - enumProperty->SetValue(activatedItem); - m_Properties->InvokeEvent(itk::ModifiedEvent()); - m_Properties->Modified(); - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - } - - emit dataChanged(index, index); - return true; - } - - return false; -} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.h b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.h deleted file mode 100644 index caf5c9a2a4..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeModel.h +++ /dev/null @@ -1,51 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef QMITKPROPERTYTREEMODEL_H -#define QMITKPROPERTYTREEMODEL_H - -#include -#include - -class QmitkPropertyTreeItem; - -class QmitkPropertyTreeModel : public QAbstractItemModel -{ - Q_OBJECT - -public: - QmitkPropertyTreeModel(QObject *parent = NULL); - ~QmitkPropertyTreeModel(); - - void SetProperties(mitk::PropertyList *properties); - - int columnCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; - Qt::ItemFlags flags(const QModelIndex &index) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QModelIndex index(int row, int column, const QModelIndex &parent) const; - QModelIndex parent(const QModelIndex &child) const; - int rowCount(const QModelIndex &parent) const; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); - -private: - void CreateRootItem(); - - mitk::PropertyList *m_Properties; - QmitkPropertyTreeItem *m_RootItem; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.cpp b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.cpp deleted file mode 100644 index a4adf64d62..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/*=================================================================== - -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 "QmitkPropertyTreeView.h" -#include "QmitkPropertyTreeModel.h" -#include "QmitkLineEdit.h" -#include "QmitkPropertyTreeFilterProxyModel.h" -#include -#include -#include -#include - -const std::string QmitkPropertyTreeView::VIEW_ID = "org.mitk.views.propertytreeview"; - -QmitkPropertyTreeView::QmitkPropertyTreeView() - : m_Filter(NULL), - m_Model(NULL), - m_ProxyModel(NULL), - m_Delegate(NULL), - m_TreeView(NULL) -{ -} - -QmitkPropertyTreeView::~QmitkPropertyTreeView() -{ - if (m_Delegate != NULL) - delete m_Delegate; - - if (m_ProxyModel != NULL) - delete m_ProxyModel; - - if (m_Model != NULL) - delete m_Model; -} - -void QmitkPropertyTreeView::CreateQtPartControl(QWidget *parent) -{ - m_Filter = new QmitkLineEdit("Filter", parent); - - m_Model = new QmitkPropertyTreeModel; - - m_ProxyModel = new QmitkPropertyTreeFilterProxyModel; - m_ProxyModel->setSourceModel(m_Model); - m_ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); - m_ProxyModel->setDynamicSortFilter(true); - - m_Delegate = new QmitkPropertyDelegate; - - connect(m_Filter, SIGNAL(textChanged(const QString &)), this, SLOT(OnFilterChanged(const QString &))); - - m_TreeView = new QTreeView(parent); - - m_TreeView->setModel(m_ProxyModel); - m_TreeView->setItemDelegateForColumn(1, m_Delegate); - m_TreeView->setSortingEnabled(true); - m_TreeView->setIndentation(16); - m_TreeView->setAlternatingRowColors(true); - m_TreeView->setSelectionMode(QAbstractItemView::SingleSelection); - m_TreeView->setSelectionBehavior(QAbstractItemView::SelectItems); - - QVBoxLayout *layout = new QVBoxLayout(parent); - - layout->addWidget(m_Filter); - layout->addWidget(m_TreeView); -} - -void QmitkPropertyTreeView::OnFilterChanged(const QString &filter) -{ - m_ProxyModel->setFilterWildcard(filter); - m_TreeView->expandAll(); -} - -void QmitkPropertyTreeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) -{ - std::string partName = "Properties"; - - if (nodes.empty() || nodes.front().IsNull()) - { - SetPartName(partName); - m_Model->SetProperties(NULL); - } - else - { - std::ostringstream extPartName; - extPartName << partName << " (" << nodes.front()->GetName() << ")"; - SetPartName(extPartName.str().c_str()); - - m_Model->SetProperties(nodes.front()->GetPropertyList()); - } -} - -void QmitkPropertyTreeView::SetFocus() -{ - m_Filter->setFocus(); -} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.h b/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.h deleted file mode 100644 index da2ed3aef7..0000000000 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeView.h +++ /dev/null @@ -1,61 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#ifndef QMITKPROPERTYTREEVIEW_H -#define QMITKPROPERTYTREEVIEW_H - -#include -#include - -class QmitkLineEdit; -class QmitkPropertyDelegate; -class QmitkPropertyTreeModel; -class QmitkPropertyTreeFilterProxyModel; -class QTreeView; - -class MITK_QT_DATAMANAGER QmitkPropertyTreeView : public QmitkAbstractView -{ - Q_OBJECT - -public: - berryObjectMacro(QmitkPropertyTreeView) - - static const std::string VIEW_ID; - - QmitkPropertyTreeView(); - ~QmitkPropertyTreeView(); - - void CreateQtPartControl(QWidget *parent); - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes); - -protected: - void SetFocus(); - -private slots: - void OnFilterChanged(const QString &filter); - -private: - QmitkPropertyTreeView(const QmitkPropertyTreeView &); - QmitkPropertyTreeView & operator=(const QmitkPropertyTreeView &); - - QmitkLineEdit *m_Filter; - QmitkPropertyTreeModel *m_Model; - QmitkPropertyTreeFilterProxyModel *m_ProxyModel; - QmitkPropertyDelegate *m_Delegate; - QTreeView *m_TreeView; -}; - -#endif diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox index 22ba4ed943..0203830475 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/documentation/UserManual/QmitkFiberfoxViewUserManual.dox @@ -1,106 +1,108 @@ /** \page org_mitk_views_fiberfoxview Fiberfox This view provides the user interface for Fiberfox [1], an interactive simulation tool for defining artificial white matter fibers and generating corresponding diffusion weighted images. Arbitrary fiber configurations like bent, crossing, kissing, twisting, and fanning bundles can be intuitively defined by positioning only a few 3D waypoints to trigger the automated generation of synthetic fibers. From these fibers a diffusion weighted signal is simulated using a flexible combination of various diffusion models. It can be modified using specified acquisition settings such as gradient direction, b-value, signal-to-noise ratio, image size, and resolution. Available sections: - \ref QmitkFiberfoxViewUserManualFiberDefinition - \ref QmitkFiberfoxViewUserManualSignalGeneration - \ref QmitkFiberfoxViewUserManualKnownIssues - \ref QmitkFiberfoxViewUserManualReferences \image html Fiberfox.png Fig. 1: Screenshot of the Fiberfox framework. The four render windows display an axial (top left), sagittal (top right) and coronal (bottom left) 2D cut as well as a 3D view of a synthetic fiber helix and the fiducials used to define its shape. In the 2D views the helix is superimposing the baseline volume of the corresponding diffusion weighted image. The sagittal render window shows a close-up view on one of the circular fiducials. \section QmitkFiberfoxViewUserManualFiberDefinition Fiber Definition Fiber strands are defined simply by placing markers in a 3D image volume. The fibers are then interpolated between these fiducials. Example: \li Chose an image volume to place the markers used to define the fiber pathway. If you don't have such an image available switch to the "Signal Generation" tab, define the size and spacing of the desired image and click "Generate Image". If no fiber bundle is selected, this will generate a dummy image that can be used to place the fiducials. \li Start placing fiducials at the desired positions to define the fiber pathway. To do that, click on the button with the circle pictogram, then click at the desired position and plane in the image volume and drag your mouse while keeping the button pressed to generate a circular shape. Adjust the shape using the control points (Fig. 2). The position of control point D introduces a twist of the fibers between two successive fiducials. The actual fiber generation is triggered automatically as soon as you place the second control point. \li In some cases the fibers are entangled in a way that can't be resolved by introducing an additional fiber twist. Fiberfox tries to avoid these situations, which arise from different normal orientations of succeeding fiducials, automatically. In rare cases this is not successful. Use the double-arrow button to flip the fiber positions of the selected fiducial in one dimension. Either the problem is resolved now or you can resolve it manually by adjusting the twist-control point. \image html Fiberfox-Fiducial.png Fig. 2: Control points defining the actual shape of the fiducial. A specifies the fiducials position in space, B and C the two ellipse radii and D the twisting angle between two successive fiducials. Fiber Options: \li Real Time Fibers: If checked, each parameter adjustment (fiducial position, number of fibers, ...) will be directly applied to the selected fiber bundle. If unchecked, the fibers will only be generated if the corresponding button "Generate Fibers" is clicked. \li Advanced Options: Show/hide advanced options \li #Fibers: Specifies the number of fibers that will be generated for the selected bundle. \li Fiber Sampling: Adjusts the number of points per cm that make up the fiber. A higher sampling rate is needed if high curvatures are modeled. \li Tension, Continuity, Bias: Parameters controlling the shape of the splines interpolation the fiducials. See Wikipedia for details. Fiducial Options: \li Use Constant Fiducial Radius: If checked, all fiducials are treated as circles with the same radius. The first fiducial of the bundle defines the radius of all other fiducials. \li Align with grid: Click to shift all fiducial center points to the next voxel center. Operations: \li Rotation: Define the rotation of the selected fiber bundle around each axis (in degree). \li Translation: Define the translation of the selected fiber bundle along each axis (in mm). \li Scaling: Define a scaling factor for the selected fiber bundle in each dimension. \li Transform Selection: Apply specified rotation, translation and scaling to the selected Bundle/Fiducial \li Copy Bundles: Add copies of the selected fiber bundles to the datamanager. \li Join Bundles: Add new bundle to the datamanager that contains all fibers from the selected bundles. \li Include Fiducials: If checked, the specified transformation is also applied to the fiducials belonging to the selected fiber bundle and the fiducials are also copied. \image html FiberfoxExamples.png Fig. 3: Examples of artificial crossing (a,b), fanning (c,d), highly curved (e,f), kissing (g,h) and twisting (i,j) fibers as well as of the corresponding tensor images generated with Fiberfox. \section QmitkFiberfoxViewUserManualSignalGeneration Signal Generation To generate an artificial signal from the input fibers we follow the concepts recently presented by Panagiotaki et al. in a review and taxonomy of different compartment models [2]: a flexible model combining multiple compartments is used to simulate the anisotropic diffusion inside (intra-axonal compartment) and between axons (inter-axonal compartment), isotropic diffusion outside of the axons (extra-axonal compartment 1) and the restricted diffusion in other cell types (extra-axonal compartment 2) weighted according to their respective volume fraction. A diffusion weighted image is generated from the fibers by selecting the according fiber bundle in the datamanager and clicking "Generate Image". If some other diffusion weighted image is selected together with the fiber bundle, Fiberfox directly uses the parameters of the selected image (size, spacing, gradient directions, b-values) for the signal generation process. Additionally a binary image can be selected that defines the tissue area. Voxels outside of this mask will contain no signal, only noise. Basic Image Settings: \li Image Dimensions: Specifies actual image size (number of voxels in each dimension). \li Image Spacing: Specifies voxel size in mm. Beware that changing the voxel size also changes the signal strength, e.g. increasing the resolution from 2x2x2 mm to 1x1x1 mm decreases the signal obtained for each voxel by a factor 8. \li Gradient Directions: Number of gradients directions distributed equally over the half sphere. 10% baseline images are automatically added. \li b-Value: Diffusion weighting in s/mm². If an existing diffusion weighted image is used to set the basic parameters, the b-value is defined by the gradient direction magnitudes of this image, which also enables the use of multiple b-values. Advanced Image Settings (activate checkbox "Advanced Options"): \li Repetitions: Specifies the number of averages used for the acquisition to reduce noise. \li Signal Scale: Additional scaling factor for the signal in each voxel. The default value of 125 results in a maximum signal amplitude of 1000 for 2x2x2 mm voxels. Beware that changing this value without changing the noise variance results in a changed SNR. Adjustment of this value might be needed if the overall signal values are much too high or much too low (depends on a variety of factors like voxel size and relaxation times). \li Echo Time TE: Time between the 90° excitation pulse and the first spin echo. Increasing this time results in a stronger T2-relaxation effect (Wikipedia). \li Line Readout Time: Time to read one line in k-space. Increasing this time results in a stronger T2* effect which causes an attenuation of the higher frequencies in phase direction (here along y-axis) which again results in a blurring effect of sharp edges perpendicular to the phase direction. \li Tinhom Relaxation: Time constant specifying the signal decay due to magnetic field inhomogeneities (also called T2'). Together with the tissue specific relaxation time constant T2 this defines the T2* decay constant: T2*=(T2 T2')/(T2+T2') \li Fiber Radius (in µm): Used to calculate the volume fractions of the used compartments (fiber, water, etc.). If set to 0 (default) the fiber radius is set automatically so that the voxel containing the most fibers is filled completely. A realistic axon radius ranges from about 5 to 20 microns. Using the automatic estimation the resulting value might very well be much larger or smaller than this range. \li Interpolation Shrink: The signal generated at each position along the fibers is distributed on the surrounding voxels using an interpolation scheme shaped like an arctangent function. Large values result in a steeper interpolation scheme approximating a nearest neighbor interpolation. Very small values result in an almost linear interpolation. \li Enforce Pure Fiber Voxels: If checked, the actual volume fractions of the single compartments are ignored. A voxel will either be filled by the intra axonal compartment completely or will contain no fiber at all. \li Output k-Space Image: Some of the effects simulated in our framework are modeled in the k-space representation of the actual image. Checking this box will output this frequency representation (amplitude spectrum). Compartment Settings: The group-boxes "Intra-axonal Compartment", "Inter-axonal Compartment" and "Extra-axonal Compartments" allow the specification which model to use and the corresponding model parameters. Currently the following models are implemented: \li Stick: The “stick†model describes diffusion in an idealized cylinder with zero radius. Parameter: Diffusivity d \li Zeppelin: Cylindrically symmetric diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity d⊥ \li Tensor: Full diffusion tensor. Parameters: Parallel diffusivity d|| and perpendicular diffusivity constants d⊥1 and d⊥2 \li Ball: Isotropic compartment. Parameter: Diffusivity d \li Astrosticks: Consists of multiple stick models pointing in different directions. The single stick orientations can either be distributed equally over the sphere or are sampled randomly. The model represents signal coming from a type of glial cell called astrocytes, or populations of axons with arbitrary orientation. Parameters: randomization of the stick orientations and diffusivity of the sticks d. \li Dot: Isotropically restricted compartment. No parameter. For a detailed description of the single models, please refer to Panagiotaki et al. "Compartment models of the diffusion MR signal in brain white matter: A taxonomy and comparison."[2]. Additionally to the model parameters, each compartment has its own T2 signal relaxation constant (in ms). Noise and Artifacts: -\li Variance: Adds Rician noise with the specified variance to the signal. -\li Gibbs Ringing: Ringing artifacts occurring on edges in the image due to the frequency low-pass filtering caused by the limited size of the k-space. The higher the oversampling factor, the larger the distance from the corresponding edge in which the ringing is still visible. +\li Rician Noise: Add Rician noise with the specified variance to the signal. +\li N/2 Ghosts: Specify the offset between successive lines in k-space. This offset causes ghost images in distance N/2 in phase direction due to the alternating EPI readout directions. +\li Distortions: Simulate distortions due to magnetic field inhomogeneities. This is achieved by adding an additional phase during the readout process. The input is a frequency map specifying the inhomogeneities. +\li Gibbs Ringing: Ringing artifacts occurring on edges in the image due to the frequency low-pass filtering caused by the limited size of the k-space. The higher the oversampling factor, the larger the distance from the corresponding edge in which the ringing is still visible. Keep in mind that increasing the oversampling factor results in a quadratic increase of computation time. \section QmitkFiberfoxViewUserManualKnownIssues Known Issues \li If fiducials are created in one of the marginal slices of the underlying image, a position change of the fiducial can be observed upon selection/deselection. If the fiducial is created in any other slice this bug does not occur. \li If a scaling factor is applied to the selcted fiber bundle, the corresponding fiducials are not scaled accordingly. \li In some cases the automatic update of the selected fiber bundle is not triggered even if "Real Time Fibers" is checked, e.g. if a fiducial is deleted. If this happens on can always force an update by pressing the "Generate Fibers" button. If any other issues or feature requests arises during the use of Fiberfox, please don't hesitate to send us an e-mail or directly report the issue in our bugtracker: http://bugs.mitk.org/ \section QmitkFiberfoxViewUserManualReferences References [1] Peter F. Neher, Bram Stieltjes, Frederik B. Laun, Hans-Peter Meinzer, and Klaus H. Fritzsche: Fiberfox: A novel tool to generate software phantoms of complex fiber geometries. In proceedings: ISMRM 2013 [2] Panagiotaki, E., Schneider, T., Siow, B., Hall, M.G., Lythgoe, M.F., Alexander, D.C.: Compartment models of the diffusion mr signal in brain white matter: A taxonomy and comparison. Neuroimage 59 (2012) 2241–2254 */ diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp index 23b8a8c7ab..10902ded2f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.cpp @@ -1,1594 +1,1670 @@ /*=================================================================== 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. ===================================================================*/ //misc #define _USE_MATH_DEFINES #include // Blueberry #include #include // Qmitk #include "QmitkFiberfoxView.h" // MITK #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 #define _USE_MATH_DEFINES #include const std::string QmitkFiberfoxView::VIEW_ID = "org.mitk.views.fiberfoxview"; QmitkFiberfoxView::QmitkFiberfoxView() : QmitkAbstractView() , m_Controls( 0 ) , m_SelectedImage( NULL ) { } // Destructor QmitkFiberfoxView::~QmitkFiberfoxView() { } void QmitkFiberfoxView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberfoxViewControls; m_Controls->setupUi( parent ); m_Controls->m_StickWidget1->setVisible(true); m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); m_Controls->m_BallWidget1->setVisible(true); m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_VarianceBox->setVisible(false); - m_Controls->m_KspaceParamFrame->setVisible(false); + m_Controls->m_GibbsRingingFrame->setVisible(false); + m_Controls->m_NoiseFrame->setVisible(true); + m_Controls->m_GhostFrame->setVisible(false); + m_Controls->m_DistortionsFrame->setVisible(false); + + m_Controls->m_FrequencyMapBox->SetDataStorage(this->GetDataStorage()); + mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); + mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); + mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); + mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); + mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); + isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); + mitk::NodePredicateNot::Pointer noDiffusionImage = mitk::NodePredicateNot::New(isDiffusionImage); + mitk::NodePredicateAnd::Pointer finalPredicate = mitk::NodePredicateAnd::New(isMitkImage, noDiffusionImage); + m_Controls->m_FrequencyMapBox->SetPredicate(finalPredicate); connect((QObject*) m_Controls->m_GenerateImageButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateImage())); connect((QObject*) m_Controls->m_GenerateFibersButton, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateFibers())); connect((QObject*) m_Controls->m_CircleButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnDrawROI())); connect((QObject*) m_Controls->m_FlipButton, SIGNAL(clicked()), (QObject*) this, SLOT(OnFlipButton())); connect((QObject*) m_Controls->m_JoinBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(JoinBundles())); connect((QObject*) m_Controls->m_VarianceBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnVarianceChanged(double))); connect((QObject*) m_Controls->m_DistributionBox, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(OnDistributionChanged(int))); connect((QObject*) m_Controls->m_FiberDensityBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberDensityChanged(int))); connect((QObject*) m_Controls->m_FiberSamplingBox, SIGNAL(valueChanged(int)), (QObject*) this, SLOT(OnFiberSamplingChanged(int))); connect((QObject*) m_Controls->m_TensionBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnTensionChanged(double))); connect((QObject*) m_Controls->m_ContinuityBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnContinuityChanged(double))); connect((QObject*) m_Controls->m_BiasBox, SIGNAL(valueChanged(double)), (QObject*) this, SLOT(OnBiasChanged(double))); connect((QObject*) m_Controls->m_AddGibbsRinging, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGibbsRinging(int))); + connect((QObject*) m_Controls->m_AddNoise, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddNoise(int))); + connect((QObject*) m_Controls->m_AddGhosts, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddGhosts(int))); + connect((QObject*) m_Controls->m_AddDistortions, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnAddDistortions(int))); + connect((QObject*) m_Controls->m_ConstantRadiusBox, SIGNAL(stateChanged(int)), (QObject*) this, SLOT(OnConstantRadius(int))); connect((QObject*) m_Controls->m_CopyBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(CopyBundles())); connect((QObject*) m_Controls->m_TransformBundlesButton, SIGNAL(clicked()), (QObject*) this, SLOT(ApplyTransform())); connect((QObject*) m_Controls->m_AlignOnGrid, SIGNAL(clicked()), (QObject*) this, SLOT(AlignOnGrid())); connect((QObject*) m_Controls->m_Compartment1Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp1ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment2Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp2ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment3Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp3ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_Compartment4Box, SIGNAL(currentIndexChanged(int)), (QObject*) this, SLOT(Comp4ModelFrameVisibility(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); connect((QObject*) m_Controls->m_AdvancedOptionsBox_2, SIGNAL( stateChanged(int)), (QObject*) this, SLOT(ShowAdvancedOptions(int))); } } void QmitkFiberfoxView::ShowAdvancedOptions(int state) { if (state) { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(true); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(true); m_Controls->m_AdvancedOptionsBox->setChecked(true); m_Controls->m_AdvancedOptionsBox_2->setChecked(true); } else { m_Controls->m_AdvancedFiberOptionsFrame->setVisible(false); m_Controls->m_AdvancedSignalOptionsFrame->setVisible(false); m_Controls->m_AdvancedOptionsBox->setChecked(false); m_Controls->m_AdvancedOptionsBox_2->setChecked(false); } } void QmitkFiberfoxView::Comp1ModelFrameVisibility(int index) { m_Controls->m_StickWidget1->setVisible(false); m_Controls->m_ZeppelinWidget1->setVisible(false); m_Controls->m_TensorWidget1->setVisible(false); switch (index) { case 0: m_Controls->m_StickWidget1->setVisible(true); break; case 1: m_Controls->m_ZeppelinWidget1->setVisible(true); break; case 2: m_Controls->m_TensorWidget1->setVisible(true); break; } } void QmitkFiberfoxView::Comp2ModelFrameVisibility(int index) { m_Controls->m_StickWidget2->setVisible(false); m_Controls->m_ZeppelinWidget2->setVisible(false); m_Controls->m_TensorWidget2->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_StickWidget2->setVisible(true); break; case 2: m_Controls->m_ZeppelinWidget2->setVisible(true); break; case 3: m_Controls->m_TensorWidget2->setVisible(true); break; } } void QmitkFiberfoxView::Comp3ModelFrameVisibility(int index) { m_Controls->m_BallWidget1->setVisible(false); m_Controls->m_AstrosticksWidget1->setVisible(false); m_Controls->m_DotWidget1->setVisible(false); switch (index) { case 0: m_Controls->m_BallWidget1->setVisible(true); break; case 1: m_Controls->m_AstrosticksWidget1->setVisible(true); break; case 2: m_Controls->m_DotWidget1->setVisible(true); break; } } void QmitkFiberfoxView::Comp4ModelFrameVisibility(int index) { m_Controls->m_BallWidget2->setVisible(false); m_Controls->m_AstrosticksWidget2->setVisible(false); m_Controls->m_DotWidget2->setVisible(false); m_Controls->m_Comp4FractionFrame->setVisible(false); switch (index) { case 0: break; case 1: m_Controls->m_BallWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 2: m_Controls->m_AstrosticksWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; case 3: m_Controls->m_DotWidget2->setVisible(true); m_Controls->m_Comp4FractionFrame->setVisible(true); break; } } void QmitkFiberfoxView::OnConstantRadius(int value) { if (value>0 && m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } +void QmitkFiberfoxView::OnAddDistortions(int value) +{ + if (value>0) + m_Controls->m_DistortionsFrame->setVisible(true); + else + m_Controls->m_DistortionsFrame->setVisible(false); +} + +void QmitkFiberfoxView::OnAddGhosts(int value) +{ + if (value>0) + m_Controls->m_GhostFrame->setVisible(true); + else + m_Controls->m_GhostFrame->setVisible(false); +} + +void QmitkFiberfoxView::OnAddNoise(int value) +{ + if (value>0) + m_Controls->m_NoiseFrame->setVisible(true); + else + m_Controls->m_NoiseFrame->setVisible(false); +} + void QmitkFiberfoxView::OnAddGibbsRinging(int value) { if (value>0) - m_Controls->m_KspaceParamFrame->setVisible(true); + m_Controls->m_GibbsRingingFrame->setVisible(true); else - m_Controls->m_KspaceParamFrame->setVisible(false); + m_Controls->m_GibbsRingingFrame->setVisible(false); } void QmitkFiberfoxView::OnDistributionChanged(int value) { if (value==1) m_Controls->m_VarianceBox->setVisible(true); else m_Controls->m_VarianceBox->setVisible(false); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnVarianceChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberDensityChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFiberSamplingChanged(int value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnTensionChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnContinuityChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnBiasChanged(double value) { if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::AlignOnGrid() { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::DataStorage::SetOfObjects::ConstPointer parentFibs = GetDataStorage()->GetSources(m_SelectedFiducials.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = parentFibs->begin(); it != parentFibs->end(); ++it ) { mitk::DataNode::Pointer pFibNode = *it; if ( pFibNode.IsNotNull() && dynamic_cast(pFibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(pFibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { mitk::Image::Pointer img = dynamic_cast(pImgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); break; } } break; } } } for( int i=0; iGetSources(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it = sources->begin(); it != sources->end(); ++it ) { mitk::DataNode::Pointer imgNode = *it; if ( imgNode.IsNotNull() && dynamic_cast(imgNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Image::Pointer img = dynamic_cast(imgNode->GetData()); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } break; } } } for( int i=0; i(m_SelectedImages.at(i)->GetData()); mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) { mitk::DataStorage::SetOfObjects::ConstPointer derivations2 = GetDataStorage()->GetDerivations(fibNode); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations2->begin(); it2 != derivations2->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = dynamic_cast(fiducialNode->GetData()); mitk::Point3D wc0 = pe->GetWorldControlPoint(0); mitk::Geometry3D::Pointer geom = img->GetGeometry(); itk::Index<3> idx; geom->WorldToIndex(wc0, idx); mitk::Point3D cIdx; cIdx[0]=idx[0]; cIdx[1]=idx[1]; cIdx[2]=idx[2]; mitk::Point3D world; geom->IndexToWorld(cIdx,world); mitk::Vector3D trans = world - wc0; pe->GetGeometry()->Translate(trans); } } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::OnFlipButton() { if (m_SelectedFiducial.IsNull()) return; std::map::iterator it = m_DataNodeToPlanarFigureData.find(m_SelectedFiducial.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; data.m_Flipped += 1; data.m_Flipped %= 2; } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } QmitkFiberfoxView::GradientListType QmitkFiberfoxView::GenerateHalfShell(int NPoints) { NPoints *= 2; GradientListType pointshell; int numB0 = NPoints/20; if (numB0==0) numB0=1; GradientType g; g.Fill(0.0); for (int i=0; i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*M_PI); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i std::vector > QmitkFiberfoxView::MakeGradientList() { std::vector > retval; vnl_matrix_fixed* U = itk::PointShell >::DistributePointShell(); // Add 0 vector for B0 int numB0 = ndirs/10; if (numB0==0) numB0=1; itk::Vector v; v.Fill(0.0); for (int i=0; i v; v[0] = U->get(0,i); v[1] = U->get(1,i); v[2] = U->get(2,i); retval.push_back(v); } return retval; } void QmitkFiberfoxView::OnAddBundle() { if (m_SelectedImage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedImage); mitk::FiberBundleX::Pointer bundle = mitk::FiberBundleX::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( bundle ); QString name = QString("Bundle_%1").arg(children->size()); node->SetName(name.toStdString()); m_SelectedBundles.push_back(node); UpdateGui(); GetDataStorage()->Add(node, m_SelectedImage); } void QmitkFiberfoxView::OnDrawROI() { if (m_SelectedBundles.empty()) OnAddBundle(); if (m_SelectedBundles.empty()) return; mitk::DataStorage::SetOfObjects::ConstPointer children = GetDataStorage()->GetDerivations(m_SelectedBundles.at(0)); mitk::PlanarEllipse::Pointer figure = mitk::PlanarEllipse::New(); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( figure ); QList nodes = this->GetDataManagerSelection(); for( int i=0; iSetSelected(false); m_SelectedFiducial = node; QString name = QString("Fiducial_%1").arg(children->size()); node->SetName(name.toStdString()); node->SetSelected(true); GetDataStorage()->Add(node, m_SelectedBundles.at(0)); this->DisableCrosshairNavigation(); mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); if(figureInteractor.IsNull()) figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", node); mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); UpdateGui(); } bool CompareLayer(mitk::DataNode::Pointer i,mitk::DataNode::Pointer j) { int li = -1; i->GetPropertyValue("layer", li); int lj = -1; j->GetPropertyValue("layer", lj); return liGetSources(m_SelectedFiducial); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) if(dynamic_cast((*it)->GetData())) m_SelectedBundles.push_back(*it); if (m_SelectedBundles.empty()) return; } vector< vector< mitk::PlanarEllipse::Pointer > > fiducials; vector< vector< unsigned int > > fliplist; for (int i=0; iGetDerivations(m_SelectedBundles.at(i)); std::vector< mitk::DataNode::Pointer > childVector; for( mitk::DataStorage::SetOfObjects::const_iterator it = children->begin(); it != children->end(); ++it ) childVector.push_back(*it); sort(childVector.begin(), childVector.end(), CompareLayer); vector< mitk::PlanarEllipse::Pointer > fib; vector< unsigned int > flip; float radius = 1; int count = 0; for( std::vector< mitk::DataNode::Pointer >::const_iterator it = childVector.begin(); it != childVector.end(); ++it ) { mitk::DataNode::Pointer node = *it; if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { mitk::PlanarEllipse* ellipse = dynamic_cast(node->GetData()); if (m_Controls->m_ConstantRadiusBox->isChecked()) { ellipse->SetTreatAsCircle(true); mitk::Point2D c = ellipse->GetControlPoint(0); mitk::Point2D p = ellipse->GetControlPoint(1); mitk::Vector2D v = p-c; if (count==0) { radius = v.GetVnlVector().magnitude(); ellipse->SetControlPoint(1, p); } else { v.Normalize(); v *= radius; ellipse->SetControlPoint(1, c+v); } } fib.push_back(ellipse); std::map::iterator it = m_DataNodeToPlanarFigureData.find(node.GetPointer()); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; flip.push_back(data.m_Flipped); } else flip.push_back(0); } count++; } if (fib.size()>1) { fiducials.push_back(fib); fliplist.push_back(flip); } else if (fib.size()>0) m_SelectedBundles.at(i)->SetData( mitk::FiberBundleX::New() ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } itk::FibersFromPlanarFiguresFilter::Pointer filter = itk::FibersFromPlanarFiguresFilter::New(); filter->SetFiducials(fiducials); filter->SetFlipList(fliplist); switch(m_Controls->m_DistributionBox->currentIndex()){ case 0: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_UNIFORM); break; case 1: filter->SetFiberDistribution(itk::FibersFromPlanarFiguresFilter::DISTRIBUTE_GAUSSIAN); filter->SetVariance(m_Controls->m_VarianceBox->value()); break; } filter->SetDensity(m_Controls->m_FiberDensityBox->value()); filter->SetTension(m_Controls->m_TensionBox->value()); filter->SetContinuity(m_Controls->m_ContinuityBox->value()); filter->SetBias(m_Controls->m_BiasBox->value()); filter->SetFiberSampling(m_Controls->m_FiberSamplingBox->value()); filter->Update(); vector< mitk::FiberBundleX::Pointer > fiberBundles = filter->GetFiberBundles(); for (int i=0; iSetData( fiberBundles.at(i) ); if (fiberBundles.at(i)->GetNumFibers()>50000) m_SelectedBundles.at(i)->SetVisibility(false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::GenerateImage() { itk::ImageRegion<3> imageRegion; imageRegion.SetSize(0, m_Controls->m_SizeX->value()); imageRegion.SetSize(1, m_Controls->m_SizeY->value()); imageRegion.SetSize(2, m_Controls->m_SizeZ->value()); mitk::Vector3D spacing; spacing[0] = m_Controls->m_SpacingX->value(); spacing[1] = m_Controls->m_SpacingY->value(); spacing[2] = m_Controls->m_SpacingZ->value(); mitk::Point3D origin; origin[0] = spacing[0]/2; origin[1] = spacing[1]/2; origin[2] = spacing[2]/2; itk::Matrix directionMatrix; directionMatrix.SetIdentity(); if (m_SelectedBundles.empty()) { mitk::Image::Pointer image = mitk::ImageGenerator::GenerateGradientImage( m_Controls->m_SizeX->value(), m_Controls->m_SizeY->value(), m_Controls->m_SizeZ->value(), m_Controls->m_SpacingX->value(), m_Controls->m_SpacingY->value(), m_Controls->m_SpacingZ->value()); mitk::Geometry3D* geom = image->GetGeometry(); geom->SetOrigin(origin); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName("Dummy"); unsigned int window = m_Controls->m_SizeX->value()*m_Controls->m_SizeY->value()*m_Controls->m_SizeZ->value(); unsigned int level = window/2; mitk::LevelWindow lw; lw.SetLevelWindow(level, window); node->SetProperty( "levelwindow", mitk::LevelWindowProperty::New( lw ) ); GetDataStorage()->Add(node); m_SelectedImage = node; mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } UpdateGui(); return; } if (m_SelectedImage.IsNotNull()) { mitk::Image* img = dynamic_cast(m_SelectedImage->GetData()); itk::Image< float, 3 >::Pointer itkImg = itk::Image< float, 3 >::New(); CastToItkImage< itk::Image< float, 3 > >(img, itkImg); imageRegion = itkImg->GetLargestPossibleRegion(); spacing = itkImg->GetSpacing(); origin = itkImg->GetOrigin(); directionMatrix = itkImg->GetDirection(); } DiffusionSignalModel::GradientListType gradientList; double bVal = 1000; if (m_SelectedDWI.IsNull()) { gradientList = GenerateHalfShell(m_Controls->m_NumGradientsBox->value());; bVal = m_Controls->m_BvalueBox->value(); } else { mitk::DiffusionImage::Pointer dwi = dynamic_cast*>(m_SelectedDWI->GetData()); imageRegion = dwi->GetVectorImage()->GetLargestPossibleRegion(); spacing = dwi->GetVectorImage()->GetSpacing(); origin = dwi->GetVectorImage()->GetOrigin(); directionMatrix = dwi->GetVectorImage()->GetDirection(); bVal = dwi->GetB_Value(); mitk::DiffusionImage::GradientDirectionContainerType::Pointer dirs = dwi->GetDirections(); for (int i=0; iSize(); i++) { DiffusionSignalModel::GradientType g; g[0] = dirs->at(i)[0]; g[1] = dirs->at(i)[1]; g[2] = dirs->at(i)[2]; gradientList.push_back(g); } } for (int i=0; im_Compartment4Box->currentIndex()>0) { comp4Weight = m_Controls->m_Comp4FractionBox->value(); comp3Weight -= comp4Weight; } mitk::StickModel stickModel1; mitk::StickModel stickModel2; mitk::TensorModel zeppelinModel1; mitk::TensorModel zeppelinModel2; mitk::TensorModel tensorModel1; mitk::TensorModel tensorModel2; mitk::BallModel ballModel1; mitk::BallModel ballModel2; mitk::AstroStickModel astrosticksModel1; mitk::AstroStickModel astrosticksModel2; mitk::DotModel dotModel1; mitk::DotModel dotModel2; // compartment 1 switch (m_Controls->m_Compartment1Box->currentIndex()) { case 0: MITK_INFO << "Using stick model"; stickModel1.SetGradientList(gradientList); stickModel1.SetDiffusivity(m_Controls->m_StickWidget1->GetD()); stickModel1.SetT2(m_Controls->m_StickWidget1->GetT2()); fiberModelList.push_back(&stickModel1); signalModelString += "Stick"; resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Stick") ); resultNode->AddProperty("Fiberfox.Compartment1.D", DoubleProperty::New(m_Controls->m_StickWidget1->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(stickModel1.GetT2()) ); break; case 1: MITK_INFO << "Using zeppelin model"; zeppelinModel1.SetGradientList(gradientList); zeppelinModel1.SetBvalue(bVal); zeppelinModel1.SetDiffusivity1(m_Controls->m_ZeppelinWidget1->GetD1()); zeppelinModel1.SetDiffusivity2(m_Controls->m_ZeppelinWidget1->GetD2()); zeppelinModel1.SetDiffusivity3(m_Controls->m_ZeppelinWidget1->GetD2()); zeppelinModel1.SetT2(m_Controls->m_ZeppelinWidget1->GetT2()); fiberModelList.push_back(&zeppelinModel1); signalModelString += "Zeppelin"; resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Zeppelin") ); resultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD1()) ); resultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget1->GetD2()) ); resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(zeppelinModel1.GetT2()) ); break; case 2: MITK_INFO << "Using tensor model"; tensorModel1.SetGradientList(gradientList); tensorModel1.SetBvalue(bVal); tensorModel1.SetDiffusivity1(m_Controls->m_TensorWidget1->GetD1()); tensorModel1.SetDiffusivity2(m_Controls->m_TensorWidget1->GetD2()); tensorModel1.SetDiffusivity3(m_Controls->m_TensorWidget1->GetD3()); tensorModel1.SetT2(m_Controls->m_TensorWidget1->GetT2()); fiberModelList.push_back(&tensorModel1); signalModelString += "Tensor"; resultNode->AddProperty("Fiberfox.Compartment1.Description", StringProperty::New("Intra-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment1.Model", StringProperty::New("Tensor") ); resultNode->AddProperty("Fiberfox.Compartment1.D1", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD1()) ); resultNode->AddProperty("Fiberfox.Compartment1.D2", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD2()) ); resultNode->AddProperty("Fiberfox.Compartment1.D3", DoubleProperty::New(m_Controls->m_TensorWidget1->GetD3()) ); resultNode->AddProperty("Fiberfox.Compartment1.T2", DoubleProperty::New(zeppelinModel1.GetT2()) ); break; } // compartment 2 switch (m_Controls->m_Compartment2Box->currentIndex()) { case 0: break; case 1: stickModel2.SetGradientList(gradientList); stickModel2.SetDiffusivity(m_Controls->m_StickWidget2->GetD()); stickModel2.SetT2(m_Controls->m_StickWidget2->GetT2()); fiberModelList.push_back(&stickModel2); signalModelString += "Stick"; resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Stick") ); resultNode->AddProperty("Fiberfox.Compartment2.D", DoubleProperty::New(m_Controls->m_StickWidget2->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(stickModel2.GetT2()) ); break; case 2: zeppelinModel2.SetGradientList(gradientList); zeppelinModel2.SetBvalue(bVal); zeppelinModel2.SetDiffusivity1(m_Controls->m_ZeppelinWidget2->GetD1()); zeppelinModel2.SetDiffusivity2(m_Controls->m_ZeppelinWidget2->GetD2()); zeppelinModel2.SetDiffusivity3(m_Controls->m_ZeppelinWidget2->GetD2()); zeppelinModel2.SetT2(m_Controls->m_ZeppelinWidget2->GetT2()); fiberModelList.push_back(&zeppelinModel2); signalModelString += "Zeppelin"; resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Zeppelin") ); resultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD1()) ); resultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_ZeppelinWidget2->GetD2()) ); resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(zeppelinModel2.GetT2()) ); break; case 3: tensorModel2.SetGradientList(gradientList); tensorModel2.SetBvalue(bVal); tensorModel2.SetDiffusivity1(m_Controls->m_TensorWidget2->GetD1()); tensorModel2.SetDiffusivity2(m_Controls->m_TensorWidget2->GetD2()); tensorModel2.SetDiffusivity3(m_Controls->m_TensorWidget2->GetD3()); tensorModel2.SetT2(m_Controls->m_TensorWidget2->GetT2()); fiberModelList.push_back(&tensorModel2); signalModelString += "Tensor"; resultNode->AddProperty("Fiberfox.Compartment2.Description", StringProperty::New("Inter-axonal compartment") ); resultNode->AddProperty("Fiberfox.Compartment2.Model", StringProperty::New("Tensor") ); resultNode->AddProperty("Fiberfox.Compartment2.D1", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD1()) ); resultNode->AddProperty("Fiberfox.Compartment2.D2", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD2()) ); resultNode->AddProperty("Fiberfox.Compartment2.D3", DoubleProperty::New(m_Controls->m_TensorWidget2->GetD3()) ); resultNode->AddProperty("Fiberfox.Compartment2.T2", DoubleProperty::New(zeppelinModel2.GetT2()) ); break; } // compartment 3 switch (m_Controls->m_Compartment3Box->currentIndex()) { case 0: ballModel1.SetGradientList(gradientList); ballModel1.SetBvalue(bVal); ballModel1.SetDiffusivity(m_Controls->m_BallWidget1->GetD()); ballModel1.SetT2(m_Controls->m_BallWidget1->GetT2()); ballModel1.SetWeight(comp3Weight); nonFiberModelList.push_back(&ballModel1); signalModelString += "Ball"; resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Ball") ); resultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_BallWidget1->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(ballModel1.GetT2()) ); break; case 1: astrosticksModel1.SetGradientList(gradientList); astrosticksModel1.SetBvalue(bVal); astrosticksModel1.SetDiffusivity(m_Controls->m_AstrosticksWidget1->GetD()); astrosticksModel1.SetT2(m_Controls->m_AstrosticksWidget1->GetT2()); astrosticksModel1.SetRandomizeSticks(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()); astrosticksModel1.SetWeight(comp3Weight); nonFiberModelList.push_back(&astrosticksModel1); signalModelString += "Astrosticks"; resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Astrosticks") ); resultNode->AddProperty("Fiberfox.Compartment3.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget1->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(astrosticksModel1.GetT2()) ); resultNode->AddProperty("Fiberfox.Compartment3.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget1->GetRandomizeSticks()) ); break; case 2: dotModel1.SetGradientList(gradientList); dotModel1.SetT2(m_Controls->m_DotWidget1->GetT2()); dotModel1.SetWeight(comp3Weight); nonFiberModelList.push_back(&dotModel1); signalModelString += "Dot"; resultNode->AddProperty("Fiberfox.Compartment3.Description", StringProperty::New("Extra-axonal compartment 1") ); resultNode->AddProperty("Fiberfox.Compartment3.Model", StringProperty::New("Dot") ); resultNode->AddProperty("Fiberfox.Compartment3.T2", DoubleProperty::New(dotModel1.GetT2()) ); break; } // compartment 4 switch (m_Controls->m_Compartment4Box->currentIndex()) { case 0: break; case 1: ballModel2.SetGradientList(gradientList); ballModel2.SetBvalue(bVal); ballModel2.SetDiffusivity(m_Controls->m_BallWidget2->GetD()); ballModel2.SetT2(m_Controls->m_BallWidget2->GetT2()); ballModel2.SetWeight(comp4Weight); nonFiberModelList.push_back(&ballModel2); signalModelString += "Ball"; resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Ball") ); resultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_BallWidget2->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(ballModel2.GetT2()) ); break; case 2: astrosticksModel2.SetGradientList(gradientList); astrosticksModel2.SetBvalue(bVal); astrosticksModel2.SetDiffusivity(m_Controls->m_AstrosticksWidget2->GetD()); astrosticksModel2.SetT2(m_Controls->m_AstrosticksWidget2->GetT2()); astrosticksModel2.SetRandomizeSticks(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()); astrosticksModel2.SetWeight(comp4Weight); nonFiberModelList.push_back(&astrosticksModel2); signalModelString += "Astrosticks"; resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Astrosticks") ); resultNode->AddProperty("Fiberfox.Compartment4.D", DoubleProperty::New(m_Controls->m_AstrosticksWidget2->GetD()) ); resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(astrosticksModel2.GetT2()) ); resultNode->AddProperty("Fiberfox.Compartment4.RandomSticks", BoolProperty::New(m_Controls->m_AstrosticksWidget2->GetRandomizeSticks()) ); break; case 3: dotModel2.SetGradientList(gradientList); dotModel2.SetT2(m_Controls->m_DotWidget2->GetT2()); dotModel2.SetWeight(comp4Weight); nonFiberModelList.push_back(&dotModel2); signalModelString += "Dot"; resultNode->AddProperty("Fiberfox.Compartment4.Description", StringProperty::New("Extra-axonal compartment 2") ); resultNode->AddProperty("Fiberfox.Compartment4.Model", StringProperty::New("Dot") ); resultNode->AddProperty("Fiberfox.Compartment4.T2", DoubleProperty::New(dotModel2.GetT2()) ); break; } itk::TractsToDWIImageFilter::KspaceArtifactList artifactList; - // noise model - double noiseVariance = m_Controls->m_NoiseLevel->value(); + // artifact models + QString artifactModelString(""); + double noiseVariance = 0; + if (m_Controls->m_AddNoise->isChecked()) + { + noiseVariance = m_Controls->m_NoiseLevel->value(); + artifactModelString += "_NOISE"; + artifactModelString += QString::number(noiseVariance); + resultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); + } mitk::RicianNoiseModel noiseModel; noiseModel.SetNoiseVariance(noiseVariance); - // artifact models - QString artifactModelString(""); mitk::GibbsRingingArtifact gibbsModel; if (m_Controls->m_AddGibbsRinging->isChecked()) { - artifactModelString += "_Gibbs-ringing"; + artifactModelString += "_RINGING"; resultNode->AddProperty("Fiberfox.k-Space-Undersampling", IntProperty::New(m_Controls->m_KspaceUndersamplingBox->currentText().toInt())); gibbsModel.SetKspaceCropping((double)m_Controls->m_KspaceUndersamplingBox->currentText().toInt()); artifactList.push_back(&gibbsModel); } if ( this->m_Controls->m_TEbox->value() < imageRegion.GetSize(1)*m_Controls->m_LineReadoutTimeBox->value() ) { this->m_Controls->m_TEbox->setValue( imageRegion.GetSize(1)*m_Controls->m_LineReadoutTimeBox->value() ); QMessageBox::information( NULL, "Warning", "Echo time is too short! Time not sufficient to read slice. Automaticall adjusted to "+QString::number(this->m_Controls->m_TEbox->value())+" ms"); } double lineReadoutTime = m_Controls->m_LineReadoutTimeBox->value(); - // adjusting line readout time to the adapted image size needed for the FFT - int y=2; - while (yimageRegion.GetSize(1)) + // adjusting line readout time to the adapted image size needed for the DFT + int y = imageRegion.GetSize(1); + if ( y%2 == 1 ) + y += 1; + if ( y>imageRegion.GetSize(1) ) lineReadoutTime *= (double)imageRegion.GetSize(1)/y; + // add signal contrast model mitk::SignalDecay contrastModel; contrastModel.SetTinhom(this->m_Controls->m_T2starBox->value()); contrastModel.SetTE(this->m_Controls->m_TEbox->value()); contrastModel.SetTline(lineReadoutTime); artifactList.push_back(&contrastModel); + // add N/2 ghosting + double kOffset = 0; + if (m_Controls->m_AddGhosts->isChecked()) + { + artifactModelString += "_GHOST"; + kOffset = m_Controls->m_kOffsetBox->value(); + resultNode->AddProperty("Fiberfox.Line-Offset", DoubleProperty::New(kOffset)); + } + + // add distortions + if (m_Controls->m_AddDistortions->isChecked() && m_Controls->m_FrequencyMapBox->GetSelectedNode().IsNotNull()) + { + mitk::DataNode::Pointer fMapNode = m_Controls->m_FrequencyMapBox->GetSelectedNode(); + mitk::Image* img = dynamic_cast(fMapNode->GetData()); + ItkDoubleImgType::Pointer itkImg = ItkDoubleImgType::New(); + CastToItkImage< ItkDoubleImgType >(img, itkImg); + + if (imageRegion.GetSize(0)==itkImg->GetLargestPossibleRegion().GetSize(0) && + imageRegion.GetSize(1)==itkImg->GetLargestPossibleRegion().GetSize(1) && + imageRegion.GetSize(2)==itkImg->GetLargestPossibleRegion().GetSize(2)) + tractsToDwiFilter->SetFrequencyMap(itkImg); + } + mitk::FiberBundleX::Pointer fiberBundle = dynamic_cast(m_SelectedBundles.at(i)->GetData()); if (fiberBundle->GetNumFibers()<=0) continue; - itk::TractsToDWIImageFilter::Pointer filter = itk::TractsToDWIImageFilter::New(); - filter->SetImageRegion(imageRegion); - filter->SetSpacing(spacing); - filter->SetOrigin(origin); - filter->SetDirectionMatrix(directionMatrix); - filter->SetFiberBundle(fiberBundle); - filter->SetFiberModels(fiberModelList); - filter->SetNonFiberModels(nonFiberModelList); - filter->SetNoiseModel(&noiseModel); - filter->SetKspaceArtifacts(artifactList); - filter->SetNumberOfRepetitions(m_Controls->m_RepetitionsBox->value()); - filter->SetEnforcePureFiberVoxels(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked()); - filter->SetInterpolationShrink(m_Controls->m_InterpolationShrink->value()); - filter->SetFiberRadius(m_Controls->m_FiberRadius->value()); - filter->SetSignalScale(m_Controls->m_SignalScaleBox->value()); + tractsToDwiFilter->SetImageRegion(imageRegion); + tractsToDwiFilter->SetSpacing(spacing); + tractsToDwiFilter->SetOrigin(origin); + tractsToDwiFilter->SetDirectionMatrix(directionMatrix); + tractsToDwiFilter->SetFiberBundle(fiberBundle); + tractsToDwiFilter->SetFiberModels(fiberModelList); + tractsToDwiFilter->SetNonFiberModels(nonFiberModelList); + tractsToDwiFilter->SetNoiseModel(&noiseModel); + tractsToDwiFilter->SetKspaceArtifacts(artifactList); + tractsToDwiFilter->SetkOffset(kOffset); + tractsToDwiFilter->SettLine(m_Controls->m_LineReadoutTimeBox->value()); + tractsToDwiFilter->SetNumberOfRepetitions(m_Controls->m_RepetitionsBox->value()); + tractsToDwiFilter->SetEnforcePureFiberVoxels(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked()); + tractsToDwiFilter->SetInterpolationShrink(m_Controls->m_InterpolationShrink->value()); + tractsToDwiFilter->SetFiberRadius(m_Controls->m_FiberRadius->value()); + tractsToDwiFilter->SetSignalScale(m_Controls->m_SignalScaleBox->value()); if (m_TissueMask.IsNotNull()) { ItkUcharImgType::Pointer mask = ItkUcharImgType::New(); mitk::CastToItkImage(m_TissueMask, mask); - filter->SetTissueMask(mask); + tractsToDwiFilter->SetTissueMask(mask); } - filter->Update(); + tractsToDwiFilter->Update(); mitk::DiffusionImage::Pointer image = mitk::DiffusionImage::New(); - image->SetVectorImage( filter->GetOutput() ); + image->SetVectorImage( tractsToDwiFilter->GetOutput() ); image->SetB_Value(bVal); image->SetDirections(gradientList); image->InitializeFromVectorImage(); resultNode->SetData( image ); resultNode->SetName(m_SelectedBundles.at(i)->GetName() +"_D"+QString::number(imageRegion.GetSize(0)).toStdString() +"-"+QString::number(imageRegion.GetSize(1)).toStdString() +"-"+QString::number(imageRegion.GetSize(2)).toStdString() +"_S"+QString::number(spacing[0]).toStdString() +"-"+QString::number(spacing[1]).toStdString() +"-"+QString::number(spacing[2]).toStdString() +"_b"+QString::number(bVal).toStdString() - +"_NOISE"+QString::number(noiseVariance).toStdString() +"_"+signalModelString.toStdString() +artifactModelString.toStdString()); GetDataStorage()->Add(resultNode, m_SelectedBundles.at(i)); resultNode->AddProperty("Fiberfox.InterpolationShrink", IntProperty::New(m_Controls->m_InterpolationShrink->value())); resultNode->AddProperty("Fiberfox.SignalScale", IntProperty::New(m_Controls->m_SignalScaleBox->value())); resultNode->AddProperty("Fiberfox.FiberRadius", IntProperty::New(m_Controls->m_FiberRadius->value())); resultNode->AddProperty("Fiberfox.Tinhom", IntProperty::New(m_Controls->m_T2starBox->value())); - resultNode->AddProperty("Fiberfox.Noise-Variance", DoubleProperty::New(noiseVariance)); resultNode->AddProperty("Fiberfox.Repetitions", IntProperty::New(m_Controls->m_RepetitionsBox->value())); resultNode->AddProperty("Fiberfox.b-value", DoubleProperty::New(bVal)); resultNode->AddProperty("Fiberfox.Model", StringProperty::New(signalModelString.toStdString())); resultNode->AddProperty("Fiberfox.PureFiberVoxels", BoolProperty::New(m_Controls->m_EnforcePureFiberVoxelsBox->isChecked())); resultNode->AddProperty("binary", BoolProperty::New(false)); - resultNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New(filter->GetLevelWindow()) ); + resultNode->SetProperty( "levelwindow", mitk::LevelWindowProperty::New(tractsToDwiFilter->GetLevelWindow()) ); if (m_Controls->m_KspaceImageBox->isChecked()) { - itk::Image::Pointer kspace = filter->GetKspaceImage(); + itk::Image::Pointer kspace = tractsToDwiFilter->GetKspaceImage(); mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(kspace.GetPointer()); image->SetVolume(kspace->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( image ); node->SetName(m_SelectedBundles.at(i)->GetName()+"_k-space"); GetDataStorage()->Add(node, m_SelectedBundles.at(i)); } mitk::BaseData::Pointer basedata = resultNode->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } void QmitkFiberfoxView::ApplyTransform() { vector< mitk::DataNode::Pointer > selectedBundles; for( int i=0; iGetDerivations(m_SelectedImages.at(i)); for( mitk::DataStorage::SetOfObjects::const_iterator it = derivations->begin(); it != derivations->end(); ++it ) { mitk::DataNode::Pointer fibNode = *it; if ( fibNode.IsNotNull() && dynamic_cast(fibNode->GetData()) ) selectedBundles.push_back(fibNode); } } if (selectedBundles.empty()) selectedBundles = m_SelectedBundles2; if (!selectedBundles.empty()) { std::vector::const_iterator it = selectedBundles.begin(); for (it; it!=selectedBundles.end(); ++it) { mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); fib->RotateAroundAxis(m_Controls->m_XrotBox->value(), m_Controls->m_YrotBox->value(), m_Controls->m_ZrotBox->value()); fib->TranslateFibers(m_Controls->m_XtransBox->value(), m_Controls->m_YtransBox->value(), m_Controls->m_ZtransBox->value()); fib->ScaleFibers(m_Controls->m_XscaleBox->value(), m_Controls->m_YscaleBox->value(), m_Controls->m_ZscaleBox->value()); // handle child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse* pe = dynamic_cast(fiducialNode->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); // implicit translation mitk::Vector3D trans; trans[0] = geom->GetOrigin()[0]-fib->GetGeometry()->GetCenter()[0]; trans[1] = geom->GetOrigin()[1]-fib->GetGeometry()->GetCenter()[1]; trans[2] = geom->GetOrigin()[2]-fib->GetGeometry()->GetCenter()[2]; mitk::Vector3D newWc = rot*trans; newWc = newWc-trans; geom->Translate(newWc); } } } } } else { for (int i=0; i(m_SelectedFiducials.at(i)->GetData()); mitk::Geometry3D* geom = pe->GetGeometry(); // translate mitk::Vector3D world; world[0] = m_Controls->m_XtransBox->value(); world[1] = m_Controls->m_YtransBox->value(); world[2] = m_Controls->m_ZtransBox->value(); geom->Translate(world); // calculate rotation matrix double x = m_Controls->m_XrotBox->value()*M_PI/180; double y = m_Controls->m_YrotBox->value()*M_PI/180; double z = m_Controls->m_ZrotBox->value()*M_PI/180; itk::Matrix< float, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; itk::Matrix< float, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; itk::Matrix< float, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< float, 3, 3 > rot = rotZ*rotY*rotX; // transform control point coordinate into geometry translation geom->SetOrigin(pe->GetWorldControlPoint(0)); mitk::Point2D cp; cp.Fill(0.0); pe->SetControlPoint(0, cp); // rotate fiducial geom->GetIndexToWorldTransform()->SetMatrix(rot*geom->GetIndexToWorldTransform()->GetMatrix()); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::CopyBundles() { if ( m_SelectedBundles.size()<1 ){ QMessageBox::information( NULL, "Warning", "Select at least one fiber bundle!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least one fiber bundle!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); for (it; it!=m_SelectedBundles.end(); ++it) { // find parent image mitk::DataNode::Pointer parentNode; mitk::DataStorage::SetOfObjects::ConstPointer parentImgs = GetDataStorage()->GetSources(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = parentImgs->begin(); it2 != parentImgs->end(); ++it2 ) { mitk::DataNode::Pointer pImgNode = *it2; if ( pImgNode.IsNotNull() && dynamic_cast(pImgNode->GetData()) ) { parentNode = pImgNode; break; } } mitk::FiberBundleX::Pointer fib = dynamic_cast((*it)->GetData()); mitk::FiberBundleX::Pointer newBundle = fib->GetDeepCopy(); QString name((*it)->GetName().c_str()); name += "_copy"; mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); if (parentNode.IsNotNull()) GetDataStorage()->Add(fbNode, parentNode); else GetDataStorage()->Add(fbNode); // copy child fiducials if (m_Controls->m_IncludeFiducials->isChecked()) { mitk::DataStorage::SetOfObjects::ConstPointer derivations = GetDataStorage()->GetDerivations(*it); for( mitk::DataStorage::SetOfObjects::const_iterator it2 = derivations->begin(); it2 != derivations->end(); ++it2 ) { mitk::DataNode::Pointer fiducialNode = *it2; if ( fiducialNode.IsNotNull() && dynamic_cast(fiducialNode->GetData()) ) { mitk::PlanarEllipse::Pointer pe = mitk::PlanarEllipse::New(); pe->DeepCopy(dynamic_cast(fiducialNode->GetData())); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData(pe); newNode->SetName(fiducialNode->GetName()); GetDataStorage()->Add(newNode, fbNode); } } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::JoinBundles() { if ( m_SelectedBundles.size()<2 ){ QMessageBox::information( NULL, "Warning", "Select at least two fiber bundles!"); MITK_WARN("QmitkFiberProcessingView") << "Select at least two fiber bundles!"; return; } std::vector::const_iterator it = m_SelectedBundles.begin(); mitk::FiberBundleX::Pointer newBundle = dynamic_cast((*it)->GetData()); QString name(""); name += QString((*it)->GetName().c_str()); ++it; for (it; it!=m_SelectedBundles.end(); ++it) { newBundle = newBundle->AddBundle(dynamic_cast((*it)->GetData())); name += "+"+QString((*it)->GetName().c_str()); } mitk::DataNode::Pointer fbNode = mitk::DataNode::New(); fbNode->SetData(newBundle); fbNode->SetName(name.toStdString()); fbNode->SetVisibility(true); GetDataStorage()->Add(fbNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkFiberfoxView::UpdateGui() { m_Controls->m_FiberBundleLabel->setText("mandatory"); m_Controls->m_GeometryFrame->setEnabled(true); m_Controls->m_GeometryMessage->setVisible(false); m_Controls->m_DiffusionPropsMessage->setVisible(false); m_Controls->m_FiberGenMessage->setVisible(true); m_Controls->m_TransformBundlesButton->setEnabled(false); m_Controls->m_CopyBundlesButton->setEnabled(false); m_Controls->m_GenerateFibersButton->setEnabled(false); m_Controls->m_FlipButton->setEnabled(false); m_Controls->m_CircleButton->setEnabled(false); m_Controls->m_BvalueBox->setEnabled(true); m_Controls->m_NumGradientsBox->setEnabled(true); m_Controls->m_JoinBundlesButton->setEnabled(false); m_Controls->m_AlignOnGrid->setEnabled(false); if (m_SelectedFiducial.IsNotNull()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_FlipButton->setEnabled(true); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_SelectedImage.IsNotNull() || !m_SelectedBundles.empty()) { m_Controls->m_TransformBundlesButton->setEnabled(true); m_Controls->m_CircleButton->setEnabled(true); m_Controls->m_FiberGenMessage->setVisible(false); m_Controls->m_AlignOnGrid->setEnabled(true); } if (m_TissueMask.IsNotNull() || m_SelectedImage.IsNotNull()) { m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (m_SelectedDWI.IsNotNull()) { m_Controls->m_DiffusionPropsMessage->setVisible(true); m_Controls->m_BvalueBox->setEnabled(false); m_Controls->m_NumGradientsBox->setEnabled(false); m_Controls->m_GeometryMessage->setVisible(true); m_Controls->m_GeometryFrame->setEnabled(false); } if (!m_SelectedBundles.empty()) { m_Controls->m_CopyBundlesButton->setEnabled(true); m_Controls->m_GenerateFibersButton->setEnabled(true); m_Controls->m_FiberBundleLabel->setText(m_SelectedBundles.at(0)->GetName().c_str()); if (m_SelectedBundles.size()>1) m_Controls->m_JoinBundlesButton->setEnabled(true); } } void QmitkFiberfoxView::OnSelectionChanged( berry::IWorkbenchPart::Pointer, const QList& nodes ) { m_SelectedBundles2.clear(); m_SelectedImages.clear(); m_SelectedFiducials.clear(); m_SelectedFiducial = NULL; m_TissueMask = NULL; m_SelectedBundles.clear(); m_SelectedImage = NULL; m_SelectedDWI = NULL; m_Controls->m_TissueMaskLabel->setText("optional"); // iterate all selected objects, adjust warning visibility for( int i=0; i*>(node->GetData()) ) { m_SelectedDWI = node; m_SelectedImage = node; m_SelectedImages.push_back(node); } else if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedImages.push_back(node); m_SelectedImage = node; bool isBinary = false; node->GetPropertyValue("binary", isBinary); if (isBinary) { m_TissueMask = dynamic_cast(node->GetData()); m_Controls->m_TissueMaskLabel->setText(node->GetName().c_str()); } } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedBundles2.push_back(node); if (m_Controls->m_RealTimeFibers->isChecked()) { m_SelectedBundles.push_back(node); mitk::FiberBundleX::Pointer newFib = dynamic_cast(node->GetData()); if (newFib->GetNumFibers()!=m_Controls->m_FiberDensityBox->value()) GenerateFibers(); } else m_SelectedBundles.push_back(node); } else if ( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_SelectedFiducials.push_back(node); m_SelectedFiducial = node; m_SelectedBundles.clear(); mitk::DataStorage::SetOfObjects::ConstPointer parents = GetDataStorage()->GetSources(node); for( mitk::DataStorage::SetOfObjects::const_iterator it = parents->begin(); it != parents->end(); ++it ) { mitk::DataNode::Pointer pNode = *it; if ( pNode.IsNotNull() && dynamic_cast(pNode->GetData()) ) m_SelectedBundles.push_back(pNode); } } } UpdateGui(); } void QmitkFiberfoxView::EnableCrosshairNavigation() { MITK_DEBUG << "EnableCrosshairNavigation"; // enable the crosshair navigation if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "enabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(true); // linkedRenderWindow->EnableSlicingPlanes(true); } if (m_Controls->m_RealTimeFibers->isChecked()) GenerateFibers(); } void QmitkFiberfoxView::DisableCrosshairNavigation() { MITK_DEBUG << "DisableCrosshairNavigation"; // disable the crosshair navigation during the drawing if (mitk::ILinkedRenderWindowPart* linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart())) { MITK_DEBUG << "disabling linked navigation"; linkedRenderWindow->EnableLinkedNavigation(false); // linkedRenderWindow->EnableSlicingPlanes(false); } } void QmitkFiberfoxView::NodeRemoved(const mitk::DataNode* node) { mitk::DataNode* nonConstNode = const_cast(node); std::map::iterator it = m_DataNodeToPlanarFigureData.find(nonConstNode); if( it != m_DataNodeToPlanarFigureData.end() ) { QmitkPlanarFigureData& data = it->second; // remove observers 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 ); m_DataNodeToPlanarFigureData.erase( it ); } } void QmitkFiberfoxView::NodeAdded( const mitk::DataNode* node ) { // add observer for selection in renderwindow mitk::PlanarFigure* figure = dynamic_cast(node->GetData()); bool isPositionMarker (false); node->GetBoolProperty("isContourMarker", isPositionMarker); if( figure && !isPositionMarker ) { MITK_DEBUG << "figure added. will add interactor if needed."; mitk::PlanarFigureInteractor::Pointer figureInteractor = dynamic_cast(node->GetInteractor()); mitk::DataNode* nonConstNode = const_cast( node ); if(figureInteractor.IsNull()) { figureInteractor = mitk::PlanarFigureInteractor::New("PlanarFigureInteractor", nonConstNode); } else { // just to be sure that the interactor is not added twice mitk::GlobalInteraction::GetInstance()->RemoveInteractor(figureInteractor); } MITK_DEBUG << "adding interactor to globalinteraction"; mitk::GlobalInteraction::GetInstance()->AddInteractor(figureInteractor); MITK_DEBUG << "will now add observers for planarfigure"; QmitkPlanarFigureData data; data.m_Figure = figure; // // add observer for event when figure has been placed typedef itk::SimpleMemberCommand< QmitkFiberfoxView > SimpleCommandType; // SimpleCommandType::Pointer initializationCommand = SimpleCommandType::New(); // initializationCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureInitialized ); // data.m_EndPlacementObserverTag = figure->AddObserver( mitk::EndPlacementPlanarFigureEvent(), initializationCommand ); // add observer for event when figure is picked (selected) typedef itk::MemberCommand< QmitkFiberfoxView > MemberCommandType; MemberCommandType::Pointer selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction( this, &QmitkFiberfoxView::PlanarFigureSelected ); data.m_SelectObserverTag = figure->AddObserver( mitk::SelectPlanarFigureEvent(), selectCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer startInteractionCommand = SimpleCommandType::New(); startInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::DisableCrosshairNavigation); data.m_StartInteractionObserverTag = figure->AddObserver( mitk::StartInteractionPlanarFigureEvent(), startInteractionCommand ); // add observer for event when interaction with figure starts SimpleCommandType::Pointer endInteractionCommand = SimpleCommandType::New(); endInteractionCommand->SetCallbackFunction( this, &QmitkFiberfoxView::EnableCrosshairNavigation); data.m_EndInteractionObserverTag = figure->AddObserver( mitk::EndInteractionPlanarFigureEvent(), endInteractionCommand ); m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkFiberfoxView::PlanarFigureSelected( itk::Object* object, const itk::EventObject& ) { mitk::TNodePredicateDataType::Pointer isPf = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allPfs = this->GetDataStorage()->GetSubset( isPf ); for ( mitk::DataStorage::SetOfObjects::const_iterator it = allPfs->begin(); it!=allPfs->end(); ++it) { mitk::DataNode* node = *it; if( node->GetData() == object ) { node->SetSelected(true); m_SelectedFiducial = node; } else node->SetSelected(false); } UpdateGui(); this->RequestRenderWindowUpdate(); } void QmitkFiberfoxView::SetFocus() { m_Controls->m_CircleButton->setFocus(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h index 472cec2de2..311b7ef92d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxView.h @@ -1,137 +1,141 @@ /*=================================================================== 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 "ui_QmitkFiberfoxViewControls.h" #include #include #include #include #include /*! \brief View for fiber based diffusion software phantoms (Fiberfox). \sa QmitkFunctionality \ingroup Functionalities */ // Forward Qt class declarations using namespace std; class QmitkFiberfoxView : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const string VIEW_ID; QmitkFiberfoxView(); virtual ~QmitkFiberfoxView(); virtual void CreateQtPartControl(QWidget *parent); void SetFocus(); + typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkUcharImgType; typedef itk::Vector GradientType; typedef vector GradientListType; template vector > MakeGradientList() ; protected slots: void OnDrawROI(); ///< adds new ROI, handles interactors etc. void OnAddBundle(); ///< adds new fiber bundle to datastorage void OnFlipButton(); ///< negate one coordinate of the fiber waypoints in the selcted planar figure. needed in case of unresolvable twists void GenerateFibers(); ///< generate fibers from the selected ROIs void GenerateImage(); ///< generate artificial image from the selected fiber bundle void JoinBundles(); ///< merges selcted fiber bundles into one void CopyBundles(); ///< add copy of the selected bundle to the datamanager void ApplyTransform(); ///< rotate and shift selected bundles void AlignOnGrid(); ///< shift selected fiducials to nearest voxel center void Comp1ModelFrameVisibility(int index);///< only show parameters of selected fiber model type void Comp2ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type void Comp3ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type void Comp4ModelFrameVisibility(int index);///< only show parameters of selected non-fiber model type void ShowAdvancedOptions(int state); /** update fibers if any parameter changes */ void OnFiberDensityChanged(int value); void OnFiberSamplingChanged(int value); void OnTensionChanged(double value); void OnContinuityChanged(double value); void OnBiasChanged(double value); void OnVarianceChanged(double value); void OnDistributionChanged(int value); void OnAddGibbsRinging(int value); + void OnAddNoise(int value); + void OnAddGhosts(int value); + void OnAddDistortions(int value); void OnConstantRadius(int value); protected: /// \brief called by QmitkFunctionality when DataManager's selection has changed virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList&); GradientListType GenerateHalfShell(int NPoints); ///< generate vectors distributed over the halfsphere Ui::QmitkFiberfoxViewControls* m_Controls; void UpdateGui(); ///< enable/disbale buttons etc. according to current datamanager selection void PlanarFigureSelected( itk::Object* object, const itk::EventObject& ); void EnableCrosshairNavigation(); ///< enable crosshair navigation if planar figure interaction ends void DisableCrosshairNavigation(); ///< disable crosshair navigation if planar figure interaction starts void NodeAdded( const mitk::DataNode* node ); ///< add observers void NodeRemoved(const mitk::DataNode* node); ///< remove observers /** structure to keep track of planar figures and observers */ struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_Figure(0) , m_EndPlacementObserverTag(0) , m_SelectObserverTag(0) , m_StartInteractionObserverTag(0) , m_EndInteractionObserverTag(0) , m_Flipped(0) { } mitk::PlanarFigure* m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; unsigned int m_Flipped; }; std::map m_DataNodeToPlanarFigureData; ///< map each planar figure uniquely to a QmitkPlanarFigureData mitk::Image::Pointer m_TissueMask; ///< mask defining which regions of the image should contain signal and which are containing only noise mitk::DataNode::Pointer m_SelectedFiducial; ///< selected planar ellipse mitk::DataNode::Pointer m_SelectedImage; mitk::DataNode::Pointer m_SelectedDWI; vector< mitk::DataNode::Pointer > m_SelectedBundles; vector< mitk::DataNode::Pointer > m_SelectedBundles2; vector< mitk::DataNode::Pointer > m_SelectedFiducials; vector< mitk::DataNode::Pointer > m_SelectedImages; }; diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui index f45819d6b4..6daeb16abe 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkFiberfoxViewControls.ui @@ -1,2020 +1,2140 @@ QmitkFiberfoxViewControls 0 0 493 - 1438 + 1482 Form 0 Fiber Definition Qt::Vertical 20 40 color: rgb(255, 0, 0); Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true Fiducial Options All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. Align With Grid Operations false Copy Bundles false Transform Selection QFrame::NoFrame QFrame::Raised 0 Y false Rotation angle (in degree) around x-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Axis: false Rotation angle (in degree) around y-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation: false Translation (in mm) in direction of the z-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 X false Rotation: false Z false Rotation angle (in degree) around z-axis. -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. -1000.000000000000000 1000.000000000000000 0.100000000000000 Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false Join Bundles If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true Fiber Options QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 Tension: false Fiber Sampling: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Fiber sampling points (per cm) 1 100 1 10 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Bias: false Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised 0 6 #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false Generate Fibers QFrame::NoFrame QFrame::Raised 0 Select fiber distribution inside of the fiducials. Uniform Gaussian Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 false 30 30 Draw elliptical fiducial. :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. :/QmitkDiffusionImaging/refresh.xpm:/QmitkDiffusionImaging/refresh.xpm 32 32 false true Qt::Horizontal 40 20 Signal Generation Intra-axonal Compartment Select signal model for intra-axonal compartment. Stick Model Zeppelin Model Tensor Model Data Fiber Bundle: false <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Tissue Mask: false <html><head/><body><p><span style=" color:#969696;">optional</span></p></body></html> true Extra-axonal Compartments Select signal model for extra-axonal compartment. Ball Model Astrosticks Model Dot Model Select signal model for extra-axonal compartment. -- Ball Model Astrosticks Model Dot Model Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 Weighting factor between the two extra-axonal compartments. 1.000000000000000 0.100000000000000 0.300000000000000 Compartment Fraction: true Start DWI generation from selected fiebr bundle. If no fiber bundle is selected, a grayscale image containing a simple gradient is generated. Generate Image Image Settings QFrame::NoFrame QFrame::Raised 0 6 <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> false Output k-Space Image false Large values shrink (towards nearest neighbour interpolation), small values strech interpolation function (towards linear interpolation). 1 10000 10 T2* relaxation time (in milliseconds). 100.000000000000000 0.100000000000000 1.000000000000000 Treat voxel content as fiber-only if at least one fiber is present. Enforce Pure Fiber Voxels false TE in milliseconds 1 10000 1 100 Fiber Radius: Interpolation Shrink: Repetitions: <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> false Line Readout Time: false Number of signal averages. Increase to reduce noise. 1 100 1 1 Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). 1 10000 1 50 Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. 0 1000 0 Signal Scale: TE in milliseconds 1 10000 1 125 color: rgb(255, 0, 0); Using geometry of selected image! color: rgb(255, 0, 0); Using gradients of selected DWI! QFrame::NoFrame QFrame::Raised 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 11 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 11 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 3 QFrame::NoFrame QFrame::Raised 0 6 Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 30 b-Value: false b-value in mm/s² 0 10000 100 1000 Advanced Options Qt::Vertical 20 40 Noise and Artifacts - - + + true QFrame::NoFrame QFrame::Raised 6 0 k-Space Undersampling: false Image is upsampled using this factor, afterwards fourier transformed, cropped to the original size and then inverse fourier transformed. 0 2 4 8 16 32 64 128 256 - - - - true + + + + Add Distortions - - QFrame::NoFrame + + false - - QFrame::Raised + + + + + + Add Gibbs Ringing + + + false + + + + + + + Add Rician Noise + + + true - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 - - - 0 - - - 0 - - - + QFrame::NoFrame QFrame::Raised 0 Variance: Variance of Rician noise model. 4 0.000000000000000 100000.000000000000000 0.001000000000000 25.000000000000000 - + - Add Gibbs Ringing + Add N/2 Ghosts false + + + + true + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + + + + + + + + + + + + K-Space Line Offset: + + + false + + + + + + + A larger offset increases the inensity of the ghost image. + + + 3 + + + 1.000000000000000 + + + 0.010000000000000 + + + 0.100000000000000 + + + + + + + + + + true + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + + + + + + + + + + + + Frequency Map: + + + false + + + + + + + Select image specifying the frequency inhomogeneities (in Hz). + + + + + + Inter-axonal Compartment Select signal model for intra-axonal compartment. -- Stick Model Zeppelin Model Tensor Model QmitkTensorModelParametersWidget QWidget
QmitkTensorModelParametersWidget.h
1
QmitkStickModelParametersWidget QWidget
QmitkStickModelParametersWidget.h
1
QmitkZeppelinModelParametersWidget QWidget
QmitkZeppelinModelParametersWidget.h
1
QmitkBallModelParametersWidget QWidget
QmitkBallModelParametersWidget.h
1
QmitkAstrosticksModelParametersWidget QWidget
QmitkAstrosticksModelParametersWidget.h
1
QmitkDotModelParametersWidget QWidget
QmitkDotModelParametersWidget.h
1
+ + QmitkDataStorageComboBox + QComboBox +
QmitkDataStorageComboBox.h
+
- tabWidget m_CircleButton m_FlipButton m_RealTimeFibers - m_DistributionBox m_AdvancedOptionsBox + m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_GenerateImageButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_AdvancedOptionsBox_2 m_RepetitionsBox + m_SignalScaleBox m_TEbox m_LineReadoutTimeBox m_T2starBox m_FiberRadius m_InterpolationShrink m_EnforcePureFiberVoxelsBox m_KspaceImageBox m_Compartment1Box m_Compartment2Box m_Compartment3Box m_Compartment4Box m_Comp4FractionBox + m_AddNoise m_NoiseLevel + m_AddGhosts + m_kOffsetBox + m_AddDistortions + m_FrequencyMapBox m_AddGibbsRinging m_KspaceUndersamplingBox + tabWidget
diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/MitkDiffusionImagingAppQtHelpCollectionProject.qhcp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/MitkDiffusionImagingAppQtHelpCollectionProject.qhcp index a9a39d92fe..ebd648576d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/MitkDiffusionImagingAppQtHelpCollectionProject.qhcp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/documentation/MitkDiffusionImagingAppQtHelpCollectionProject.qhcp @@ -1,22 +1,22 @@ MITK Diffusion Help - assistant-logo.png + assistant-logo.png qthelp://org.mitk.gui.qt.diffusionimagingapp/bundle/index.html - assistant-icon.png + assistant-icon.png false false true MitkDIApp About MITK Diffusion Help - - about-logo.png - + + about-logo.png + - + diff --git a/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/MitkDTIAtlasAppQtHelpCollectionProject.qhcp b/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/MitkDTIAtlasAppQtHelpCollectionProject.qhcp index fa48318c3b..121bb95921 100644 --- a/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/MitkDTIAtlasAppQtHelpCollectionProject.qhcp +++ b/Plugins/org.mitk.gui.qt.dtiatlasapp/documentation/MitkDTIAtlasAppQtHelpCollectionProject.qhcp @@ -1,22 +1,22 @@ MITK 3M3 Help - assistant-logo.png + assistant-logo.png qthelp://org.mitk.gui.qt.dtiatlasapp/bundle/index.html - assistant-icon.png + assistant-icon.png false false true Mitk3M3 About MITK 3M3 Help - - about-logo.png - + + about-logo.png + - + diff --git a/Plugins/org.mitk.gui.qt.properties/CMakeLists.txt b/Plugins/org.mitk.gui.qt.properties/CMakeLists.txt new file mode 100644 index 0000000000..edf096cfa2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_properties) + +MACRO_CREATE_MITK_CTK_PLUGIN( + EXPORT_DIRECTIVE PROPERTIES_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDENCIES Properties QmitkExt +) diff --git a/Plugins/org.mitk.gui.qt.properties/files.cmake b/Plugins/org.mitk.gui.qt.properties/files.cmake new file mode 100644 index 0000000000..6a61ba0288 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/files.cmake @@ -0,0 +1,45 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_properties_Activator.cpp + QmitkPropertiesPreferencePage.cpp + QmitkPropertyItemDelegate.cpp + QmitkPropertyItem.cpp + QmitkPropertyItemModel.cpp + QmitkPropertyItemSortFilterProxyModel.cpp + QmitkPropertyTreeView.cpp +) + +set(UI_FILES + src/internal/QmitkPropertiesPreferencePage.ui + src/internal/QmitkPropertyTreeView.ui +) + +set(MOC_H_FILES + src/internal/QmitkPropertiesPreferencePage.h + src/internal/org_mitk_gui_qt_properties_Activator.h + src/internal/QmitkPropertyItemDelegate.h + src/internal/QmitkPropertyItemModel.h + src/internal/QmitkPropertyItemSortFilterProxyModel.h + src/internal/QmitkPropertyTreeView.h +) + +set(CACHED_RESOURCE_FILES + resources/icon.png + plugin.xml +) + +set(QRC_FILES +) + +set(CPP_FILES +) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach() + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach() diff --git a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.properties/manifest_headers.cmake similarity index 83% copy from Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake copy to Plugins/org.mitk.gui.qt.properties/manifest_headers.cmake index 912e7b0cf4..49a9ff6bc5 100644 --- a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.properties/manifest_headers.cmake @@ -1,5 +1,5 @@ -set(Plugin-Name "MITK Simulation") +set(Plugin-Name "MITK Properties") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.properties/plugin.xml b/Plugins/org.mitk.gui.qt.properties/plugin.xml new file mode 100644 index 0000000000..961cb29811 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/plugin.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.properties/resources/icon.png b/Plugins/org.mitk.gui.qt.properties/resources/icon.png new file mode 100644 index 0000000000..0a55fbdd74 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.properties/resources/icon.png differ diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.cpp new file mode 100644 index 0000000000..8da2375f20 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.cpp @@ -0,0 +1,79 @@ +/*=================================================================== + +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 "QmitkPropertiesPreferencePage.h" +#include + +const std::string QmitkPropertiesPreferencePage::FILTER_PROPERTIES = "filter properties"; +const std::string QmitkPropertiesPreferencePage::SHOW_ALIASES = "show aliases"; +const std::string QmitkPropertiesPreferencePage::SHOW_DESCRIPTIONS = "show descriptions"; +const std::string QmitkPropertiesPreferencePage::SHOW_GENUINE_NAMES = "show genuine names"; + +QmitkPropertiesPreferencePage::QmitkPropertiesPreferencePage() + : m_Control(NULL), + m_Preferences(berry::Platform::GetServiceRegistry().GetServiceById(berry::IPreferencesService::ID)->GetSystemPreferences()->Node("/org.mitk.views.properties")) +{ +} + +QmitkPropertiesPreferencePage::~QmitkPropertiesPreferencePage() +{ +} + +void QmitkPropertiesPreferencePage::CreateQtControl(QWidget* parent) +{ + m_Control = new QWidget(parent); + m_Controls.setupUi(m_Control); + + connect(m_Controls.showDescriptionsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnShowDescriptionsStateChanged(int))); + + this->Update(); +} + +QWidget* QmitkPropertiesPreferencePage::GetQtControl() const +{ + return m_Control; +} + +void QmitkPropertiesPreferencePage::Init(berry::IWorkbench::Pointer) +{ +} + +void QmitkPropertiesPreferencePage::OnShowDescriptionsStateChanged(int state) +{ + m_Controls.showGenuineNamesCheckBox->setEnabled(state != Qt::Unchecked); +} + +bool QmitkPropertiesPreferencePage::PerformOk() +{ + m_Preferences->PutBool(FILTER_PROPERTIES, m_Controls.filterPropertiesCheckBox->isChecked()); + m_Preferences->PutBool(SHOW_ALIASES, m_Controls.showAliasesCheckBox->isChecked()); + m_Preferences->PutBool(SHOW_DESCRIPTIONS, m_Controls.showDescriptionsCheckBox->isChecked()); + m_Preferences->PutBool(SHOW_GENUINE_NAMES, m_Controls.showGenuineNamesCheckBox->isChecked()); + + return true; +} + +void QmitkPropertiesPreferencePage::PerformCancel() +{ +} + +void QmitkPropertiesPreferencePage::Update() +{ + m_Controls.filterPropertiesCheckBox->setChecked(m_Preferences->GetBool(FILTER_PROPERTIES, true)); + m_Controls.showAliasesCheckBox->setChecked(m_Preferences->GetBool(SHOW_ALIASES, true)); + m_Controls.showDescriptionsCheckBox->setChecked(m_Preferences->GetBool(SHOW_DESCRIPTIONS, true)); + m_Controls.showGenuineNamesCheckBox->setChecked(m_Preferences->GetBool(SHOW_GENUINE_NAMES, true)); +} diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.h similarity index 54% copy from Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h copy to Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.h index 484c855305..79f53b3b35 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.h @@ -1,57 +1,53 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QmitkSimulationPreferencePage_h -#define QmitkSimulationPreferencePage_h +#ifndef QmitkPropertiesPreferencePage_h +#define QmitkPropertiesPreferencePage_h #include -#include -#include -#include +#include -berry::IPreferences::Pointer getSimulationPreferences(); -void initSOFAPlugins(berry::IPreferences::Pointer preferences = getSimulationPreferences()); - -class SIMULATION_EXPORT QmitkSimulationPreferencePage : public QObject, public berry::IQtPreferencePage +class QmitkPropertiesPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: - static const std::string PLUGIN_PATHS; + static const std::string FILTER_PROPERTIES; + static const std::string SHOW_ALIASES; + static const std::string SHOW_DESCRIPTIONS; + static const std::string SHOW_GENUINE_NAMES; - QmitkSimulationPreferencePage(); - ~QmitkSimulationPreferencePage(); + QmitkPropertiesPreferencePage(); + ~QmitkPropertiesPreferencePage(); void CreateQtControl(QWidget* parent); QWidget* GetQtControl() const; void Init(berry::IWorkbench::Pointer workbench); - void PerformCancel(); bool PerformOk(); + void PerformCancel(); void Update(); private slots: - void OnAddButtonClicked(); - void OnPluginTreeWidgetItemSelectionChanged(); - void OnRemoveButtonClicked(); + void OnShowDescriptionsStateChanged(int state); private: - berry::IPreferences::Pointer m_Preferences; QWidget* m_Control; - Ui::QmitkSimulationPreferencePageControls m_Controls; + Ui::QmitkPropertiesPreferencePage m_Controls; + berry::IPreferences::Pointer m_Preferences; }; #endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.ui b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.ui new file mode 100644 index 0000000000..a9a1783f30 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertiesPreferencePage.ui @@ -0,0 +1,109 @@ + + + QmitkPropertiesPreferencePage + + + + 0 + 0 + 400 + 300 + + + + + + + + + + Aliases + + + + + + Replace genuine property names by aliases + + + true + + + + + + + + + + Descriptions + + + + + + Show descriptions + + + true + + + + + + + margin-left: 18px; + + + Show genuine names of property aliases + + + true + + + + + + + + + + Filters + + + + + + Only show filtered properties + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 204 + + + + + + + + showAliasesCheckBox + showDescriptionsCheckBox + showGenuineNamesCheckBox + + + + diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.cpp new file mode 100644 index 0000000000..b6382bf1ef --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.cpp @@ -0,0 +1,124 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkPropertyItem.h" +#include + +QmitkPropertyItem::QmitkPropertyItem(const QList& data) + : m_Data(data), + m_Parent(NULL) +{ +} + +QmitkPropertyItem::~QmitkPropertyItem() +{ + qDeleteAll(m_Children); +} + +void QmitkPropertyItem::AppendChild(QmitkPropertyItem* child) +{ + if (child == NULL) + return; + + // If property name doesn't contain full stop(s), append property directly. + if (!child->GetData(0).toString().contains('.')) + { + m_Children.append(child); + child->m_Parent = this; + } + else + { + // Property name contains full stop(s). Split accordingly. + QStringList names = child->GetData(0).toString().split('.'); + + // Traverse subtree and insert nodes if not already present. + QmitkPropertyItem* currentParent = this; + + for (int i = 0; i < names.count(); ++i) + { + if (i != names.count() - 1) + { + QmitkPropertyItem* currentChild = NULL; + + // Search for current node. + for (int j = 0; j < currentParent->m_Children.count(); ++j) + { + if (currentParent->m_Children[j]->GetData(0).toString() == names[i]) + { + currentChild = currentParent->m_Children[j]; + break; + } + } + + // Node doesn't exist. Create and append it. + if (currentChild == NULL) + { + QList data; + data << names[i] << QVariant(); + + currentChild = new QmitkPropertyItem(data); + currentParent->AppendChild(currentChild); + } + + currentParent = currentChild; + } + else + { + // Subtree already present, append property as leaf node. + QList data; + data << names[i] << child->m_Data[1]; + + currentParent->AppendChild(new QmitkPropertyItem(data)); + + delete child; + child = NULL; + } + } + } +} + +QmitkPropertyItem* QmitkPropertyItem::GetChild(int row) const +{ + return m_Children.value(row); +} + +int QmitkPropertyItem::GetChildCount() const +{ + return m_Children.count(); +} + +int QmitkPropertyItem::GetColumnCount() const +{ + return m_Data.count(); +} + +QVariant QmitkPropertyItem::GetData(int column) const +{ + return m_Data.value(column); +} + +QmitkPropertyItem* QmitkPropertyItem::GetParent() const +{ + return m_Parent; +} + +int QmitkPropertyItem::GetRow() +{ + if (m_Parent != NULL) + return m_Parent->m_Children.indexOf(this); + + return 0; +} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.h similarity index 58% rename from Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.h rename to Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.h index 7d47c33b9f..905a1d11ec 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeItem.h +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItem.h @@ -1,43 +1,46 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKPROPERTYTREEITEM_H -#define QMITKPROPERTYTREEITEM_H +#ifndef QmitkPropertyItem_h +#define QmitkPropertyItem_h #include #include -class QmitkPropertyTreeItem +class QmitkPropertyItem { public: - explicit QmitkPropertyTreeItem(const QList &data); - ~QmitkPropertyTreeItem(); + explicit QmitkPropertyItem(const QList& data); + ~QmitkPropertyItem(); - void AppendChild(QmitkPropertyTreeItem *child); - QmitkPropertyTreeItem * GetChild(int row); + void AppendChild(QmitkPropertyItem* child); + QmitkPropertyItem* GetChild(int row) const; int GetChildCount() const; int GetColumnCount() const; QVariant GetData(int column) const; - QmitkPropertyTreeItem * GetParent(); - int GetRow() const; + QmitkPropertyItem* GetParent() const; + int GetRow(); private: - QList m_Children; + QmitkPropertyItem(const QmitkPropertyItem&); + QmitkPropertyItem& operator=(const QmitkPropertyItem&); + QList m_Data; - QmitkPropertyTreeItem *m_Parent; + QList m_Children; + QmitkPropertyItem* m_Parent; }; #endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.cpp new file mode 100644 index 0000000000..266f836828 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.cpp @@ -0,0 +1,172 @@ +/*=================================================================== + +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 "QmitkPropertyItemDelegate.h" +#include +#include +#include +#include + +static mitk::BaseProperty* GetBaseProperty(const QVariant& data) +{ + return data.isValid() + ? reinterpret_cast(data.value()) + : NULL; +} + +QmitkPropertyItemDelegate::QmitkPropertyItemDelegate(QObject* parent) + : QStyledItemDelegate(parent) +{ +} + +QmitkPropertyItemDelegate::~QmitkPropertyItemDelegate() +{ +} + +QWidget* QmitkPropertyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QVariant data = index.data(Qt::EditRole); + + if (data.isValid()) + { + if (data.type() == QVariant::Int) + { + QSpinBox* spinBox = new QSpinBox(parent); + + connect(spinBox, SIGNAL(editingFinished()), this, SLOT(OnSpinBoxEditingFinished())); + + return spinBox; + } + + if (data.type() == QVariant::Double || static_cast(data.type()) == QMetaType::Float) + { + QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent); + + spinBox->setDecimals(4); + spinBox->setSingleStep(0.1); + + QString name = index.model()->data(index.model()->index(index.row(), index.column() - 1)).toString(); + + if (name == "opacity") + { + spinBox->setMinimum(0.0); + spinBox->setMaximum(1.0); + } + + connect(spinBox, SIGNAL(editingFinished()), this, SLOT(OnSpinBoxEditingFinished())); + + return spinBox; + } + + if (data.type() == QVariant::StringList) + { + QComboBox* comboBox = new QComboBox(parent); + + comboBox->addItems(data.toStringList()); + + connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnComboBoxCurrentIndexChanged(int))); + + return comboBox; + } + } + + return QStyledItemDelegate::createEditor(parent, option, index); +} + +void QmitkPropertyItemDelegate::OnComboBoxCurrentIndexChanged(int) +{ + QComboBox* comboBox = qobject_cast(sender()); + + emit commitData(comboBox); + emit closeEditor(comboBox); +} + +void QmitkPropertyItemDelegate::OnSpinBoxEditingFinished() +{ + QAbstractSpinBox* spinBox = qobject_cast(sender()); + + emit commitData(spinBox); + emit closeEditor(spinBox); +} + +void QmitkPropertyItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + QVariant data = index.data(); + + if (index.column() == 1 && data.type() == QVariant::Color) + { + painter->fillRect(option.rect, data.value()); + return; + } + + QStyledItemDelegate::paint(painter, option, index); +} + +void QmitkPropertyItemDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + QVariant data = index.data(Qt::EditRole); + + if (!data.isValid()) + return; + + if (data.type() == QVariant::StringList) + { + QComboBox* comboBox = qobject_cast(editor); + comboBox->setCurrentIndex(comboBox->findText(index.data().toString())); + } + else + { + QStyledItemDelegate::setEditorData(editor, index); + } +} + +void QmitkPropertyItemDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const +{ + QVariant data = index.data(Qt::EditRole); + + if (!data.isValid()) + return; + + if (data.type() == QVariant::Int) + { + QSpinBox* spinBox = qobject_cast(editor); + model->setData(index, spinBox->value()); + } + else if (data.type() == QVariant::Double) + { + QDoubleSpinBox* spinBox = qobject_cast(editor); + model->setData(index, spinBox->value()); + } + else if (static_cast(data.type()) == QMetaType::Float) + { + QDoubleSpinBox* spinBox = qobject_cast(editor); + model->setData(index, static_cast(spinBox->value())); + } + else if (data.type() == QVariant::StringList) + { + QComboBox* comboBox = qobject_cast(editor); + model->setData(index, comboBox->currentText()); + } + else + { + QStyledItemDelegate::setModelData(editor, model, index); + } +} + +QSize QmitkPropertyItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + return QStyledItemDelegate::sizeHint(option, index); +} diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.h new file mode 100644 index 0000000000..a66796c1ae --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemDelegate.h @@ -0,0 +1,41 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkPropertyItemDelegate_h +#define QmitkPropertyItemDelegate_h + +#include + +class QmitkPropertyItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit QmitkPropertyItemDelegate(QObject* parent = NULL); + ~QmitkPropertyItemDelegate(); + + QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; + void setEditorData(QWidget* editor, const QModelIndex& index) const; + void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + +private slots: + void OnComboBoxCurrentIndexChanged(int index); + void OnSpinBoxEditingFinished(); +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.cpp new file mode 100644 index 0000000000..463b5f89dc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.cpp @@ -0,0 +1,498 @@ +/*=================================================================== + +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 "mitkGetPropertyService.h" +#include "QmitkPropertiesPreferencePage.h" +#include "QmitkPropertyItem.h" +#include "QmitkPropertyItemModel.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static QColor MitkToQt(const mitk::Color &color) +{ + return QColor(color.GetRed() * 255, color.GetGreen() * 255, color.GetBlue() * 255); +} + +static mitk::BaseProperty* GetBaseProperty(const QVariant& data) +{ + return data.isValid() + ? reinterpret_cast(data.value()) + : NULL; +} + +static mitk::Color QtToMitk(const QColor &color) +{ + mitk::Color mitkColor; + + mitkColor.SetRed(color.red() / 255.0f); + mitkColor.SetGreen(color.green() / 255.0f); + mitkColor.SetBlue(color.blue() / 255.0f); + + return mitkColor; +} + +class PropertyEqualTo +{ +public: + PropertyEqualTo(const mitk::BaseProperty* property) + : m_Property(property) + { + } + + bool operator()(const mitk::PropertyList::PropertyMapElementType& pair) const + { + return pair.second.GetPointer() == m_Property; + } + +private: + const mitk::BaseProperty* m_Property; +}; + +QmitkPropertyItemModel::QmitkPropertyItemModel(QObject* parent) + : QAbstractItemModel(parent), + m_PropertyAliases(NULL), + m_PropertyFilters(NULL) +{ + this->CreateRootItem(); +} + +QmitkPropertyItemModel::~QmitkPropertyItemModel() +{ + this->SetNewPropertyList(NULL); +} + +int QmitkPropertyItemModel::columnCount(const QModelIndex& parent) const +{ + if (parent.isValid()) + return static_cast(parent.internalPointer())->GetColumnCount(); + else + return m_RootItem->GetColumnCount(); +} + +void QmitkPropertyItemModel::CreateRootItem() +{ + QList rootData; + rootData << "Property" << "Value"; + + m_RootItem.reset(new QmitkPropertyItem(rootData)); + + this->reset(); +} + +QVariant QmitkPropertyItemModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + mitk::BaseProperty* property = index.column() == 1 + ? GetBaseProperty(static_cast(index.internalPointer())->GetData(1)) + : NULL; + + if (role == Qt::DisplayRole) + { + if (index.column() == 0) + { + return static_cast(index.internalPointer())->GetData(0); + } + else if (index.column() == 1 && property != NULL) + { + if (mitk::ColorProperty* colorProperty = dynamic_cast(property)) + return MitkToQt(colorProperty->GetValue()); + else if (dynamic_cast(property) == NULL) + return QString::fromStdString(property->GetValueAsString()); + } + } + else if (index.column() == 1 && property != NULL) + { + if (role == Qt::CheckStateRole) + { + if (mitk::BoolProperty* boolProperty = dynamic_cast(property)) + return boolProperty->GetValue() ? Qt::Checked : Qt::Unchecked; + } + else if (role == Qt::EditRole) + { + if (dynamic_cast(property) != NULL) + { + return QString::fromStdString(property->GetValueAsString()); + } + else if (mitk::IntProperty* intProperty = dynamic_cast(property)) + { + return intProperty->GetValue(); + } + else if (mitk::FloatProperty* floatProperty = dynamic_cast(property)) + { + return floatProperty->GetValue(); + } + else if (mitk::DoubleProperty* doubleProperty = dynamic_cast(property)) + { + return doubleProperty->GetValue(); + } + else if (mitk::EnumerationProperty* enumProperty = dynamic_cast(property)) + { + QStringList values; + + for (mitk::EnumerationProperty::EnumConstIterator it = enumProperty->Begin(); it != enumProperty->End(); it++) + values << QString::fromStdString(it->second); + + return values; + } + else if (mitk::ColorProperty* colorProperty = dynamic_cast(property)) + { + return MitkToQt(colorProperty->GetValue()); + } + } + } + + return QVariant(); +} + +QModelIndex QmitkPropertyItemModel::FindProperty(const mitk::BaseProperty* property) +{ + if (property == NULL) + return QModelIndex(); + + typedef mitk::PropertyList::PropertyMap PropertyMap; + const PropertyMap* propertyMap = m_PropertyList->GetMap(); + + PropertyMap::const_iterator it = std::find_if(propertyMap->begin(), propertyMap->end(), PropertyEqualTo(property)); + + if (it == propertyMap->end()) + return QModelIndex(); + + QString name = QString::fromStdString(it->first); + + if (!name.contains('.')) + { + QModelIndexList item = this->match(index(0, 0), Qt::DisplayRole, name, 1, Qt::MatchExactly); + + if (!item.empty()) + return item[0]; + } + else + { + QStringList names = name.split('.'); + QModelIndexList items = this->match(index(0, 0), Qt::DisplayRole, names.last(), -1, Qt::MatchRecursive | Qt::MatchExactly); + + foreach(QModelIndex item, items) + { + QModelIndex candidate = item; + + for (int i = names.length() - 1; i != 0; --i) + { + QModelIndex parent = item.parent(); + + if (parent.parent() == QModelIndex()) + { + if (parent.data() != names.first()) + break; + + return candidate; + } + + if (parent.data() != names[i - 1]) + break; + + item = parent; + } + } + } + + return QModelIndex(); +} + +Qt::ItemFlags QmitkPropertyItemModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + if (index.column() == 1) + { + if (index.data(Qt::EditRole).isValid()) + flags |= Qt::ItemIsEditable; + + if (index.data(Qt::CheckStateRole).isValid()) + flags |= Qt::ItemIsUserCheckable; + } + + return flags; +} + +mitk::PropertyList* QmitkPropertyItemModel::GetPropertyList() const +{ + return m_PropertyList.GetPointer(); +} + +QVariant QmitkPropertyItemModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return m_RootItem->GetData(section); + + return QVariant(); +} + +QModelIndex QmitkPropertyItemModel::index(int row, int column, const QModelIndex& parent) const +{ + if (!this->hasIndex(row, column, parent)) + return QModelIndex(); + + QmitkPropertyItem* parentItem = parent.isValid() + ? static_cast(parent.internalPointer()) + : m_RootItem.get(); + + QmitkPropertyItem* childItem = parentItem->GetChild(row); + + return childItem != NULL + ? this->createIndex(row, column, childItem) + : QModelIndex(); +} + +void QmitkPropertyItemModel::OnPreferencesChanged(const berry::IBerryPreferences* preferences) +{ + bool showAliases = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES, true); + bool filterProperties = preferences->GetBool(QmitkPropertiesPreferencePage::FILTER_PROPERTIES, true); + + bool updateAliases = showAliases != (m_PropertyAliases != NULL); + bool updateFilters = filterProperties != (m_PropertyFilters != NULL); + + bool resetPropertyList = false; + + if (updateAliases) + { + m_PropertyAliases = showAliases + ? mitk::GetPropertyService() + : NULL; + + resetPropertyList = m_PropertyList.IsNotNull(); + } + + if (updateFilters) + { + m_PropertyFilters = filterProperties + ? mitk::GetPropertyService() + : NULL; + + if (!resetPropertyList) + resetPropertyList = m_PropertyList.IsNotNull(); + } + + if (resetPropertyList) + this->SetNewPropertyList(m_PropertyList.GetPointer()); +} + +void QmitkPropertyItemModel::OnPropertyDeleted(const itk::Object* property, const itk::EventObject&) +{ + /*QModelIndex index = this->FindProperty(static_cast(property)); + + if (index != QModelIndex()) + this->reset();*/ +} + +void QmitkPropertyItemModel::OnPropertyListDeleted(const itk::Object*) +{ + this->CreateRootItem(); +} + +void QmitkPropertyItemModel::OnPropertyModified(const itk::Object* property, const itk::EventObject&) +{ + QModelIndex index = this->FindProperty(static_cast(property)); + + if (index != QModelIndex()) + emit dataChanged(index, index); +} + +QModelIndex QmitkPropertyItemModel::parent(const QModelIndex& child) const +{ + if (!child.isValid()) + return QModelIndex(); + + QmitkPropertyItem* parentItem = static_cast(child.internalPointer())->GetParent(); + + if (parentItem == m_RootItem.get()) + return QModelIndex(); + + return this->createIndex(parentItem->GetRow(), 0, parentItem); +} + +int QmitkPropertyItemModel::rowCount(const QModelIndex& parent) const +{ + if (parent.column() > 0) + return 0; + + QmitkPropertyItem *parentItem = parent.isValid() + ? static_cast(parent.internalPointer()) + : m_RootItem.get(); + + return parentItem->GetChildCount(); +} + +bool QmitkPropertyItemModel::setData(const QModelIndex& index, const QVariant& value, int role) +{ + if (!index.isValid() || index.column() != 1 || (role != Qt::EditRole && role != Qt::CheckStateRole)) + return false; + + mitk::BaseProperty* property = GetBaseProperty(static_cast(index.internalPointer())->GetData(1)); + + if (property == NULL) + return false; + + if (mitk::BoolProperty* boolProperty = dynamic_cast(property)) + { + boolProperty->SetValue(value.toInt() == Qt::Checked ? true : false); + } + else if (mitk::StringProperty* stringProperty = dynamic_cast(property)) + { + stringProperty->SetValue(value.toString().toStdString()); + } + else if (mitk::IntProperty* intProperty = dynamic_cast(property)) + { + intProperty->SetValue(value.toInt()); + } + else if (mitk::FloatProperty* floatProperty = dynamic_cast(property)) + { + floatProperty->SetValue(value.toFloat()); + } + else if (mitk::DoubleProperty* doubleProperty = dynamic_cast(property)) + { + doubleProperty->SetValue(value.toDouble()); + } + else if (mitk::EnumerationProperty* enumProperty = dynamic_cast(property)) + { + std::string selection = value.toString().toStdString(); + + if (selection != enumProperty->GetValueAsString() && enumProperty->IsValidEnumerationValue(selection)) + enumProperty->SetValue(selection); + } + else if (mitk::ColorProperty* colorProperty = dynamic_cast(property)) + { + colorProperty->SetValue(QtToMitk(value.value())); + } + + m_PropertyList->InvokeEvent(itk::ModifiedEvent()); + m_PropertyList->Modified(); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + return true; +} + +void QmitkPropertyItemModel::SetNewPropertyList(mitk::PropertyList* propertyList) +{ + typedef mitk::PropertyList::PropertyMap PropertyMap; + + this->beginResetModel(); + + if (m_PropertyList.IsNotNull()) + { + mitk::MessageDelegate1 delegate(this, &QmitkPropertyItemModel::OnPropertyListDeleted); + m_PropertyList.ObjectDelete.RemoveListener(delegate); + + const PropertyMap* propertyMap = m_PropertyList->GetMap(); + + for (PropertyMap::const_iterator propertyIt = propertyMap->begin(); propertyIt != propertyMap->end(); ++propertyIt) + { + std::map::const_iterator tagIt = m_PropertyModifiedTags.find(propertyIt->first); + + if (tagIt != m_PropertyModifiedTags.end()) + propertyIt->second->RemoveObserver(tagIt->second); + + tagIt = m_PropertyDeletedTags.find(propertyIt->first); + + if (tagIt != m_PropertyDeletedTags.end()) + propertyIt->second->RemoveObserver(tagIt->second); + } + + m_PropertyModifiedTags.clear(); + } + + m_PropertyList = propertyList; + + if (m_PropertyList.IsNotNull()) + { + mitk::MessageDelegate1 delegate(this, &QmitkPropertyItemModel::OnPropertyListDeleted); + m_PropertyList.ObjectDelete.AddListener(delegate); + + mitk::MessageDelegate2 propertyDelegate(this, &QmitkPropertyItemModel::OnPropertyModified); + + itk::MemberCommand::Pointer modifiedCommand = itk::MemberCommand::New(); + modifiedCommand->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyModified); + + const PropertyMap* propertyMap = m_PropertyList->GetMap(); + + for (PropertyMap::const_iterator it = propertyMap->begin(); it != propertyMap->end(); ++it) + m_PropertyModifiedTags.insert(std::make_pair(it->first, it->second->AddObserver(itk::ModifiedEvent(), modifiedCommand))); + + itk::MemberCommand::Pointer deletedCommand = itk::MemberCommand::New(); + deletedCommand->SetCallbackFunction(this, &QmitkPropertyItemModel::OnPropertyDeleted); + + for (PropertyMap::const_iterator it = propertyMap->begin(); it != propertyMap->end(); ++it) + m_PropertyDeletedTags.insert(std::make_pair(it->first, it->second->AddObserver(itk::DeleteEvent(), deletedCommand))); + } + + this->CreateRootItem(); + + if (m_PropertyList != NULL && !m_PropertyList->IsEmpty()) + { + mitk::PropertyList::PropertyMap filteredProperties; + bool filterProperties = false; + + if (m_PropertyFilters != NULL && (m_PropertyFilters->HasFilter() || m_PropertyFilters->HasFilter(m_ClassName.toStdString()))) + { + filteredProperties = m_PropertyFilters->ApplyFilter(m_ClassName.toStdString(), *m_PropertyList->GetMap()); + filterProperties = true; + } + + const mitk::PropertyList::PropertyMap* propertyMap = !filterProperties + ? m_PropertyList->GetMap() + : &filteredProperties; + + mitk::PropertyList::PropertyMap::const_iterator end = propertyMap->end(); + + for (mitk::PropertyList::PropertyMap::const_iterator iter = propertyMap->begin(); iter != end; ++iter) + { + QStringList nameAndAlias(QString::fromStdString(iter->first)); + + nameAndAlias << (m_PropertyAliases != NULL + ? QString::fromStdString(m_PropertyAliases->GetAlias(iter->first)) + : ""); + + QList data; + + data << (nameAndAlias[1].isEmpty() + ? nameAndAlias[0] + : nameAndAlias[1]); + + data << QVariant::fromValue((reinterpret_cast(iter->second.GetPointer()))); + + m_RootItem->AppendChild(new QmitkPropertyItem(data)); + } + } + + this->endResetModel(); +} + +void QmitkPropertyItemModel::SetPropertyList(mitk::PropertyList* propertyList, const QString& className) +{ + if (m_PropertyList.GetPointer() != propertyList) + { + m_ClassName = className; + this->SetNewPropertyList(propertyList); + } +} diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.h new file mode 100644 index 0000000000..c057eb8147 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemModel.h @@ -0,0 +1,74 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkPropertyItemModel_h +#define QmitkPropertyItemModel_h + +#include +#include +#include + +class QmitkPropertyItem; + +namespace berry +{ + struct IBerryPreferences; +} + +namespace mitk +{ + class PropertyAliases; + class PropertyFilters; +} + +class QmitkPropertyItemModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit QmitkPropertyItemModel(QObject* parent = NULL); + ~QmitkPropertyItemModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + Qt::ItemFlags flags(const QModelIndex& index) const; + mitk::PropertyList* GetPropertyList() const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; + void OnPreferencesChanged(const berry::IBerryPreferences* preferences); + QModelIndex parent(const QModelIndex& child) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); + void SetPropertyList(mitk::PropertyList* propertyList, const QString& className = ""); + +private: + void CreateRootItem(); + QModelIndex FindProperty(const mitk::BaseProperty* property); + void OnPropertyDeleted(const itk::Object* property, const itk::EventObject& event); + void OnPropertyListDeleted(const itk::Object* propertyList); + void OnPropertyModified(const itk::Object* property, const itk::EventObject& event); + void SetNewPropertyList(mitk::PropertyList* propertyList); + + mitk::PropertyAliases* m_PropertyAliases; + mitk::PropertyFilters* m_PropertyFilters; + mitk::WeakPointer m_PropertyList; + QString m_ClassName; + std::auto_ptr m_RootItem; + std::map m_PropertyDeletedTags; + std::map m_PropertyModifiedTags; +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.cpp new file mode 100644 index 0000000000..d0e96f4653 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.cpp @@ -0,0 +1,58 @@ +/*=================================================================== + +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 "QmitkPropertyItemSortFilterProxyModel.h" + +QmitkPropertyItemSortFilterProxyModel::QmitkPropertyItemSortFilterProxyModel(QObject* parent) + : QSortFilterProxyModel(parent) +{ +} + +QmitkPropertyItemSortFilterProxyModel::~QmitkPropertyItemSortFilterProxyModel() +{ +} + +bool QmitkPropertyItemSortFilterProxyModel::FilterAcceptsAnyChildRow(const QModelIndex& sourceParent) const +{ + QString propertyName = this->sourceModel()->data(sourceParent).toString(); + + if (propertyName.contains(filterRegExp())) + return true; + + if (this->sourceModel()->hasChildren(sourceParent)) + { + for (int row = 0; row < this->sourceModel()->rowCount(sourceParent); ++row) + { + if(this->FilterAcceptsAnyChildRow(this->sourceModel()->index(row, 0, sourceParent))) + return true; + } + } + + return false; +} + +bool QmitkPropertyItemSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const +{ + return this->FilterAcceptsAnyChildRow(this->sourceModel()->index(sourceRow, 0, sourceParent)); +} + +bool QmitkPropertyItemSortFilterProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const +{ + QString leftString = this->sourceModel()->data(left).toString(); + QString rightString = this->sourceModel()->data(right).toString(); + + return leftString.compare(rightString, this->sortCaseSensitivity()) < 0; +} diff --git a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.h similarity index 55% rename from Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.h rename to Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.h index 4e89b16c6c..022bafbd5f 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/src/internal/QmitkPropertyTreeFilterProxyModel.h +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyItemSortFilterProxyModel.h @@ -1,38 +1,38 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#ifndef QMITKPROPERTYTREEFILTERPROXYMODEL_H -#define QMITKPROPERTYTREEFILTERPROXYMODEL_H +#ifndef QmitkPropertyItemSortFilterProxyModel_h +#define QmitkPropertyItemSortFilterProxyModel_h #include -class QmitkPropertyTreeFilterProxyModel : public QSortFilterProxyModel +class QmitkPropertyItemSortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - QmitkPropertyTreeFilterProxyModel(QObject *parent = NULL); - ~QmitkPropertyTreeFilterProxyModel(); + explicit QmitkPropertyItemSortFilterProxyModel(QObject* parent = NULL); + ~QmitkPropertyItemSortFilterProxyModel(); protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const; + bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const; + bool lessThan(const QModelIndex& left, const QModelIndex& right) const; private: - bool filterAcceptsAnyChildRows(const QModelIndex &sourceParent) const; + bool FilterAcceptsAnyChildRow(const QModelIndex& sourceParent) const; }; #endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp new file mode 100644 index 0000000000..5158cefba1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.cpp @@ -0,0 +1,269 @@ +/*=================================================================== + +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 "mitkGetPropertyService.h" +#include "QmitkPropertiesPreferencePage.h" +#include "QmitkPropertyItemDelegate.h" +#include "QmitkPropertyItemModel.h" +#include "QmitkPropertyItemSortFilterProxyModel.h" +#include "QmitkPropertyTreeView.h" +#include +#include +#include +#include + +const std::string QmitkPropertyTreeView::VIEW_ID = "org.mitk.views.properties"; + +QmitkPropertyTreeView::QmitkPropertyTreeView() + : m_PropertyNameChangedTag(0), + m_PropertyAliases(NULL), + m_PropertyDescriptions(NULL), + m_ShowGenuineNames(false), + m_ProxyModel(NULL), + m_Model(NULL) +{ +} + +QmitkPropertyTreeView::~QmitkPropertyTreeView() +{ +} + +void QmitkPropertyTreeView::CreateQtPartControl(QWidget* parent) +{ + m_Controls.setupUi(parent); + + m_Controls.filter->SetDefaultText("Filter"); + + m_Controls.description->hide(); + + m_ProxyModel = new QmitkPropertyItemSortFilterProxyModel(m_Controls.treeView); + m_Model = new QmitkPropertyItemModel(m_ProxyModel); + + m_ProxyModel->setSourceModel(m_Model); + m_ProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive); + m_ProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + m_ProxyModel->setDynamicSortFilter(true); + + m_Controls.treeView->setItemDelegateForColumn(1, new QmitkPropertyItemDelegate(m_Controls.treeView)); + m_Controls.treeView->setModel(m_ProxyModel); + m_Controls.treeView->setColumnWidth(0, 150); + m_Controls.treeView->sortByColumn(0, Qt::AscendingOrder); + m_Controls.treeView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.treeView->setSelectionMode(QAbstractItemView::SingleSelection); + m_Controls.treeView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked); + + connect(m_Controls.filter, SIGNAL(textChanged(const QString&)), this, SLOT(OnFilterTextChanged(const QString&))); + connect(m_Controls.treeView->selectionModel(), SIGNAL(currentRowChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(OnCurrentRowChanged(const QModelIndex&, const QModelIndex&))); + connect(m_Model, SIGNAL(modelReset()), this, SLOT(OnModelReset())); +} + +QString QmitkPropertyTreeView::GetPropertyNameOrAlias(const QModelIndex& index) +{ + QString propertyName; + + if (index.isValid()) + { + QModelIndex current = index; + + while (current.isValid()) + { + QString name = m_ProxyModel->data(m_ProxyModel->index(current.row(), 0, current.parent())).toString(); + + propertyName.prepend(propertyName.isEmpty() + ? name + : name.append('.')); + + current = current.parent(); + } + } + + return propertyName; +} + +void QmitkPropertyTreeView::OnCurrentRowChanged(const QModelIndex& current, const QModelIndex&) +{ + if (m_PropertyDescriptions != NULL && current.isValid()) + { + QString name = this->GetPropertyNameOrAlias(current); + + if (!name.isEmpty()) + { + QString alias; + bool isTrueName = true; + + if (m_PropertyAliases != NULL) + { + std::string trueName = m_PropertyAliases->GetPropertyName(name.toStdString()); + + if (!trueName.empty()) + { + alias = name; + name = QString::fromStdString(trueName); + isTrueName = false; + } + } + + QString description = QString::fromStdString(m_PropertyDescriptions->GetDescription(name.toStdString())); + + if (!description.isEmpty()) + { + if (!isTrueName && alias.isEmpty() && m_PropertyAliases != NULL) + alias = QString::fromStdString(m_PropertyAliases->GetAlias(name.toStdString())); + + QString customizedDescription; + + if (!alias.isEmpty()) + { + if (m_ShowGenuineNames) + { + customizedDescription = "

" + alias + "

"; + customizedDescription += "
" + name + "
"; + } + else + { + customizedDescription = "

" + alias + "

"; + } + } + else + { + customizedDescription = "

" + name + "

"; + } + + customizedDescription += description; + + m_Controls.description->setText(customizedDescription); + m_Controls.description->show(); + + return; + } + } + } + + m_Controls.description->hide(); +} + +void QmitkPropertyTreeView::OnFilterTextChanged(const QString& filter) +{ + m_ProxyModel->setFilterWildcard(filter); + + if (filter.isEmpty()) + m_Controls.treeView->collapseAll(); + else + m_Controls.treeView->expandAll(); +} + +void QmitkPropertyTreeView::OnModelReset() +{ + m_Controls.description->hide(); +} + +void QmitkPropertyTreeView::OnPreferencesChanged(const berry::IBerryPreferences* preferences) +{ + bool showAliases = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_ALIASES, true); + bool showDescriptions = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_DESCRIPTIONS, true); + bool showGenuineNames = preferences->GetBool(QmitkPropertiesPreferencePage::SHOW_GENUINE_NAMES, true); + + bool updateAliases = showAliases != (m_PropertyAliases != NULL); + bool updateDescriptions = showDescriptions != (m_PropertyDescriptions != NULL); + bool updateGenuineNames = showGenuineNames != m_ShowGenuineNames; + + if (updateAliases) + m_PropertyAliases = showAliases + ? mitk::GetPropertyService() + : NULL; + + if (updateDescriptions) + m_PropertyDescriptions = showDescriptions + ? mitk::GetPropertyService() + : NULL; + + if (updateGenuineNames) + m_ShowGenuineNames = showGenuineNames; + + if (updateDescriptions || updateGenuineNames) + { + QModelIndexList selection = m_Controls.treeView->selectionModel()->selectedRows(); + + if (!selection.isEmpty()) + this->OnCurrentRowChanged(selection[0], selection[0]); + } + + m_Model->OnPreferencesChanged(preferences); +} + +void QmitkPropertyTreeView::OnPropertyNameChanged(const itk::EventObject&) +{ + mitk::PropertyList* propertyList = m_Model->GetPropertyList(); + + if (propertyList != NULL) + { + mitk::BaseProperty* nameProperty = propertyList->GetProperty("name"); + + if (nameProperty != NULL) + { + std::ostringstream partName; + partName << "Properties (" << nameProperty->GetValueAsString() << ')'; + this->SetPartName(partName.str()); + } + } +} + +void QmitkPropertyTreeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) +{ + mitk::PropertyList* propertyList = m_Model->GetPropertyList(); + + if (propertyList != NULL) + { + mitk::BaseProperty* nameProperty = propertyList->GetProperty("name"); + + if (nameProperty != NULL) + nameProperty->RemoveObserver(m_PropertyNameChangedTag); + + m_PropertyNameChangedTag = 0; + } + + if (nodes.empty() || nodes.front().IsNull()) + { + this->SetPartName("Properties"); + m_Model->SetPropertyList(NULL); + } + else + { + QString selectionClassName = nodes.front()->GetData() != NULL + ? nodes.front()->GetData()->GetNameOfClass() + : ""; + + m_Model->SetPropertyList(nodes.front()->GetPropertyList(), selectionClassName); + OnPropertyNameChanged(itk::ModifiedEvent()); + + mitk::BaseProperty* nameProperty = nodes.front()->GetProperty("name"); + + if (nameProperty != NULL) + { + itk::ReceptorMemberCommand::Pointer command = itk::ReceptorMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkPropertyTreeView::OnPropertyNameChanged); + m_PropertyNameChangedTag = nameProperty->AddObserver(itk::ModifiedEvent(), command); + } + } + + if (!m_ProxyModel->filterRegExp().isEmpty()) + m_Controls.treeView->expandAll(); +} + +void QmitkPropertyTreeView::SetFocus() +{ + m_Controls.filter->setFocus(); +} diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.h b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.h new file mode 100644 index 0000000000..2e8957c298 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.h @@ -0,0 +1,70 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkPropertyTreeView_h +#define QmitkPropertyTreeView_h + +#include +#include + +class QmitkPropertyItemModel; +class QmitkPropertyItemSortFilterProxyModel; + +namespace mitk +{ + class PropertyAliases; + class PropertyDescriptions; +} + +class QmitkPropertyTreeView : public QmitkAbstractView +{ + Q_OBJECT + +public: + static const std::string VIEW_ID; + + berryObjectMacro(QmitkPropertyTreeView) + + QmitkPropertyTreeView(); + ~QmitkPropertyTreeView(); + + void SetFocus(); + +protected: + void CreateQtPartControl(QWidget* parent); + +private: + QString GetPropertyNameOrAlias(const QModelIndex& index); + void OnPreferencesChanged(const berry::IBerryPreferences* preferences); + void OnPropertyNameChanged(const itk::EventObject& event); + void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes); + +private slots: + void OnCurrentRowChanged(const QModelIndex& current, const QModelIndex& previous); + void OnFilterTextChanged(const QString& filter); + void OnModelReset(); + +private: + unsigned long m_PropertyNameChangedTag; + mitk::PropertyAliases* m_PropertyAliases; + mitk::PropertyDescriptions* m_PropertyDescriptions; + bool m_ShowGenuineNames; + Ui::QmitkPropertyTreeView m_Controls; + QmitkPropertyItemSortFilterProxyModel* m_ProxyModel; + QmitkPropertyItemModel* m_Model; +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.ui b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.ui new file mode 100644 index 0000000000..87333b23d5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/QmitkPropertyTreeView.ui @@ -0,0 +1,85 @@ + + + QmitkPropertyTreeView + + + + 0 + 0 + 300 + 600 + + + + + + + + + + + + + Qt::NoFocus + + + ::item { + border-right: 1px solid palette(midlight); + padding-bottom: 1px; + padding-top: 1px; +} + +::item:last { + border-right: 0; +} + +::item:selected { + background: palette(highlight); + color: palette(highlighted-text); +} + + + Qt::ScrollBarAsNeeded + + + true + + + true + + + 54 + + + + + + + + 0 + 0 + + + + + + + Qt::RichText + + + true + + + + + + + + QmitkLineEdit + QLineEdit +
QmitkLineEdit.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/mitkGetPropertyService.h b/Plugins/org.mitk.gui.qt.properties/src/internal/mitkGetPropertyService.h new file mode 100644 index 0000000000..be6bb9d9e0 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/mitkGetPropertyService.h @@ -0,0 +1,39 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGetPropertyService_h +#define mitkGetPropertyService_h + +#include "org_mitk_gui_qt_properties_Activator.h" +#include + +namespace mitk +{ + template + T* GetPropertyService() + { + mitk::LoadPropertiesModule(); + + ctkPluginContext* context = mitk::org_mitk_gui_qt_properties_Activator::GetContext(); + ctkServiceReference serviceRef = context->getServiceReference(); + + return serviceRef + ? context->getService(serviceRef) + : NULL; + } +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.cpp b/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.cpp new file mode 100644 index 0000000000..16112dd4f4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.cpp @@ -0,0 +1,41 @@ +/*=================================================================== + +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 "org_mitk_gui_qt_properties_Activator.h" +#include "QmitkPropertiesPreferencePage.h" +#include "QmitkPropertyTreeView.h" +#include + +ctkPluginContext* mitk::org_mitk_gui_qt_properties_Activator::m_Context = NULL; + +ctkPluginContext* mitk::org_mitk_gui_qt_properties_Activator::GetContext() +{ + return m_Context; +} + +void mitk::org_mitk_gui_qt_properties_Activator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(QmitkPropertiesPreferencePage, context); + BERRY_REGISTER_EXTENSION_CLASS(QmitkPropertyTreeView, context); + m_Context = context; +} + +void mitk::org_mitk_gui_qt_properties_Activator::stop(ctkPluginContext*) +{ + m_Context = NULL; +} + +Q_EXPORT_PLUGIN2(org_mitk_gui_qt_properties, mitk::org_mitk_gui_qt_properties_Activator) diff --git a/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.h b/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.h new file mode 100644 index 0000000000..331a0bebd8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.properties/src/internal/org_mitk_gui_qt_properties_Activator.h @@ -0,0 +1,40 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef org_mitk_gui_qt_properties_Activator_h +#define org_mitk_gui_qt_properties_Activator_h + +#include + +namespace mitk +{ + class org_mitk_gui_qt_properties_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) + + public: + static ctkPluginContext* GetContext(); + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + + private: + static ctkPluginContext* m_Context; + }; +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox index e087268bb7..5a7657ce68 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentation.dox @@ -1,292 +1,309 @@ /** \page org_mitk_views_segmentation The Segmentation Plugin \image html segmentation.png "Icon of the Plugin" Some of the features described below are closed source additions to the open source toolkit MITK and are not available in every application. Available sections: - \ref org_mitk_gui_qt_segmentationUserManualOverview - \ref org_mitk_gui_qt_segmentationUserManualTechnical - \ref org_mitk_gui_qt_segmentationUserManualImageSelection - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling1 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling2 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling3 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling4 - \ref org_mitk_gui_qt_segmentationUserManualManualKringeling5 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation1 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation2 - \ref org_mitk_gui_qt_segmentationUserManualOrganSegmentation99 - \ref org_mitk_gui_qt_segmentationUserManualLesionSegmentation - \ref org_mitk_gui_qt_segmentationUserManualPostprocessing - \ref org_mitk_gui_qt_segmentationUserManualSurfaceMasking - \ref org_mitk_gui_qt_segmentationUserManualTechnicalDetail \section org_mitk_gui_qt_segmentationUserManualOverview Overview The Segmentation perspective allows you to create segmentations of anatomical and pathological structures in medical images of the human body. The perspective groups a number of tools which can be used for:
  • (semi-)automatic segmentation of organs on CT or MR image volumes
  • semi-automatic segmentation of lesions such as enlarged lymph nodes or tumors
  • manual segmentation of any structures you might want to delineate
\image html org_mitk_gui_qt_segmentationIMGapplication.png Segmentation perspective consisting of the Data Manager view and the Segmentation view If you wonder what segmentations are good for, we shortly revisit the concept of a segmentation here. A CT or MR image is made up of volume of physical measurements (volume elements are called voxels). In CT images, for example, the gray value of each voxel corresponds to the mass absorbtion coefficient for X-rays in this voxel, which is similar in many %parts of the human body. The gray value does not contain any further information, so the computer does not know whether a given voxel is part of the body or the background, nor can it tell a brain from a liver. However, the distinction between a foreground and a background structure is required when:
  • you want to know the volume of a given organ (the computer needs to know which %parts of the image belong to this organ)
  • you want to create 3D polygon visualizations (the computer needs to know the surfaces of structures that should be drawn)
  • as a necessary pre-processing step for therapy planning, therapy support, and therapy monitoring
Creating this distinction between foreground and background is called segmentation. The Segmentation perspective of the MITK Workbench uses a voxel based approach to segmentation, i.e. each voxel of an image must be completely assigned to either foreground or background. This is in contrast to some other applications which might use an approach based on contours, where the border of a structure might cut a voxel into two %parts. The remainder of this document will summarize the features of the Segmentation perspective and how they are used. \section org_mitk_gui_qt_segmentationUserManualTechnical Technical Issues The Segmentation perspective makes a number of assumptions. To know what this view can be used for, it will help you to know that:
  • Images must be 2D, 3D, or 3D+t
  • Images must be single-values, i.e. CT, MRI or "normal" ultrasound. Images from color doppler or photographic (RGB) images are not supported
  • Segmentations are handled as binary images of the same extent as the original image
\section org_mitk_gui_qt_segmentationUserManualImageSelection Image Selection The Segmentation perspective makes use of the Data Manager view to give you an overview of all images and segmentations. \image html org_mitk_gui_qt_segmentationIMGselection.png Data Manager is used for selecting the current segmentation. The reference image is selected in the drop down box of the control area. To select the reference image (e.g. the original CT/MR image) use the drop down box in the control area of the Segmentation view. The segmentation image selected in the Data Manager is displayed below the drop down box. If no segmentation image exists or none is selected create a new segmentation image by using the "New segmentation" button. Some items of the graphical user interface might be disabled when no image is selected. In any case, the application will give you hints if a selection is needed. \section org_mitk_gui_qt_segmentationUserManualManualKringeling Manual Contouring With manual contouring you define which voxels are part of the segmentation and which are not. This allows you to create segmentations of any structeres that you may find in an image, even if they are not part of the human body. You might also use manual contouring to correct segmentations that result from sub-optimal automatic methods. The drawback of manual contouring is that you might need to define contours on many 2D slices. However, this is moderated by the interpolation feature, which will make suggestions for a segmentation. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling1 Creating New Segmentations Unless you want to edit existing segmentations, you have to create a new, empty segmentation before you can edit it. To do so, click the "New manual segmentation" button. Input fields will appear where you can choose a name for the new segmentation and a color for its display. Click the checkmark button to confirm or the X button to cancel the new segmentation. Notice that the input field suggests names once you %start typing and that it also suggests colors for known organ names. If you use names that are not yet known to the application, it will automatically remember these names and consider them the next time you create a new segmentation. Once you created a new segmentation, you can notice a new item with the "binary mask" icon in the Data Manager tree view. This item is automatically selected for you, allowing you to %start editing the new segmentation right away. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling2 Selecting Segmentations for Editing As you might want to have segmentations of multiple structures in a single patient image, the application needs to know which of them to use for editing. You select a segmenation by clicking it in the tree view of Data Manager. Note that segmentations are usually displayed as sub-items of "their" patient image. In the rare case, where you need to edit a segmentation that is not displayed as a a sub-item, you can click both the original image AND the segmentation while holding down CTRL or for Mac OS X the CMD on the keyboard. When a selection is made, the Segmentation View will hide all but the selected segmentation and the corresponding original image. When there are multiple segmentations, the unselected ones will remain in the Data Manager, you can make them visible at any time by selecting them. \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling3 Selecting Editing Tools If you are familiar with the MITK Workbench, you know that clicking and moving the mouse in any of the 2D render windows will move around the crosshair that defines what part of the image is displayed. This behavior is disabled while any of the manual segmentation tools are active -- otherwise you might have a hard time concentrating on the contour you are drawing. To %start using one of the editing tools, click its button the the displayed toolbox. The selected editing tool will be active and its corresponding button will stay pressed until you click the button again. Selecting a different tool also deactivates the previous one. If you have to delineate a lot of images, you should try using shortcuts to switch tools. Just hit the first letter of each tool to activate it (A for Add, S for Subtract, etc.). \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling4 Using Editing Tools All of the editing tools work by the same principle: you use the mouse (left button) to click anywhere in a 2D window (any of the orientations axial, sagittal, or frontal), move the mouse while holding the mouse button and release to finish the editing action. Multi-step undo and redo is fully supported by all editing tools. Use the application-wide undo button in the toolbar to revert erroneous %actions. \image html org_mitk_gui_qt_segmentationIMGiconAddSubtract.png Add and Subtract Tools Use the left mouse button to draw a closed contour. When releasing the mouse button, the contour will be added (Add tool) to or removed from (Subtract tool) the current segmentation. Hold down the CTRL / CMD key to invert the operation (this will switch tools temporarily to allow for quick corrections). \image html org_mitk_gui_qt_segmentationIMGiconPaintWipe.png Paint and Wipe Tools Use the slider below the toolbox to change the radius of these round paintbrush tools. Move the mouse in any 2D window and press the left button to draw or erase pixels. As the Add/Subtract tools, holding CTRL / CMD while drawing will invert the current tool's behavior. \image html org_mitk_gui_qt_segmentationIMGiconRegionGrowing.png Region Growing Tool Click at one point in a 2D slice widget to add an image region to the segmentation with the region growing tool. Moving up the cursor while holding the left mouse button widens the range for the included grey values; moving it down narrows it. When working on an image with a high range of grey values, the selection range can be influenced more strongly by moving the cursor at higher velocity. Region Growing selects all pixels around the mouse cursor that have a similar gray value as the pixel below the mouse cursor. This enables you to quickly create segmentations of structures that have a good contrast to surrounding tissue, e.g. the lungs. The tool will select more or less pixels (corresponding to a changing gray value interval width) when you move the mouse up or down while holding down the left mouse button. A common issue with region growing is the so called "leakage" which happens when the structure of interest is connected to other pixels, of similar gray values, through a narrow "bridge" at the border of the structure. The Region Growing tool comes with a "leakage detection/removal" feature. If leakage happens, you can left-click into the leakage region and the tool will try to automatically remove this region (see illustration below). \image html org_mitk_gui_qt_segmentationIMGleakage.png Leakage correction feature of the Region Growing tool
\image html org_mitk_gui_qt_segmentationIMGiconCorrection.png Correction Tool You do not have to draw a closed contour to use the Correction tool and do not need to switch between the Add and Substract tool to perform small corrective changes. The following figure shows the usage of this tool:
  • if the user draws a line which %starts and ends outside the segmenation AND it intersects no other segmentation the endpoints of the line are connected and the resulting contour is filled
  • if the user draws a line which %starts and ends outside the segmenation a part of it is cut off (left image)
  • if the line is drawn fully inside the segmentation the marked region is added to the segmentation (right image)
\image html org_mitk_gui_qt_segmentationIMGcorrectionActions.png %Actions of the Correction tool illustrated.
\image html org_mitk_gui_qt_segmentationIMGiconFill.png Fill Tool Left-click inside a segmentation with holes to completely fill all holes. \image html org_mitk_gui_qt_segmentationIMGiconErase.png Erase Tool This tool removes a connected part of pixels that form a segmentation. You may use it to remove so called islands (see picture) or to clear a whole slice at once (hold CTRL while clicking). +\image html org_mitk_gui_qt_segmentationIMGiconLiveWire.png LiveWire Tool + +The LiveWire Tool acts as a magnetic lasso with a contour snapping to edges of objects. + +\image html org_mitk_gui_qt_segmentationIMGLiveWireUsage.png Steps for using LiveWire Tool + +
    +
  • (1) To start the Tool you have to double click near the edge of the object you want to segment. The initial anchor point will snap to the edge within a 3x3 region. +
  • (2) Move the mouse. You don't have trace the edge of the object. The contour will automatically snap to it. +
  • (3) To fix a segment you can set anchor points by single left mouse button click. +
  • (4) Go on with moving the mouse and setting anchor points. +
  • (5) To close the contour double click on the initial anchor point. +
  • (6) After closing the contour can be edited by moving, inserting and deleting anchor points. +
+ +The contour will be transfered to its binary image representation by deactivating the tool. + \subsection org_mitk_gui_qt_segmentationUserManualManualKringeling5 Interpolation Creating segmentations for modern CT volumes is very time-consuming, because structures of interest can easily cover a range of 50 or more slices. The Manual Segmentation View offers two helpful features for these cases:
  • 3D Interpolation
  • 2D Interpolation

The 3D interpolation is activated by default when using the manual segmentation tools. That means if you start contouring, from the second contour onwards, the surface of the segmented area will be interpolated based on the given contour information. The interpolation works with all available manual tools. Please note that this is currently a pure mathematical interpolation, i.e. image intensity information is not taken into account. With each further contour the interpolation result will be improved, but the more contours you provide the longer the recalculation will take. To achieve an optimal interpolation result and in this way a most accurate segmentation you should try to describe the surface with sparse contours by segmenting in arbitrary oriented planes. The 3D interpolation is not meant to be used for parallel slice-wise segmentation. \image html org_mitk_gui_qt_segmentation3DInterpolationWrongRight.png 3D Interpolation HowTo You can accept the interpolation result by clicking the "Accept" - button below the tool buttons. In this case the 3D interpolation will be deactivated automatically so that the result can be postprocessed without any interpolation running in background. During recalculation the interpolated surface is blinking yellow/white. When the interpolation has finished the surface is shown yellow with a small opacity. Additional to the surface, black contours are shown in the 3D render window. They mark the positions of all the drawn contours which were used for the interpolation. You can navigate between the drawn contours by clicking on the „Position“ - Nodes in the datamanager which are located below the selected segmentation. If you don't want to see these nodes just unckeck the „Show Position Nodes“ Checkbox and these nodes will be hidden. If you want to delete a drawn contour we recommend to use the Erase-Tool since Redo/Undo is not yet working for 3D interpolation.
The 2D Interpolation creates suggestions for a segmentation whenever you have a slice that
  • has got neighboring slices with segmentations (these do not need to be direct neighbors but could also be a couple of slices away) AND
  • is completely clear of a manual segmentation -- i.e. there will be no suggestion if there is even only a single pixel of segmentation in the current slice.
Interpolated suggestions are displayed in a different way than manual segmentations are, until you "accept" them as part of the segmentation. To accept single slices, click the "Accept" button below the toolbox. If you have segmented a whole organ in every-x-slice, you may also review the interpolations and then accept all of them at once by clicking "... all slices". \section org_mitk_gui_qt_segmentationUserManualOrganSegmentation Organ Segmentation \note This feature is only available in our 3M3 Demo Application (http://www.mint-medical.de/productssolutions/mitk3m3/mitk3m3/#downloads) but not in the open source part of MITK The manual contouring described above is a fallback option that will work for any kind of images and structures of interest. However, manual contouring is very time-consuming and tedious. This is why a major part of image analysis research is working towards automatic segmentation methods. The Segmentation View comprises a number of easy-to-use tools for segmentation of CT images (Liver) and MR image (left ventricle and wall, left and right lung). \subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation1 Liver on CT Images On CT image volumes, preferrably with a contrast agent in the portal venous phase, the Liver tool will fully automatically analyze and segment the image. All you have to do is to load and select the image, then click the "Liver" button. During the process, which takes a minute or two, you will get visual progress feedback by means of a contour that moves closer and closer to the real liver boundaries. \subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation2 Heart, Lung, and Hippocampus on MRI While liver segmentation is performed fully automatic, the following tools for segmentation of the heart, the lungs, and the hippocampus need a minimum amount of guidance. Click one of the buttons on the "Organ segmentation" page to add an average %model of the respective organ to the image. This %model can be dragged to the right position by using the left mouse button while holding down the CTRL key. You can also use CTRL + middle mouse button to rotate or CTRL + right mouse button to scale the %model. Before starting the automatic segmentation process by clicking the "Start segmentation" button, try placing the %model closely to the organ in the MR image (in most cases, you do not need to rotate or scale the %model). During the segmentation process, a green contour that moves closer and closer to the real liver boundaries will provide you with visual feedback of the segmentation progress. The algorithms used for segmentation of the heart and lung are method which need training by a number of example images. They will not work well with other kind of images, so here is a list of the image types that were used for training:
  • Hippocampus segmentation: T1-weighted MR images, 1.5 Tesla scanner (Magnetom Vision, Siemens Medical Solutions), 1.0 mm isotropic resolution
  • Heart: Left ventricle inner segmentation (LV Model): MRI; velocity encoded cine (VEC-cine) MRI sequence; trained on systole and diastole
  • Heart: Left ventricular wall segmentation (LV Inner Wall, LV Outer Wall): 4D MRI; short axis 12 slice spin lock sequence(SA_12_sl); trained on whole heart cycle
  • Lung segmentation: 3D and 4D MRI; works best on FLASH3D and TWIST4D sequences
\subsection org_mitk_gui_qt_segmentationUserManualOrganSegmentation99 Other Organs As mentioned in the Heart/Lung section, most of the underlying methods are based on "training". The basic algorithm is versatile and can be applied on all kinds of segmentation problems where the structure of interest is topologically like a sphere (and not like a torus etc.). If you are interested in other organs than those offered by the current version of the Segmentation view, please contact our research team. \section org_mitk_gui_qt_segmentationUserManualLesionSegmentation Lesion Segmentation \note This feature is only available in our 3M3 Demo Application (http://www.mint-medical.de/productssolutions/mitk3m3/mitk3m3/#downloads) but not in the open source part of MITK Lesion segmentation is a little different from organ segmentation. Since lesions are not part of the healthy body, they sometimes have a diffused border, and are often found in varying places all over the body. The tools in this section offer efficient ways to create 3D segmentations of such lesions. The Segmentation View currently offers supoprt for enlarged lymph nodes. To segment an enlarged lymph node, find a more or less central slice of it, activate the "Lymph Node" tool and draw a rough contour on the inside of the lymph node. When releaseing the mouse button, a segmentation algorithm is started in a background task. The result will become visible after a couple of seconds, but you do not have to wait for it. If you need to segment several lymph nodes, you can continue to inspect the image right after closing the drawn contour. If the lymph node segmentation is not to your content, you can select the "Lymph Node Correction" tool and drag %parts of the lymph node surface towards the right position (works in 3D, not slice-by-slice). This kind of correction helps in many cases. If nothing else helps, you can still use the pure manual tools as a fallback. \section org_mitk_gui_qt_segmentationUserManualPostprocessing Things you can do with segmentations As mentioned in the introduction, segmentations are never an end in themselves. Consequently, the Segmentation view adds a couple of "post-processing" %actions to the Data Manager. These %actions are accessible through the context-menu of segmentations in Data Manager's list view \image html org_mitk_gui_qt_segmentationIMGDataManagerContextMenu.png Context menu items for segmentations.
  • Create polygon %model applies the marching cubes algorithms to the segmentation. This polygon %model can be used for visualization in 3D or other things such as stereolithography (3D printing).
  • Create smoothed polygon %model uses smoothing in addition to the marching cubes algorithms, which creates models that do not follow the exact outlines of the segmentation, but look smoother.
  • Statistics goes through all the voxels in the patient image that are part of the segmentation and calculates some statistical measures (minumum, maximum, median, histogram, etc.). Note that the statistics are ALWAYS calculated for the parent element of the segmentation as shown in Data Manager.
  • Autocrop can save memory. Manual segmentations have the same extent as the patient image, even if the segmentation comprises only a small sub-volume. This invisible and meaningless margin is removed by autocropping.
\section org_mitk_gui_qt_segmentationUserManualSurfaceMasking Surface Masking You can use the surface masking tool to create binary images from a surface which is used used as a mask on an image. This task is demonstrated below: \image html segmentationFromSurfaceBefore.png Load an image and a surface. Select the image and the surface in the corresponding drop-down boxes (both are selected automatically if there is just one image and one surface) \image html segmentationFromSurfaceAfter.png Create segmentation from surface After clicking "Create segmentation from surface" the newly created binary image is inserted in the DataManager and can be used for further processing \section org_mitk_gui_qt_segmentationUserManualTechnicalDetail Technical Information for Developers For technical specifications see \subpage QmitkSegmentationTechnicalPage and for information on the extensions of the tools system \subpage toolextensions . */ diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGLiveWireUsage.PNG b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGLiveWireUsage.PNG new file mode 100644 index 0000000000..fb667cdc1c Binary files /dev/null and b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGLiveWireUsage.PNG differ diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGiconLiveWire.png b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGiconLiveWire.png new file mode 100644 index 0000000000..befc1f39bd Binary files /dev/null and b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/org_mitk_gui_qt_segmentationIMGiconLiveWire.png differ 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 e0410c695d..ab6fb31ecd 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationView.cpp @@ -1,1252 +1,1251 @@ /*=================================================================== 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 "mitkDataNodeObject.h" #include "mitkProperties.h" #include "mitkSegTool2D.h" #include "mitkGlobalInteraction.h" #include "QmitkStdMultiWidget.h" #include "QmitkNewSegmentationDialog.h" #include #include #include "QmitkSegmentationView.h" #include "QmitkSegmentationPostProcessing.h" #include "QmitkSegmentationOrganNamesHandling.cpp" #include #include //For Segmentation in rotated slices //TODO clean up includes #include "mitkVtkResliceInterpolationProperty.h" #include "mitkPlanarCircle.h" #include "mitkGetModuleContext.h" #include "mitkModule.h" #include "mitkModuleRegistry.h" #include "mitkSegmentationObjectFactory.h" const std::string QmitkSegmentationView::VIEW_ID = "org.mitk.views.segmentation"; // public methods QmitkSegmentationView::QmitkSegmentationView() :m_Parent(NULL) ,m_Controls(NULL) ,m_MultiWidget(NULL) ,m_RenderingManagerObserverTag(0) ,m_DataSelectionChanged(false) { RegisterSegmentationObjectFactory(); } QmitkSegmentationView::~QmitkSegmentationView() { // delete m_PostProcessing; delete m_Controls; } void QmitkSegmentationView::NewNodesGenerated() { // ForceDisplayPreferencesUponAllImages(); } void QmitkSegmentationView::NewNodeObjectsGenerated(mitk::ToolManager::DataVectorType* nodes) { if (!nodes) return; mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->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() { if (m_DataSelectionChanged) { this->OnSelectionChanged(this->GetDataManagerSelection()); } } void QmitkSegmentationView::Activated() { // should be moved to ::BecomesVisible() or similar if( m_Controls ) { m_Controls->m_ManualToolSelectionBox->setEnabled( true ); m_Controls->m_OrganToolSelectionBox->setEnabled( true ); m_Controls->m_LesionToolSelectionBox->setEnabled( true ); m_Controls->m_SlicesInterpolator->Enable3DInterpolation( m_Controls->widgetStack->currentWidget() == m_Controls->pageManual ); //TODO Remove Observer itk::ReceptorMemberCommand::Pointer command1 = itk::ReceptorMemberCommand::New(); command1->SetCallbackFunction( this, &QmitkSegmentationView::RenderingManagerReinitialized ); m_RenderingManagerObserverTag = mitk::RenderingManager::GetInstance()->AddObserver( mitk::RenderingManagerViewsInitializedEvent(), command1 ); //Adding observers for node visibility to existing segmentations mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isSegmentation = mitk::NodePredicateAnd::New( isImage, isBinary ); mitk::DataStorage::SetOfObjects::ConstPointer segmentations = this->GetDefaultDataStorage()->GetSubset( isSegmentation ); mitk::DataStorage::SetOfObjects::ConstPointer image = this->GetDefaultDataStorage()->GetSubset( isImage ); if (!image->empty()) { OnSelectionChanged(*image->begin()); } for ( mitk::DataStorage::SetOfObjects::const_iterator iter = segmentations->begin(); iter != segmentations->end(); ++iter) { mitk::DataNode* node = *iter; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( node, node->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); } if(segmentations->Size() > 0) { FireNodeSelected(segmentations->ElementAt(0)); segmentations->ElementAt(0)->GetProperty("visible")->Modified(); } } } void QmitkSegmentationView::Deactivated() { if( m_Controls ) { mitk::RenderingManager::GetInstance()->RemoveObserver( m_RenderingManagerObserverTag ); m_Controls->m_ManualToolSelectionBox->setEnabled( false ); //deactivate all tools m_Controls->m_ManualToolSelectionBox->GetToolManager()->ActivateTool(-1); m_Controls->m_OrganToolSelectionBox->setEnabled( false ); m_Controls->m_LesionToolSelectionBox->setEnabled( false ); m_Controls->m_SlicesInterpolator->EnableInterpolation( false ); //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(); if (m_MultiWidget) { mitk::SlicesCoordinator *coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) coordinator->RemoveObserver(m_SlicesRotationObserverTag1); coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) coordinator->RemoveObserver(m_SlicesRotationObserverTag2); } // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); service->RemoveAllPlanePositions(); } } void QmitkSegmentationView::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { SetMultiWidget(&stdMultiWidget); } void QmitkSegmentationView::StdMultiWidgetNotAvailable() { SetMultiWidget(NULL); } void QmitkSegmentationView::StdMultiWidgetClosed( QmitkStdMultiWidget& /*stdMultiWidget*/ ) { SetMultiWidget(NULL); } void QmitkSegmentationView::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag1 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { coordinator->RemoveObserver( m_SlicesRotationObserverTag2 ); } } // save the current multiwidget as the working widget m_MultiWidget = multiWidget; //TODO Remove Observers if (m_MultiWidget) { mitk::SlicesCoordinator* coordinator = m_MultiWidget->GetSlicesRotator(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag1 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } coordinator = m_MultiWidget->GetSlicesSwiveller(); if (coordinator) { itk::ReceptorMemberCommand::Pointer command2 = itk::ReceptorMemberCommand::New(); command2->SetCallbackFunction( this, &QmitkSegmentationView::SliceRotation ); m_SlicesRotationObserverTag2 = coordinator->AddObserver( mitk::SliceRotationEvent(), command2 ); } } //TODO End Remove Observers if (m_Parent) { m_Parent->setEnabled(m_MultiWidget); } // tell the interpolation about toolmanager and multiwidget (and data storage) if (m_Controls && m_MultiWidget) { mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); m_Controls->m_SlicesInterpolator->SetDataStorage( *(this->GetDefaultDataStorage())); m_Controls->m_SlicesInterpolator->Initialize( toolManager, m_MultiWidget ); } } void QmitkSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences*) { ForceDisplayPreferencesUponAllImages(); } //TODO remove function void QmitkSegmentationView::RenderingManagerReinitialized(const itk::EventObject&) { CheckImageAlignment(); } //TODO remove function void QmitkSegmentationView::SliceRotation(const itk::EventObject&) { CheckImageAlignment(); } // protected slots void QmitkSegmentationView::CreateNewSegmentation() { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer 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 QString storedList = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); QStringList organColors; if (storedList.isEmpty()) { organColors = GetDefaultOrganColorString(); } else { /* a couple of examples of how organ names are stored: a simple item is built up like 'name#AABBCC' where #AABBCC is the hexadecimal notation of a color as known from HTML items are stored separated by ';' this makes it necessary to escape occurrences of ';' in name. otherwise the string "hugo;ypsilon#AABBCC;eugen#AABBCC" could not be parsed as two organs but we would get "hugo" and "ypsilon#AABBCC" and "eugen#AABBCC" so the organ name "hugo;ypsilon" is stored as "hugo\;ypsilon" and must be unescaped after loading the following lines could be one split with Perl's negative lookbehind */ // recover string list from BlueBerry view's preferences QString storedString = QString::fromStdString( this->GetPreferences()->GetByteArray("Organ-Color-List","") ); MITK_DEBUG << "storedString: " << storedString.toStdString(); // match a string consisting of any number of repetitions of either "anything but ;" or "\;". This matches everything until the next unescaped ';' QRegExp onePart("(?:[^;]|\\\\;)*"); MITK_DEBUG << "matching " << onePart.pattern().toStdString(); int count = 0; int pos = 0; while( (pos = onePart.indexIn( storedString, pos )) != -1 ) { ++count; int length = onePart.matchedLength(); if (length == 0) break; QString matchedString = storedString.mid(pos, length); MITK_DEBUG << " Captured length " << length << ": " << matchedString.toStdString(); pos += length + 1; // skip separating ';' // unescape possible occurrences of '\;' in the string matchedString.replace("\\;", ";"); // add matched string part to output list organColors << matchedString; } MITK_DEBUG << "Captured " << count << " organ name/colors"; } dialog->SetSuggestionList( organColors ); int dialogReturnValue = dialog->exec(); if ( dialogReturnValue == QDialog::Rejected ) return; // user clicked cancel or pressed Esc or something similar // 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 = m_Controls->m_ManualToolSelectionBox->GetToolManager(); mitk::Tool* firstTool = toolManager->GetToolById(0); if (firstTool) { try { mitk::DataNode::Pointer emptySegmentation = firstTool->CreateEmptySegmentationNode( image, dialog->GetSegmentationName().toStdString(), dialog->GetColor() ); //Here we change the reslice interpolation mode for a segmentation, so that contours in rotated slice can be shown correctly emptySegmentation->SetProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_NEAREST) ); // 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 UpdateOrganList( organColors, dialog->GetSegmentationName(), dialog->GetColor() ); /* escape ';' here (replace by '\;'), see longer comment above */ std::string stringForStorage = organColors.replaceInStrings(";","\\;").join(";").toStdString(); MITK_DEBUG << "Will store: " << stringForStorage; this->GetPreferences()->PutByteArray("Organ-Color-List", stringForStorage ); this->GetPreferences()->Flush(); if(m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)) { m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)->SetSelected(false); } emptySegmentation->SetSelected(true); this->GetDefaultDataStorage()->Add( emptySegmentation, node ); // add as a child, because the segmentation "derives" from the original this->FireNodeSelected( emptySegmentation ); this->OnSelectionChanged( emptySegmentation ); this->SetToolManagerSelection(node, emptySegmentation); } catch (std::bad_alloc) { QMessageBox::warning(NULL,"Create new segmentation","Could not allocate memory for new segmentation"); } } } else { QMessageBox::information(NULL,"Segmentation","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::OnWorkingNodeVisibilityChanged(/*const itk::Object* caller, const itk::EventObject& e*/) { if (!m_Parent || !m_Parent->isVisible()) return; // The new selection behaviour is: // // When clicking on the checkbox of a segmentation the node will e selected and its reference node either // The previous selected segmentation (if there is one) will be deselected. Additionally a reinit on the // selected segmenation will be performed. // If more than one segmentation is selected the tools will be disabled. if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::DataNode::Pointer referenceDataNew; mitk::DataNode::Pointer workingData; bool workingNodeIsVisible (true); unsigned int numberOfSelectedSegmentations (0); // iterate all images mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( isImage ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); bool isSegmentation(false); node->GetBoolProperty("binary", isSegmentation); if (node->IsSelected() && isSegmentation) { workingNodeIsVisible = node->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); if (!workingNodeIsVisible) return; numberOfSelectedSegmentations++; workingData = node; if (this->GetDefaultDataStorage()->GetSources(node)->Size() != 0) { referenceDataNew = this->GetDefaultDataStorage()->GetSources(node)->ElementAt(0); } bool isBinary(false); //Find topmost source or first source which is no binary image while (referenceDataNew.IsNotNull() && this->GetDefaultDataStorage()->GetSources(referenceDataNew)->Size() != 0) { referenceDataNew = this->GetDefaultDataStorage()->GetSources(referenceDataNew)->ElementAt(0); referenceDataNew->GetBoolProperty("binary",isBinary); if (!isBinary) break; } if (workingNodeIsVisible && referenceDataNew) { //Since the binary property of a segmentation can be set to false and afterwards you can create a new segmentation out of it //->could lead to a deadloop NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( referenceDataNew ); if ( searchIter != m_WorkingDataObserverTags.end()) { referenceDataNew->GetProperty("visible")->RemoveObserver( (*searchIter).second ); } referenceDataNew->SetVisibility(true); } //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceDataNew) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); continue; } if (workingData.IsNull() || (workingNodeIsVisible && node != referenceDataNew)) { node->SetVisibility((false)); } } if(numberOfSelectedSegmentations == 1) SetToolManagerSelection(referenceDataNew, workingData); mitk::DataStorage::SetOfObjects::Pointer temp = mitk::DataStorage::SetOfObjects::New(); temp->InsertElement(0,workingData); mitk::TimeSlicedGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(temp); // Reinit current node ForceDisplayPreferencesUponAllImages(); // initialize the views to the bounding geometry /*mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll();*/ } void QmitkSegmentationView::NodeRemoved(const mitk::DataNode* node) { bool isSeg(false); bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); node->GetBoolProperty("binary", isSeg); mitk::Image* image = dynamic_cast(node->GetData()); if(isSeg && !isHelperObject && image) { mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations(node, mitk::NodePredicateProperty::New("isContourMarker" , mitk::BoolProperty::New(true))); // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); 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()); } mitk::DataNode* tempNode = const_cast(node); node->GetProperty("visible")->RemoveObserver( m_WorkingDataObserverTags[tempNode] ); m_WorkingDataObserverTags.erase(tempNode); mitk::SurfaceInterpolationController::GetInstance()->RemoveSegmentationFromContourList(image); } if((m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0) == node)|| (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0) == node)) { //as we don't know which node was actually remove e.g. our reference node, disable 'New Segmentation' button. //consider the case that there is no more image in the datastorage this->SetToolManagerSelection(NULL, NULL); } } void QmitkSegmentationView::CreateSegmentationFromSurface() { mitk::DataNode::Pointer surfaceNode = m_Controls->MaskSurfaces->GetSelectedNode(); mitk::Surface::Pointer surface(0); if(surfaceNode.IsNotNull()) surface = dynamic_cast ( surfaceNode->GetData() ); if(surface.IsNull()) { this->HandleException( "No surface selected.", m_Parent, true); return; } mitk::DataNode::Pointer imageNode = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); mitk::Image::Pointer image(0); if (imageNode.IsNotNull()) image = dynamic_cast( imageNode->GetData() ); if(image.IsNull()) { this->HandleException( "No image selected.", m_Parent, true); return; } mitk::SurfaceToImageFilter::Pointer s2iFilter = mitk::SurfaceToImageFilter::New(); s2iFilter->MakeOutputBinaryOn(); s2iFilter->SetInput(surface); s2iFilter->SetImage(image); s2iFilter->Update(); mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); std::string nameOfResultImage = imageNode->GetName(); nameOfResultImage.append(surfaceNode->GetName()); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); resultNode->SetData( s2iFilter->GetOutput() ); this->GetDataStorage()->Add(resultNode, imageNode); } void QmitkSegmentationView::ToolboxStackPageChanged(int id) { // interpolation only with manual tools visible m_Controls->m_SlicesInterpolator->EnableInterpolation( id == 0 ); if( id == 0 ) { mitk::DataNode::Pointer workingData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0); if( workingData.IsNotNull() ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegImage->show(); m_Controls->lblSegmentation->show(); } } else { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } // this is just a workaround, should be removed when all tools support 3D+t if (id==2) // lesions { mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull()) { if (image->GetDimension()>3) { m_Controls->widgetStack->setCurrentIndex(0); QMessageBox::information(NULL,"Segmentation","Lesion segmentation is currently not supported for 4D images"); } } } } } // protected void QmitkSegmentationView::OnComboBoxSelectionChanged( const mitk::DataNode* node ) { mitk::DataNode* selectedNode = const_cast(node); if( selectedNode != NULL ) { m_Controls->refImageSelector->show(); m_Controls->lblReferenceImageSelectionWarning->hide(); bool isBinary(false); selectedNode->GetBoolProperty("binary", isBinary); if ( isBinary ) { FireNodeSelected(selectedNode); selectedNode->SetVisibility(true); } else if (node != m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)) { if (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)) m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0)->SetVisibility(false); if (m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)) { m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetWorkingData(0)->SetVisibility(false); } FireNodeSelected(selectedNode); selectedNode->SetVisibility(true); SetToolManagerSelection(selectedNode, NULL); } } else { m_Controls->refImageSelector->hide(); m_Controls->lblReferenceImageSelectionWarning->show(); } } void QmitkSegmentationView::OnShowMarkerNodes (bool state) { mitk::SegTool2D::Pointer manualSegmentationTool; unsigned int numberOfExistingTools = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetTools().size(); for(unsigned int i = 0; i < numberOfExistingTools; i++) { manualSegmentationTool = dynamic_cast(m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetToolById(i)); if (manualSegmentationTool) { if(state == true) { manualSegmentationTool->SetShowMarkerNodes( true ); } else { manualSegmentationTool->SetShowMarkerNodes( false ); } } } } void QmitkSegmentationView::OnSelectionChanged(mitk::DataNode* node) { std::vector nodes; nodes.push_back( node ); this->OnSelectionChanged( nodes ); } void QmitkSegmentationView::OnSurfaceSelectionChanged() { // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); } void QmitkSegmentationView::OnSelectionChanged(std::vector nodes) { // if the selected node is a contourmarker if ( !nodes.empty() ) { 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 ) ); } } // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull())) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); m_DataSelectionChanged = false; if (!m_Parent || !m_Parent->isVisible()) { m_DataSelectionChanged = true; return; } // reaction to BlueBerry selection events // this method will try to figure out if a relevant segmentation and its corresponding original image were selected // a warning is issued if the selection is invalid // appropriate reactions are triggered otherwise mitk::DataNode::Pointer referenceData = FindFirstRegularImage( nodes ); //m_Controls->refImageSelector->GetSelectedNode(); //FindFirstRegularImage( nodes ); mitk::DataNode::Pointer workingData = FindFirstSegmentation( nodes ); if(referenceData.IsNull() && workingData.IsNull()) return; bool invalidSelection( !nodes.empty() && ( nodes.size() > 2 || // maximum 2 selected nodes (nodes.size() == 2 && (workingData.IsNull() || referenceData.IsNull()) ) || // with two nodes, one must be the original image, one the segmentation ( workingData.GetPointer() == referenceData.GetPointer() ) //one node is selected as reference and working image // one item is always ok (might be working or reference or nothing ) ); if (invalidSelection) { // TODO visible warning when two images are selected MITK_ERROR << "WARNING: No image, too many (>2) or two equal images were selected."; workingData = NULL; if( m_Controls->refImageSelector->GetSelectedNode().IsNull() ) referenceData = NULL; } if ( workingData.IsNotNull() && referenceData.IsNull() ) { // find the DataStorage parent of workingData // try to find a "normal image" parent, select this as reference image mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinary = mitk::NodePredicateNot::New( isBinary ); mitk::NodePredicateAnd::Pointer isNormalImage = mitk::NodePredicateAnd::New( isImage, isNotBinary ); mitk::DataStorage::SetOfObjects::ConstPointer possibleParents = this->GetDefaultDataStorage()->GetSources( workingData, isNormalImage ); if (possibleParents->size() > 0) { if (possibleParents->size() > 1) { // TODO visible warning for this rare case MITK_ERROR << "Selected binary image has multiple parents. Using arbitrary first one for segmentation."; } referenceData = (*possibleParents)[0]; } NodeTagMapType::iterator searchIter = m_WorkingDataObserverTags.find( workingData ); if ( searchIter == m_WorkingDataObserverTags.end() ) { //MITK_INFO<<"Creating new observer"; itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkSegmentationView::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( workingData, workingData->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); workingData->GetProperty("visible")->Modified(); return; } if(workingData->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1")))) { //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(workingData) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull()) || (!referenceData)) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); SetToolManagerSelection(referenceData, workingData); FireNodeSelected(workingData); } else { SetToolManagerSelection(NULL, NULL); FireNodeSelected(workingData); } } else { //set comboBox to reference image disconnect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); m_Controls->refImageSelector->setCurrentIndex( m_Controls->refImageSelector->Find(referenceData) ); connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); // if Image and Surface are selected, enable button if ( (m_Controls->refImageSelector->GetSelectedNode().IsNull()) || (m_Controls->MaskSurfaces->GetSelectedNode().IsNull()) || (!referenceData)) m_Controls->CreateSegmentationFromSurface->setEnabled(false); else m_Controls->CreateSegmentationFromSurface->setEnabled(true); SetToolManagerSelection(referenceData, workingData); FireNodeSelected(referenceData); } } void QmitkSegmentationView::OnContourMarkerSelected(const mitk::DataNode *node) { //TODO renderWindow anders bestimmen, siehe CheckAlignment QmitkRenderWindow* selectedRenderWindow = 0; QmitkRenderWindow* RenderWindow1 = this->GetActiveStdMultiWidget()->GetRenderWindow1(); QmitkRenderWindow* RenderWindow2 = this->GetActiveStdMultiWidget()->GetRenderWindow2(); QmitkRenderWindow* RenderWindow3 = this->GetActiveStdMultiWidget()->GetRenderWindow3(); QmitkRenderWindow* RenderWindow4 = this->GetActiveStdMultiWidget()->GetRenderWindow4(); bool PlanarFigureInitializedWindow = false; // find initialized renderwindow if (node->GetBoolProperty("PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow1->GetRenderer())) { selectedRenderWindow = RenderWindow1; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow2->GetRenderer())) { selectedRenderWindow = RenderWindow2; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow3->GetRenderer())) { selectedRenderWindow = RenderWindow3; } if (!selectedRenderWindow && node->GetBoolProperty( "PlanarFigureInitializedWindow", PlanarFigureInitializedWindow, RenderWindow4->GetRenderer())) { selectedRenderWindow = RenderWindow4; } // 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; // gets the context of the "Mitk" (Core) module (always has id 1) // TODO Workaround until CTL plugincontext is available mitk::ModuleContext* context = mitk::ModuleRegistry::GetModule(1)->GetModuleContext(); // Workaround end mitk::ServiceReference serviceRef = context->GetServiceReference(); //mitk::ServiceReference serviceRef = mitk::GetModuleContext()->GetServiceReference(); mitk::PlanePositionManagerService* service = dynamic_cast(context->GetService(serviceRef)); selectedRenderWindow->GetSliceNavigationController()->ExecuteOperation(service->GetPlanePosition(id)); selectedRenderWindow->GetRenderer()->GetDisplayGeometry()->Fit(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstRegularImage( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { //mitk::DataNode::Pointer node = i.value() bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } // make sure this is not a binary image bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper mitk::Image if (isImage && !isSegmentation) return nodes.at(i); } return NULL; } mitk::DataNode::Pointer QmitkSegmentationView::FindFirstSegmentation( std::vector nodes ) { if (nodes.empty()) return NULL; for(unsigned int i = 0; i < nodes.size(); ++i) { bool isImage(false); if (nodes.at(i)->GetData()) { isImage = dynamic_cast(nodes.at(i)->GetData()) != NULL; } bool isSegmentation(false); nodes.at(i)->GetBoolProperty("binary", isSegmentation); // return first proper binary mitk::Image if (isImage && isSegmentation) { return nodes.at(i); } } return NULL; } void QmitkSegmentationView::SetToolManagerSelection(const mitk::DataNode* referenceData, const 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 = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetReferenceData(const_cast(referenceData)); toolManager->SetWorkingData( const_cast(workingData)); // check original image m_Controls->btnNewSegmentation->setEnabled(referenceData != NULL); if (referenceData) { m_Controls->lblReferenceImageSelectionWarning->hide(); } else { m_Controls->lblReferenceImageSelectionWarning->show(); m_Controls->lblWorkingImageSelectionWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } //TODO remove statement // check, wheter reference image is aligned like render windows. Otherwise display a visible warning (because 2D tools will probably not work) CheckImageAlignment(); // check segmentation if (referenceData) { if (!workingData) { m_Controls->lblWorkingImageSelectionWarning->show(); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); } } else { m_Controls->lblWorkingImageSelectionWarning->hide(); this->FireNodeSelected(const_cast(workingData)); if( m_Controls->widgetStack->currentIndex() == 0 ) { m_Controls->lblSegmentation->setText( workingData->GetName().c_str() ); m_Controls->lblSegmentation->show(); m_Controls->lblSegImage->show(); } } } } //TODO remove function void QmitkSegmentationView::CheckImageAlignment() { bool wrongAlignment(true); mitk::DataNode::Pointer node = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNotNull() && m_MultiWidget) { wrongAlignment = !( IsRenderWindowAligned(m_MultiWidget->GetRenderWindow1(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow2(), image ) && IsRenderWindowAligned(m_MultiWidget->GetRenderWindow3(), image ) ); } } m_Controls->lblAlignmentWarning->setVisible(wrongAlignment); } //TODO remove function bool QmitkSegmentationView::IsRenderWindowAligned(QmitkRenderWindow* renderWindow, mitk::Image* image) { if (!renderWindow) return false; // for all 2D renderwindows of m_MultiWidget check alignment mitk::PlaneGeometry::ConstPointer displayPlane = dynamic_cast( renderWindow->GetRenderer()->GetCurrentWorldGeometry2D() ); if (displayPlane.IsNull()) return false; int affectedDimension(-1); int affectedSlice(-1); return mitk::SegTool2D::DetermineAffectedImageSlice( image, displayPlane, affectedDimension, affectedSlice ); } //TODO remove function void QmitkSegmentationView::ForceDisplayPreferencesUponAllImages() { if (!m_Parent || !m_Parent->isVisible()) 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, NULL parent)) // if no segmentation is selected, do nothing if (!m_Controls) return; // might happen on initialization (preferences loaded) mitk::DataNode::Pointer referenceData = m_Controls->m_ManualToolSelectionBox->GetToolManager()->GetReferenceData(0); // 1. if (referenceData.IsNotNull()) { // iterate all images mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer allImages = this->GetDefaultDataStorage()->GetSubset( isImage ); //mitk::DataStorage::SetOfObjects::ConstPointer allSegmentationChilds = this->GetDefaultDataStorage()->GetDerivations(referenceData, isImage ); for ( mitk::DataStorage::SetOfObjects::const_iterator iter = allImages->begin(); iter != allImages->end(); ++iter) { mitk::DataNode* node = *iter; // apply display preferences ApplyDisplayOptions(node); // set visibility if(!node->IsSelected() || (node->IsSelected() && !node->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))))) node->SetVisibility((node == referenceData) || node->IsSelected() ); } // Reinit current node mitk::RenderingManager::GetInstance()->InitializeViews( referenceData->GetData()->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true ); } // 2. //if (workingData.IsNotNull() && !workingData->IsSelected()) //{ // workingData->SetVisibility(true); //} mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkSegmentationView::ApplyDisplayOptions(mitk::DataNode* node) { if (!node) return; bool isBinary(false); node->GetPropertyValue("binary", isBinary); if (isBinary) { node->SetProperty( "outline binary", mitk::BoolProperty::New( this->GetPreferences()->GetBool("draw outline", true)) ); node->SetProperty( "outline width", mitk::FloatProperty::New( 2.0 ) ); node->SetProperty( "opacity", mitk::FloatProperty::New( this->GetPreferences()->GetBool("draw outline", true) ? 1.0 : 0.3 ) ); node->SetProperty( "volumerendering", mitk::BoolProperty::New( this->GetPreferences()->GetBool("volume rendering", false) ) ); } } 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->lblWorkingImageSelectionWarning->hide(); m_Controls->lblAlignmentWarning->hide(); m_Controls->lblSegImage->hide(); m_Controls->lblSegmentation->hide(); m_Controls->refImageSelector->SetDataStorage(this->GetDefaultDataStorage()); mitk::TNodePredicateDataType::Pointer isMitkImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer isDiffusionImage = mitk::NodePredicateOr::New(isDwi, isDti); isDiffusionImage = mitk::NodePredicateOr::New(isDiffusionImage, isQbi); mitk::NodePredicateOr::Pointer isImage = mitk::NodePredicateOr::New(isDiffusionImage, isMitkImage); m_Controls->refImageSelector->SetPredicate(isImage); if( m_Controls->refImageSelector->GetSelectedNode().IsNotNull() ) m_Controls->lblReferenceImageSelectionWarning->hide(); else m_Controls->refImageSelector->hide(); mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); toolManager->SetDataStorage( *(this->GetDefaultDataStorage()) ); assert ( toolManager ); // all part of open source MITK m_Controls->m_ManualToolSelectionBox->SetGenerateAccelerators(true); m_Controls->m_ManualToolSelectionBox->SetToolGUIArea( m_Controls->m_ManualToolGUIContainer ); - m_Controls->m_ManualToolSelectionBox->SetDisplayedToolGroups("Add Subtract Paint Wipe 'Region Growing' Correction Fill Erase"); + m_Controls->m_ManualToolSelectionBox->SetDisplayedToolGroups("Add Subtract Paint Wipe 'Region Growing' Correction Fill Erase LiveWire"); m_Controls->m_ManualToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingData ); // available only in the 3M application if ( !m_Controls->m_OrganToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 1, false ); } m_Controls->m_OrganToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_OrganToolSelectionBox->SetToolGUIArea( m_Controls->m_OrganToolGUIContainer ); m_Controls->m_OrganToolSelectionBox->SetDisplayedToolGroups("'Hippocampus left' 'Hippocampus right' 'Lung left' 'Lung right' 'Liver' 'Heart LV' 'Endocard LV' 'Epicard LV' 'Prostate'"); m_Controls->m_OrganToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); // available only in the 3M application if ( !m_Controls->m_LesionToolSelectionBox->children().count() ) { m_Controls->widgetStack->setItemEnabled( 2, false ); } m_Controls->m_LesionToolSelectionBox->SetToolManager( *toolManager ); m_Controls->m_LesionToolSelectionBox->SetToolGUIArea( m_Controls->m_LesionToolGUIContainer ); m_Controls->m_LesionToolSelectionBox->SetDisplayedToolGroups("'Lymph Node'"); m_Controls->m_LesionToolSelectionBox->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceData ); toolManager->NewNodesGenerated += mitk::MessageDelegate( this, &QmitkSegmentationView::NewNodesGenerated ); // update the list of segmentations toolManager->NewNodeObjectsGenerated += mitk::MessageDelegate1( this, &QmitkSegmentationView::NewNodeObjectsGenerated ); // update the list of segmentations // create signal/slot connections connect( m_Controls->refImageSelector, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnComboBoxSelectionChanged( const mitk::DataNode* ) ) ); connect( m_Controls->btnNewSegmentation, SIGNAL(clicked()), this, SLOT(CreateNewSegmentation()) ); connect( m_Controls->CreateSegmentationFromSurface, SIGNAL(clicked()), this, SLOT(CreateSegmentationFromSurface()) ); connect( m_Controls->widgetStack, SIGNAL(currentChanged(int)), this, SLOT(ToolboxStackPageChanged(int)) ); connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSurfaceSelectionChanged( ) ) ); connect(m_Controls->MaskSurfaces, SIGNAL( OnSelectionChanged( const mitk::DataNode* ) ), this, SLOT( OnSurfaceSelectionChanged( ) ) ); connect(m_Controls->m_SlicesInterpolator, SIGNAL(SignalShowMarkerNodes(bool)), this, SLOT(OnShowMarkerNodes(bool))); m_Controls->MaskSurfaces->SetDataStorage(this->GetDefaultDataStorage()); m_Controls->MaskSurfaces->SetPredicate(mitk::NodePredicateDataType::New("Surface")); //// create helper class to provide context menus for segmentations in data manager // m_PostProcessing = new QmitkSegmentationPostProcessing(this->GetDefaultDataStorage(), this, m_Parent); } //void QmitkSegmentationView::OnPlaneModeChanged(int i) //{ // //if plane mode changes, disable all tools // if (m_MultiWidget) // { // mitk::ToolManager* toolManager = m_Controls->m_ManualToolSelectionBox->GetToolManager(); // // if (toolManager) // { // if (toolManager->GetActiveToolID() >= 0) // { // toolManager->ActivateTool(-1); // } // else // { // m_MultiWidget->EnableNavigationControllerEventListening(); // } // } // } //} // ATTENTION some methods for handling the known list of (organ names, colors) are defined in QmitkSegmentationOrganNamesHandling.cpp - diff --git a/Plugins/org.mitk.gui.qt.simulation/CMakeLists.txt b/Plugins/org.mitk.gui.qt.simulation/CMakeLists.txt index 84195b260a..e075434c20 100644 --- a/Plugins/org.mitk.gui.qt.simulation/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.simulation/CMakeLists.txt @@ -1,7 +1,7 @@ project(org_mitk_gui_qt_simulation) MACRO_CREATE_MITK_CTK_PLUGIN( EXPORT_DIRECTIVE SIMULATION_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDENCIES Simulation Qmitk + MODULE_DEPENDENCIES Qmitk Simulation ) diff --git a/Plugins/org.mitk.gui.qt.simulation/files.cmake b/Plugins/org.mitk.gui.qt.simulation/files.cmake index 342a0f859e..3be5b42edf 100644 --- a/Plugins/org.mitk.gui.qt.simulation/files.cmake +++ b/Plugins/org.mitk.gui.qt.simulation/files.cmake @@ -1,39 +1,41 @@ set(SRC_CPP_FILES ) set(INTERNAL_CPP_FILES org_mitk_gui_qt_simulation_Activator.cpp + QmitkCreateSimulationAction.cpp QmitkSimulationPreferencePage.cpp QmitkSimulationView.cpp ) set(UI_FILES src/internal/QmitkSimulationPreferencePageControls.ui src/internal/QmitkSimulationViewControls.ui ) set(MOC_H_FILES src/internal/org_mitk_gui_qt_simulation_Activator.h + src/internal/QmitkCreateSimulationAction.h src/internal/QmitkSimulationPreferencePage.h src/internal/QmitkSimulationView.h ) set(CACHED_RESOURCE_FILES resources/icon.png plugin.xml ) set(QRC_FILES resources/Simulation.qrc ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach() foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach() diff --git a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake index 912e7b0cf4..8ff31cfca6 100644 --- a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake +++ b/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake @@ -1,5 +1,5 @@ set(Plugin-Name "MITK Simulation") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.simulation org.mitk.gui.qt.datamanager) diff --git a/Plugins/org.mitk.gui.qt.simulation/plugin.xml b/Plugins/org.mitk.gui.qt.simulation/plugin.xml index b16639779a..fe22cf383a 100644 --- a/Plugins/org.mitk.gui.qt.simulation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.simulation/plugin.xml @@ -1,14 +1,20 @@ + + + diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.cpp new file mode 100644 index 0000000000..2cb32091bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.cpp @@ -0,0 +1,118 @@ +/*=================================================================== + +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 "QmitkCreateSimulationAction.h" +#include +#include +#include +#include +#include +#include + +static std::string CreateFileName(mitk::DataNode::Pointer dataNode) +{ + std::string path; + dataNode->GetStringProperty("path", path); + + std::string name; + dataNode->GetStringProperty("name", name); + + if (name.length() < 5) + { + name += ".scn"; + } + else + { + std::string ext = name.substr(name.length() - 4); + std::transform(ext.begin(), ext.end(), ext.begin(), tolower); + + if (ext != ".scn" && ext != ".xml") + name += ".scn"; + } + + return path + "/" + name; +} + +static void InitializeViews(mitk::DataStorage::Pointer dataStorage) +{ + mitk::NodePredicateNot::Pointer predicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); + mitk::DataStorage::SetOfObjects::ConstPointer subset = dataStorage->GetSubset(predicate); + mitk::TimeSlicedGeometry::Pointer geometry = dataStorage->ComputeBoundingGeometry3D(subset); + + mitk::RenderingManager::GetInstance()->InitializeViews(geometry); +} + +QmitkCreateSimulationAction::QmitkCreateSimulationAction() +{ +} + +QmitkCreateSimulationAction::~QmitkCreateSimulationAction() +{ +} + +void QmitkCreateSimulationAction::Run(const QList& selectedNodes) +{ + mitk::DataNode::Pointer dataNode; + + foreach(dataNode, selectedNodes) + { + if (dynamic_cast(dataNode->GetData()) != NULL) + { + mitk::SimulationTemplate* simulationTemplate = static_cast(dataNode->GetData()); + std::string contents = simulationTemplate->Bake(); + + if (contents.empty()) + { + MITK_ERROR << "Could not bake simulation template '" << dataNode->GetName() << "'!"; + continue; + } + + std::string fileName = CreateFileName(dataNode); + + std::ofstream file(fileName.c_str()); + file << contents; + file.close(); + + std::vector fileNames; + fileNames.push_back(fileName); + + mitk::DataNode::Pointer simulationNode = mitk::IOUtil::LoadDataNode(fileName); + + if (simulationNode.IsNotNull()) + { + m_DataStorage->Add(simulationNode, dataNode); + InitializeViews(m_DataStorage); + } + } + } +} + +void QmitkCreateSimulationAction::SetDataStorage(mitk::DataStorage* dataStorage) +{ + m_DataStorage = dataStorage; +} + +void QmitkCreateSimulationAction::SetFunctionality(berry::QtViewPart*) +{ +} + +void QmitkCreateSimulationAction::SetDecimated(bool) +{ +} + +void QmitkCreateSimulationAction::SetSmoothed(bool) +{ +} diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.h b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.h new file mode 100644 index 0000000000..e5817552eb --- /dev/null +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkCreateSimulationAction.h @@ -0,0 +1,45 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkCreateSimulationAction_h +#define QmitkCreateSimulationAction_h + +#include +#include + +class QmitkCreateSimulationAction : public QObject, public mitk::IContextMenuAction +{ + Q_OBJECT + Q_INTERFACES(mitk::IContextMenuAction) + +public: + QmitkCreateSimulationAction(); + ~QmitkCreateSimulationAction(); + + void Run(const QList& selectedNodes); + void SetDataStorage(mitk::DataStorage* dataStorage); + void SetFunctionality(berry::QtViewPart* functionality); + void SetDecimated(bool decimated); + void SetSmoothed(bool smoothed); + +private: + QmitkCreateSimulationAction(const QmitkCreateSimulationAction&); + QmitkCreateSimulationAction& operator=(const QmitkCreateSimulationAction&); + + mitk::DataStorage::Pointer m_DataStorage; +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp index d22ca55d04..b8d857a62f 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.cpp @@ -1,244 +1,207 @@ /*=================================================================== 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 "QmitkSimulationPreferencePage.h" -#include -#include +#include #include #include -#include +#include typedef sofa::helper::system::Plugin Plugin; typedef sofa::helper::system::PluginManager PluginManager; typedef sofa::helper::system::PluginManager::PluginIterator PluginIterator; typedef sofa::helper::system::PluginManager::PluginMap PluginMap; -berry::IPreferences::Pointer getSimulationPreferences() -{ - berry::ServiceRegistry& serviceRegistry = berry::Platform::GetServiceRegistry(); - berry::IPreferencesService::Pointer preferencesService = serviceRegistry.GetServiceById(berry::IPreferencesService::ID); - berry::IPreferences::Pointer preferences = preferencesService->GetSystemPreferences(); - return preferences->Node("/org.mitk.views.simulation"); -} - -void initSOFAPlugins(berry::IPreferences::Pointer preferences) -{ - if (preferences.IsNull()) - return; - - QString pluginPaths = preferences->GetByteArray(QmitkSimulationPreferencePage::PLUGIN_PATHS, "").c_str(); - - if (pluginPaths.isEmpty()) - return; - - QStringList pluginPathList = pluginPaths.split(';', QString::SkipEmptyParts); - QStringListIterator it(pluginPathList); - - typedef sofa::helper::system::PluginManager PluginManager; - PluginManager& pluginManager = PluginManager::getInstance(); - - while (it.hasNext()) - { - std::string path = it.next().toStdString(); - std::ostringstream errlog; - - pluginManager.loadPlugin(path, &errlog); - - if (errlog.str().empty()) - pluginManager.getPluginMap()[path].initExternalModule(); - } -} - -const std::string QmitkSimulationPreferencePage::PLUGIN_PATHS = "plugin paths"; - QmitkSimulationPreferencePage::QmitkSimulationPreferencePage() - : m_Preferences(getSimulationPreferences()), + : m_Preferences(mitk::GetSimulationPreferences()), m_Control(NULL) { - initSOFAPlugins(m_Preferences); } QmitkSimulationPreferencePage::~QmitkSimulationPreferencePage() { } void QmitkSimulationPreferencePage::CreateQtControl(QWidget* parent) { m_Control = new QWidget(parent); m_Controls.setupUi(m_Control); QStringList headerLabels; headerLabels << "Name" << "License" << "Version" << "Path"; m_Controls.pluginsTreeWidget->setHeaderLabels(headerLabels); connect(m_Controls.pluginsTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(OnPluginTreeWidgetItemSelectionChanged())); connect(m_Controls.addButton, SIGNAL(clicked()), this, SLOT(OnAddButtonClicked())); connect(m_Controls.removeButton, SIGNAL(clicked()), this, SLOT(OnRemoveButtonClicked())); this->Update(); } QWidget* QmitkSimulationPreferencePage::GetQtControl() const { return m_Control; } void QmitkSimulationPreferencePage::Init(berry::IWorkbench::Pointer) { } void QmitkSimulationPreferencePage::OnAddButtonClicked() { QString filter = "SOFA Plugins "; #if defined(__APPLE__) filter += "(*.dylib*)"; #elif defined(WIN32) filter += "(*.dll)"; #else filter += "(*.so)"; #endif std::string path = QFileDialog::getOpenFileName(m_Control, "Add SOFA Library", "", filter).toStdString(); + if (path.empty()) + return; + PluginManager &pluginManager = PluginManager::getInstance(); std::ostringstream errlog; if (pluginManager.loadPlugin(path, &errlog)) { if (!errlog.str().empty()) { QMessageBox* messageBox = new QMessageBox(m_Control); messageBox->setIcon(QMessageBox::Warning); messageBox->setStandardButtons(QMessageBox::Ok); messageBox->setText(errlog.str().c_str()); messageBox->setWindowTitle("Warning"); messageBox->show(); } Plugin& plugin = pluginManager.getPluginMap()[path]; plugin.initExternalModule(); QStringList pluginItem; pluginItem << plugin.getModuleName() << plugin.getModuleLicense() << plugin.getModuleVersion() << path.c_str(); m_Controls.pluginsTreeWidget->addTopLevelItem(new QTreeWidgetItem(pluginItem)); } else { QMessageBox* messageBox = new QMessageBox(m_Control); messageBox->setIcon(QMessageBox::Critical); messageBox->setStandardButtons(QMessageBox::Ok); messageBox->setText(errlog.str().c_str()); messageBox->setWindowTitle("Error"); messageBox->show(); } } void QmitkSimulationPreferencePage::OnPluginTreeWidgetItemSelectionChanged() { QList selectedItems = m_Controls.pluginsTreeWidget->selectedItems(); if (!selectedItems.isEmpty()) { PluginMap& pluginMap = sofa::helper::system::PluginManager::getInstance().getPluginMap(); std::string path = selectedItems[0]->text(3).toStdString(); m_Controls.descriptionPlainTextEdit->setPlainText(pluginMap[path].getModuleDescription()); m_Controls.removeButton->setEnabled(true); } else { m_Controls.descriptionPlainTextEdit->clear(); m_Controls.componentsListWidget->clear(); m_Controls.removeButton->setEnabled(false); } } void QmitkSimulationPreferencePage::OnRemoveButtonClicked() { QList selectedItems = m_Controls.pluginsTreeWidget->selectedItems(); if (selectedItems.isEmpty()) return; std::string path = selectedItems[0]->text(3).toStdString(); PluginManager& pluginManager = PluginManager::getInstance(); std::ostringstream errlog; if (pluginManager.unloadPlugin(path, &errlog)) { delete selectedItems[0]; } else { QMessageBox* messageBox = new QMessageBox(m_Control); messageBox->setIcon(QMessageBox::Critical); messageBox->setStandardButtons(QMessageBox::Ok); messageBox->setText(errlog.str().c_str()); messageBox->setWindowTitle("Error"); messageBox->show(); } } void QmitkSimulationPreferencePage::PerformCancel() { } bool QmitkSimulationPreferencePage::PerformOk() { PluginManager& pluginManager = PluginManager::getInstance(); PluginMap& pluginMap = pluginManager.getPluginMap(); std::string pluginPaths; for (PluginIterator it = pluginMap.begin(); it != pluginMap.end(); ++it) { if (!pluginPaths.empty()) pluginPaths += ";"; pluginPaths += it->first; } - m_Preferences->PutByteArray(PLUGIN_PATHS, pluginPaths); + m_Preferences->PutByteArray("plugin paths", pluginPaths); return true; } void QmitkSimulationPreferencePage::Update() { PluginManager& pluginManager = PluginManager::getInstance(); PluginMap& pluginMap = pluginManager.getPluginMap(); for (PluginIterator it = pluginMap.begin(); it != pluginMap.end(); ++it) { Plugin& plugin = it->second; QStringList pluginItem; pluginItem << plugin.getModuleName() << plugin.getModuleLicense() << plugin.getModuleVersion() << it->first.c_str(); m_Controls.pluginsTreeWidget->addTopLevelItem(new QTreeWidgetItem(pluginItem)); } } diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h index 484c855305..d1fb5743e9 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationPreferencePage.h @@ -1,57 +1,52 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkSimulationPreferencePage_h #define QmitkSimulationPreferencePage_h #include #include #include #include -berry::IPreferences::Pointer getSimulationPreferences(); -void initSOFAPlugins(berry::IPreferences::Pointer preferences = getSimulationPreferences()); - class SIMULATION_EXPORT QmitkSimulationPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: - static const std::string PLUGIN_PATHS; - QmitkSimulationPreferencePage(); ~QmitkSimulationPreferencePage(); void CreateQtControl(QWidget* parent); QWidget* GetQtControl() const; void Init(berry::IWorkbench::Pointer workbench); void PerformCancel(); bool PerformOk(); void Update(); private slots: void OnAddButtonClicked(); void OnPluginTreeWidgetItemSelectionChanged(); void OnRemoveButtonClicked(); private: berry::IPreferences::Pointer m_Preferences; QWidget* m_Control; Ui::QmitkSimulationPreferencePageControls m_Controls; }; #endif diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp index d54415ee0d..79016bbe98 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/QmitkSimulationView.cpp @@ -1,263 +1,254 @@ /*=================================================================== 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 "QmitkSimulationPreferencePage.h" #include "QmitkSimulationView.h" #include #include #include #include -#include #include -static void InitializeViews(mitk::IRenderWindowPart* renderWindowPart, mitk::Geometry3D* geometry) -{ - if (renderWindowPart == NULL || geometry == NULL) - return; - - mitk::IRenderingManager* renderingManager = renderWindowPart->GetRenderingManager(); - - if (renderingManager != NULL) - renderingManager->InitializeViews(geometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, true); -} - QmitkSimulationView::QmitkSimulationView() : m_SelectionWasRemovedFromDataStorage(false), m_Timer(this) { this->GetDataStorage()->RemoveNodeEvent.AddListener( mitk::MessageDelegate1(this, &QmitkSimulationView::OnNodeRemovedFromDataStorage)); connect(&m_Timer, SIGNAL(timeout()), this, SLOT(OnTimerTimeout())); - initSOFAPlugins(); } QmitkSimulationView::~QmitkSimulationView() { this->GetDataStorage()->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkSimulationView::OnNodeRemovedFromDataStorage)); } void QmitkSimulationView::CreateQtPartControl(QWidget* parent) { m_Controls.setupUi(parent); m_Controls.simulationComboBox->SetDataStorage(this->GetDataStorage()); m_Controls.simulationComboBox->SetPredicate(mitk::NodePredicateDataType::New("Simulation")); m_Controls.stepsRecordedLabel->hide(); connect(m_Controls.animateButton, SIGNAL(toggled(bool)), this, SLOT(OnAnimateButtonToggled(bool))); connect(m_Controls.recordButton, SIGNAL(toggled(bool)), this, SLOT(OnRecordButtonToggled(bool))); connect(m_Controls.resetButton, SIGNAL(clicked()), this, SLOT(OnResetButtonClicked())); connect(m_Controls.stepButton, SIGNAL(clicked()), this, SLOT(OnStepButtonClicked())); connect(m_Controls.simulationComboBox, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnSimulationComboBoxSelectionChanged(const mitk::DataNode*))); connect(m_Controls.dtSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDTSpinBoxValueChanged(double))); connect(m_Controls.snapshotButton, SIGNAL(clicked()), this, SLOT(OnSnapshotButtonClicked())); if (m_Controls.simulationComboBox->GetSelectedNode().IsNotNull()) this->OnSimulationComboBoxSelectionChanged(m_Controls.simulationComboBox->GetSelectedNode()); } void QmitkSimulationView::OnAnimateButtonToggled(bool toggled) { if (this->SetSelectionAsCurrentSimulation()) { mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); rootNode->getContext()->setAnimate(toggled); if (toggled) { m_Controls.stepButton->setEnabled(false); m_Timer.start(0); } } if (!toggled) { m_Timer.stop(); m_Controls.stepButton->setEnabled(true); } } void QmitkSimulationView::OnDTSpinBoxValueChanged(double value) { if (!this->SetSelectionAsCurrentSimulation()) return; mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); rootNode->setDt(value == 0.0 ? simulation->GetDefaultDT() : value); } void QmitkSimulationView::OnNodeRemovedFromDataStorage(const mitk::DataNode* node) { if (m_Selection.IsNotNull() && m_Selection.GetPointer() == node) m_SelectionWasRemovedFromDataStorage = true; } void QmitkSimulationView::OnRecordButtonToggled(bool toggled) { if (!toggled) { if (m_Record.IsNotNull()) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetData(m_Record); dataNode->SetName(m_Record->GetTimeSteps() == 1 ? "Snapshot" : "Record"); this->GetDataStorage()->Add(dataNode, m_Selection); - InitializeViews(this->GetRenderWindowPart(), m_Record->GetTimeSlicedGeometry()); + mitk::RenderingManager::GetInstance()->InitializeViews(m_Record->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); m_Record = NULL; } m_Controls.stepsRecordedLabel->hide(); m_Controls.stepsRecordedLabel->setText("0 steps recorded"); } else if (toggled) { m_Controls.stepsRecordedLabel->show(); } } void QmitkSimulationView::OnResetButtonClicked() { if (!this->SetSelectionAsCurrentSimulation()) return; if (m_Controls.recordButton->isChecked()) m_Controls.recordButton->setChecked(false); mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); m_Controls.dtSpinBox->setValue(0.0); sofaSimulation->reset(rootNode.get()); rootNode->setTime(0.0); rootNode->execute(sofa::core::ExecParams::defaultInstance()); simulation->GetDrawTool()->Reset(); this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); } void QmitkSimulationView::OnSimulationComboBoxSelectionChanged(const mitk::DataNode* node) { if (m_Controls.animateButton->isChecked()) m_Controls.animateButton->setChecked(false); if (m_SelectionWasRemovedFromDataStorage) { m_SelectionWasRemovedFromDataStorage = false; m_Selection = NULL; } if (m_Controls.recordButton->isChecked()) m_Controls.recordButton->setChecked(false); if (node != NULL) { m_Selection = m_Controls.simulationComboBox->GetSelectedNode(); m_Controls.sceneGroupBox->setEnabled(true); m_Controls.snapshotButton->setEnabled(true); - static_cast(node->GetData())->SetAsActiveSimulation(); + static_cast(m_Selection->GetData())->SetAsActiveSimulation(); } else { m_Selection = NULL; m_Controls.sceneGroupBox->setEnabled(false); m_Controls.snapshotButton->setEnabled(false); mitk::Simulation::SetActiveSimulation(NULL); } } void QmitkSimulationView::OnSnapshotButtonClicked() { if (!this->SetSelectionAsCurrentSimulation()) return; mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); mitk::Surface::Pointer snapshot = simulation->TakeSnapshot(); if (snapshot.IsNull()) return; mitk::DataNode::Pointer snapshotDataNode = mitk::DataNode::New(); snapshotDataNode->SetData(snapshot); snapshotDataNode->SetName("Snapshot"); this->GetDataStorage()->Add(snapshotDataNode, m_Selection); } void QmitkSimulationView::OnStepButtonClicked() { if (!this->SetSelectionAsCurrentSimulation()) return; - mitk::Simulation::Pointer simulation = dynamic_cast(m_Controls.simulationComboBox->GetSelectedNode()->GetData()); + mitk::Simulation::Pointer simulation = dynamic_cast(m_Selection->GetData()); sofa::simulation::Simulation::SPtr sofaSimulation = simulation->GetSimulation(); sofa::simulation::Node::SPtr rootNode = simulation->GetRootNode(); simulation->GetDrawTool()->Reset(); sofaSimulation->animate(rootNode.get(), rootNode->getDt()); this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS); if (m_Controls.recordButton->isChecked()) { if (m_Record.IsNull()) m_Record = mitk::Surface::New(); - simulation->AppendSnapshot(m_Record); - - unsigned int numSteps = m_Record->GetTimeSteps(); - QString plural = numSteps != 1 ? "s" : ""; + if (simulation->AppendSnapshot(m_Record)) + { + unsigned int numSteps = m_Record->GetTimeSteps(); + QString plural = numSteps != 1 ? "s" : ""; - m_Controls.stepsRecordedLabel->setText(QString("%1 step%2 recorded").arg(numSteps).arg(plural)); + m_Controls.stepsRecordedLabel->setText(QString("%1 step%2 recorded").arg(numSteps).arg(plural)); + } + else if (m_Record->GetTimeSteps() == 1) + { + m_Record = NULL; + } } } void QmitkSimulationView::SetFocus() { m_Controls.animateButton->setFocus(); } bool QmitkSimulationView::SetSelectionAsCurrentSimulation() const { if (m_Selection.IsNotNull()) { static_cast(m_Selection->GetData())->SetAsActiveSimulation(); return true; } return false; } void QmitkSimulationView::OnTimerTimeout() { this->OnStepButtonClicked(); } diff --git a/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp b/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp index d29e31d03b..9abd83b10a 100644 --- a/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.simulation/src/internal/org_mitk_gui_qt_simulation_Activator.cpp @@ -1,42 +1,34 @@ /*=================================================================== 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 "org_mitk_gui_qt_simulation_Activator.h" +#include "QmitkCreateSimulationAction.h" #include "QmitkSimulationPreferencePage.h" #include "QmitkSimulationView.h" -#include -#include #include void mitk::org_mitk_gui_qt_simulation_Activator::start(ctkPluginContext* context) { + BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateSimulationAction, context); BERRY_REGISTER_EXTENSION_CLASS(QmitkSimulationPreferencePage, context); BERRY_REGISTER_EXTENSION_CLASS(QmitkSimulationView, context); - - QmitkNodeDescriptorManager* nodeDescriptorManager = QmitkNodeDescriptorManager::GetInstance(); - - if (nodeDescriptorManager != NULL) - { - mitk::NodePredicateDataType::Pointer isSimulation = mitk::NodePredicateDataType::New("Simulation"); - nodeDescriptorManager->AddDescriptor(new QmitkNodeDescriptor("Simulation", ":/Simulation/icon.png", isSimulation, nodeDescriptorManager)); - } } void mitk::org_mitk_gui_qt_simulation_Activator::stop(ctkPluginContext*) { } Q_EXPORT_PLUGIN2(org_mitk_gui_qt_simulation, mitk::org_mitk_gui_qt_simulation_Activator) diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp index 3fde750bdb..6c3d3fffbc 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.cpp @@ -1,618 +1,663 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "QmitkToFUtilView.h" #include #include // Qt #include #include //QT headers #include #include #include // MITK #include #include #include #include #include #include #include #include #include //itk headers #include // VTK #include // ITK #include +#include const std::string QmitkToFUtilView::VIEW_ID = "org.mitk.views.tofutil"; //Constructor QmitkToFUtilView::QmitkToFUtilView() - : QmitkAbstractView() - , m_Controls(NULL), m_MultiWidget( NULL ) - , m_MitkDistanceImage(NULL), m_MitkAmplitudeImage(NULL), m_MitkIntensityImage(NULL), m_Surface(NULL) - , m_DistanceImageNode(NULL), m_AmplitudeImageNode(NULL), m_IntensityImageNode(NULL), m_RGBImageNode(NULL), m_SurfaceNode(NULL) - , m_ToFImageRecorder(NULL), m_ToFImageGrabber(NULL), m_ToFDistanceImageToSurfaceFilter(NULL), m_ToFCompositeFilter(NULL) - , m_2DDisplayCount(0) - , m_RealTimeClock(NULL) - , m_StepsForFramerate(100) - , m_2DTimeBefore(0.0) - , m_2DTimeAfter(0.0) - , m_CameraIntrinsics(NULL) + : QmitkAbstractView() + , m_Controls(NULL), m_MultiWidget( NULL ) + , m_MitkDistanceImage(NULL), m_MitkAmplitudeImage(NULL), m_MitkIntensityImage(NULL), m_Surface(NULL) + , m_DistanceImageNode(NULL), m_AmplitudeImageNode(NULL), m_IntensityImageNode(NULL), m_RGBImageNode(NULL), m_SurfaceNode(NULL) + , m_ToFImageRecorder(NULL), m_ToFImageGrabber(NULL), m_ToFDistanceImageToSurfaceFilter(NULL), m_ToFCompositeFilter(NULL) + , m_2DDisplayCount(0) + , m_RealTimeClock(NULL) + , m_StepsForFramerate(100) + , m_2DTimeBefore(0.0) + , m_2DTimeAfter(0.0) + , m_CameraIntrinsics(NULL) { - this->m_Frametimer = new QTimer(this); + this->m_Frametimer = new QTimer(this); - this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); - this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); - this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); - this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); + this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); + this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); + this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); + this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); } //Destructor, specifically calling OnToFCameraStopped() and OnToFCammeraDiconnected() QmitkToFUtilView::~QmitkToFUtilView() { - OnToFCameraStopped(); - OnToFCameraDisconnected(); + OnToFCameraStopped(); + OnToFCameraDisconnected(); } //Createing the PartControl Signal-Slot principal void QmitkToFUtilView::CreateQtPartControl( QWidget *parent ) { - // build up qt view, unless already done - if ( !m_Controls ) - { - // create GUI widgets from the Qt Designer's .ui file - m_Controls = new Ui::QmitkToFUtilViewControls; - m_Controls->setupUi( parent ); - - //Looking for Input and Defining reaction - connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); - - connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 - connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); - connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); - connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraSelected(const QString)), this, SLOT(OnToFCameraSelected(const QString)) ); - connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); - connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); - connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); - connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); - connect( (QObject*)(m_Controls->m_SurfaceCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnSurfaceCheckboxChecked(bool)) ); - connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); - connect( (QObject*)(m_Controls->m_KinectTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnKinectRGBTextureCheckBoxChecked(bool)) ); - - } + // build up qt view, unless already done + if ( !m_Controls ) + { + // create GUI widgets from the Qt Designer's .ui file + m_Controls = new Ui::QmitkToFUtilViewControls; + m_Controls->setupUi( parent ); + + //Looking for Input and Defining reaction + connect(m_Frametimer, SIGNAL(timeout()), this, SLOT(OnUpdateCamera())); + + connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(KinectAcquisitionModeChanged()), this, SLOT(OnKinectAcquisitionModeChanged()) ); // Todo in Widget2 + connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraConnected()), this, SLOT(OnToFCameraConnected()) ); + connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraDisconnected()), this, SLOT(OnToFCameraDisconnected()) ); + connect( (QObject*)(m_Controls->m_ToFConnectionWidget), SIGNAL(ToFCameraSelected(const QString)), this, SLOT(OnToFCameraSelected(const QString)) ); + connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStarted()), this, SLOT(OnToFCameraStarted()) ); + connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(ToFCameraStopped()), this, SLOT(OnToFCameraStopped()) ); + connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStarted()), this, SLOT(OnToFCameraStopped()) ); + connect( (QObject*)(m_Controls->m_ToFRecorderWidget), SIGNAL(RecordingStopped()), this, SLOT(OnToFCameraStarted()) ); + connect( (QObject*)(m_Controls->m_SurfaceCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnSurfaceCheckboxChecked(bool)) ); + connect( (QObject*)(m_Controls->m_TextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTextureCheckBoxChecked(bool)) ); + connect( (QObject*)(m_Controls->m_KinectTextureCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnKinectRGBTextureCheckBoxChecked(bool)) ); + + } } //SetFocus-Method -> actually seting Focus to the Recorder void QmitkToFUtilView::SetFocus() { - m_Controls->m_ToFRecorderWidget->setFocus(); + m_Controls->m_ToFRecorderWidget->setFocus(); } //Activated-Method->Generating RenderWindow void QmitkToFUtilView::Activated() { - //get the current RenderWindowPart or open a new one if there is none - if(this->GetRenderWindowPart(OPEN)) + //get the current RenderWindowPart or open a new one if there is none + if(this->GetRenderWindowPart(OPEN)) + { + mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); + if(linkedRenderWindowPart == 0) + { + MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; + } + else + { + linkedRenderWindowPart->EnableSlicingPlanes(false); + } + GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); + GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); + GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); + + this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); + + this->UseToFVisibilitySettings(true); + + if (this->m_ToFCompositeFilter) + { + m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); + } + if (this->GetDataStorage()) + { + m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); + } + + if (this->m_ToFImageGrabber.IsNull()) { - mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); - if(linkedRenderWindowPart == 0) - { - MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; - } - else - { - linkedRenderWindowPart->EnableSlicingPlanes(false); - } - GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOn(); - GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOn(); - GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOn(); - - this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); - - this->UseToFVisibilitySettings(true); - - if (this->m_ToFCompositeFilter) - { - m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); - } - if (this->GetDataStorage()) - { - m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); - } - - if (this->m_ToFImageGrabber.IsNull()) - { - m_Controls->m_ToFRecorderWidget->setEnabled(false); - m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); - m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); - m_Controls->tofMeasurementWidget->setEnabled(false); - m_Controls->SurfacePropertiesBox->setEnabled(false); - } + m_Controls->m_ToFRecorderWidget->setEnabled(false); + m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); + m_Controls->tofMeasurementWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); } + } } //ZomnnieView-Method -> Resetting GUI to default. Why not just QmitkToFUtilView()?! void QmitkToFUtilView::ActivatedZombieView(berry::IWorkbenchPartReference::Pointer /*zombieView*/) { - ResetGUIToDefault(); + ResetGUIToDefault(); } void QmitkToFUtilView::Deactivated() { } void QmitkToFUtilView::Visible() { } //Reset of the ToFUtilView void QmitkToFUtilView::Hidden() { - ResetGUIToDefault(); + ResetGUIToDefault(); } void QmitkToFUtilView::OnToFCameraConnected() { - MITK_DEBUG <<"OnToFCameraConnected"; - this->m_2DDisplayCount = 0; + MITK_DEBUG <<"OnToFCameraConnected"; + this->m_2DDisplayCount = 0; + + this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); + + // initialize surface generation + this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); + this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); + + // initialize ToFImageRecorder and ToFRecorderWidget + this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); + this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); + m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); + m_Controls->m_ToFRecorderWidget->setEnabled(true); + m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); + m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + + // initialize ToFCompositeFilterWidget + this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); + if (this->m_ToFCompositeFilter) + { + m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); + } + if (this->GetDataStorage()) + { + m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); + } - this->m_ToFImageGrabber = m_Controls->m_ToFConnectionWidget->GetToFImageGrabber(); + // initialize measurement widget + m_Controls->tofMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); - // initialize surface generation - this->m_ToFDistanceImageToSurfaceFilter = mitk::ToFDistanceImageToSurfaceFilter::New(); - this->m_ToFSurfaceVtkMapper3D = mitk::ToFSurfaceVtkMapper3D::New(); + this->m_RealTimeClock = mitk::RealTimeClock::New(); + this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); - // initialize ToFImageRecorder and ToFRecorderWidget - this->m_ToFImageRecorder = mitk::ToFImageRecorder::New(); - this->m_ToFImageRecorder->SetCameraDevice(this->m_ToFImageGrabber->GetCameraDevice()); - m_Controls->m_ToFRecorderWidget->SetParameter(this->m_ToFImageGrabber, this->m_ToFImageRecorder); - m_Controls->m_ToFRecorderWidget->setEnabled(true); - m_Controls->m_ToFRecorderWidget->ResetGUIToInitial(); - m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + this->RequestRenderWindowUpdate(); +} - // initialize ToFCompositeFilterWidget - this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); - if (this->m_ToFCompositeFilter) +void QmitkToFUtilView::ResetGUIToDefault() +{ + if(this->GetRenderWindowPart()) + { + mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); + if(linkedRenderWindowPart == 0) { - m_Controls->m_ToFCompositeFilterWidget->SetToFCompositeFilter(this->m_ToFCompositeFilter); + MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; } - if (this->GetDataStorage()) + else { - m_Controls->m_ToFCompositeFilterWidget->SetDataStorage(this->GetDataStorage()); + linkedRenderWindowPart->EnableSlicingPlanes(true); } + GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); + GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); + GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); + GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); + GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); + GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); - // initialize measurement widget - m_Controls->tofMeasurementWidget->InitializeWidget(this->GetRenderWindowPart()->GetQmitkRenderWindows(),this->GetDataStorage(), this->m_ToFDistanceImageToSurfaceFilter->GetCameraIntrinsics()); - - this->m_RealTimeClock = mitk::RealTimeClock::New(); - this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); + this->UseToFVisibilitySettings(false); + //global reinit + this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); this->RequestRenderWindowUpdate(); -} - -void QmitkToFUtilView::ResetGUIToDefault() -{ - if(this->GetRenderWindowPart()) - { - mitk::ILinkedRenderWindowPart* linkedRenderWindowPart = dynamic_cast(this->GetRenderWindowPart()); - if(linkedRenderWindowPart == 0) - { - MITK_ERROR << "No linked StdMultiWidget avaiable!!!"; - } - else - { - linkedRenderWindowPart->EnableSlicingPlanes(true); - } - GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); - GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SliceLockedOff(); - GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); - GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SliceLockedOff(); - GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); - GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SliceLockedOff(); - - this->UseToFVisibilitySettings(false); - - //global reinit - this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews(); - this->RequestRenderWindowUpdate(); - } + } } void QmitkToFUtilView::OnToFCameraDisconnected() { - m_Controls->m_ToFRecorderWidget->OnStop(); - m_Controls->m_ToFRecorderWidget->setEnabled(false); - m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); - m_Controls->tofMeasurementWidget->setEnabled(false); - m_Controls->SurfacePropertiesBox->setEnabled(false); - //clean up measurement widget - m_Controls->tofMeasurementWidget->CleanUpWidget(); + m_Controls->m_ToFRecorderWidget->OnStop(); + m_Controls->m_ToFRecorderWidget->setEnabled(false); + m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->tofMeasurementWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); + //clean up measurement widget + m_Controls->tofMeasurementWidget->CleanUpWidget(); } void QmitkToFUtilView::OnKinectAcquisitionModeChanged() { - if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) + if (m_ToFCompositeFilter.IsNotNull()&&m_ToFImageGrabber.IsNotNull()) + { + if (m_SelectedCamera.contains("Kinect")) { - if (m_SelectedCamera.contains("Kinect")) - { - if (m_ToFImageGrabber->GetBoolProperty("RGB")) - { - this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); - this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); - } - else if (m_ToFImageGrabber->GetBoolProperty("IR")) - { - this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); - this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); - } - } - this->UseToFVisibilitySettings(true); + if (m_ToFImageGrabber->GetBoolProperty("RGB")) + { + this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); + this->m_ToFDistanceImageToSurfaceFilter->SetInput(3,this->m_ToFImageGrabber->GetOutput(3)); + } + else if (m_ToFImageGrabber->GetBoolProperty("IR")) + { + this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); + this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); + } } + this->UseToFVisibilitySettings(true); + } } void QmitkToFUtilView::OnToFCameraStarted() { if (m_ToFImageGrabber.IsNotNull()) { // initialize camera intrinsics if (this->m_ToFImageGrabber->GetProperty("CameraIntrinsics")) { m_CameraIntrinsics = dynamic_cast(this->m_ToFImageGrabber->GetProperty("CameraIntrinsics"))->GetValue(); MITK_INFO << m_CameraIntrinsics->ToString(); } else { m_CameraIntrinsics = NULL; MITK_ERROR << "No camera intrinsics were found!"; } // initial update of image grabber this->m_ToFImageGrabber->Update(); - this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); - this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); - this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); - - // initial update of composite filter - this->m_ToFCompositeFilter->Update(); - this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(0); - this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); - - std::string rgbFileName; - m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); - - if ((m_SelectedCamera.contains("Kinect"))||(rgbFileName!="")) - { - //set the reconstruction mode for kinect - this->m_ToFDistanceImageToSurfaceFilter->SetReconstructionMode(mitk::ToFDistanceImageToSurfaceFilter::Kinect); - if (rgbFileName!="" || m_ToFImageGrabber->GetBoolProperty("RGB") ) - { - this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); - } - else if (m_ToFImageGrabber->GetBoolProperty("IR")) - { - this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); - } - } - else - { - this->m_RGBImageNode = NULL; - this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); - this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); - this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); - this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); - } - this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); - this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); - - this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); - this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); - this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); - this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); - this->m_SurfaceNode = ReplaceNodeData("Surface",m_Surface); - - this->UseToFVisibilitySettings(true); - - m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); - // initialize visualization widget - m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode); - // set distance image to measurement widget - m_Controls->tofMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); - - this->m_Frametimer->start(0); - - m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); - m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); - m_Controls->tofMeasurementWidget->setEnabled(true); - m_Controls->SurfacePropertiesBox->setEnabled(true); - - if (m_Controls->m_TextureCheckBox->isChecked()) - { - OnTextureCheckBoxChecked(true); - } - if (m_Controls->m_KinectTextureCheckBox->isChecked()) - { - OnKinectRGBTextureCheckBoxChecked(true); - } + this->m_ToFCompositeFilter->SetInput(0,this->m_ToFImageGrabber->GetOutput(0)); + this->m_ToFCompositeFilter->SetInput(1,this->m_ToFImageGrabber->GetOutput(1)); + this->m_ToFCompositeFilter->SetInput(2,this->m_ToFImageGrabber->GetOutput(2)); + + // initial update of composite filter + this->m_ToFCompositeFilter->Update(); + this->m_MitkDistanceImage = m_ToFCompositeFilter->GetOutput(0); + this->m_DistanceImageNode = ReplaceNodeData("Distance image",m_MitkDistanceImage); + + std::string rgbFileName; + m_ToFImageGrabber->GetCameraDevice()->GetStringProperty("RGBImageFileName",rgbFileName); + + bool hasRGBImage = false; + m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasRGBImage",hasRGBImage); + + bool hasIntensityImage = false; + m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasIntensityImage",hasIntensityImage); + + bool hasAmplitudeImage = false; + m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("HasAmplitudeImage",hasAmplitudeImage); + + bool KinectReconstructionMode = false; + m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("KinectReconstructionMode",KinectReconstructionMode); + if(KinectReconstructionMode) + { + //set the reconstruction mode for kinect + this->m_ToFDistanceImageToSurfaceFilter->SetReconstructionMode(mitk::ToFDistanceImageToSurfaceFilter::Kinect); } - m_Controls->m_TextureCheckBox->setEnabled(true); + + if(hasRGBImage || (rgbFileName!="")) + { + if(m_ToFImageGrabber->GetBoolProperty("IR")) + { + this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); + } + else + { + this->m_RGBImageNode = ReplaceNodeData("RGB image",this->m_ToFImageGrabber->GetOutput(3)); + } + } + else + { + this->m_RGBImageNode = NULL; + } + + if(hasAmplitudeImage) + { + this->m_MitkAmplitudeImage = m_ToFCompositeFilter->GetOutput(1); + this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); + } + + if(hasIntensityImage) + { + this->m_MitkIntensityImage = m_ToFCompositeFilter->GetOutput(2); + this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); + } + + // if ((rgbFileName!="") || hasRGBImage) + // { + + // } + // else + // { + + + // } + // this->m_AmplitudeImageNode = ReplaceNodeData("Amplitude image",m_MitkAmplitudeImage); + // this->m_IntensityImageNode = ReplaceNodeData("Intensity image",m_MitkIntensityImage); + + this->m_ToFDistanceImageToSurfaceFilter->SetInput(0,m_MitkDistanceImage); + this->m_ToFDistanceImageToSurfaceFilter->SetInput(1,m_MitkAmplitudeImage); + this->m_ToFDistanceImageToSurfaceFilter->SetInput(2,m_MitkIntensityImage); + this->m_Surface = this->m_ToFDistanceImageToSurfaceFilter->GetOutput(0); + this->m_SurfaceNode = ReplaceNodeData("Surface",m_Surface); + + this->UseToFVisibilitySettings(true); + + m_Controls->m_ToFCompositeFilterWidget->UpdateFilterParameter(); + // initialize visualization widget + m_Controls->m_ToFVisualisationSettingsWidget->Initialize(this->m_DistanceImageNode, this->m_AmplitudeImageNode, this->m_IntensityImageNode); + // set distance image to measurement widget + m_Controls->tofMeasurementWidget->SetDistanceImage(m_MitkDistanceImage); + + this->m_Frametimer->start(0); + + m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(true); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(true); + m_Controls->tofMeasurementWidget->setEnabled(true); + m_Controls->SurfacePropertiesBox->setEnabled(true); + + if (m_Controls->m_TextureCheckBox->isChecked()) + { + OnTextureCheckBoxChecked(true); + } + if (m_Controls->m_KinectTextureCheckBox->isChecked()) + { + OnKinectRGBTextureCheckBoxChecked(true); + } + } + m_Controls->m_TextureCheckBox->setEnabled(true); } void QmitkToFUtilView::OnToFCameraStopped() { - m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); - m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); - m_Controls->SurfacePropertiesBox->setEnabled(false); + m_Controls->m_ToFVisualisationSettingsWidget->setEnabled(false); + m_Controls->m_ToFCompositeFilterWidget->setEnabled(false); + m_Controls->SurfacePropertiesBox->setEnabled(false); - this->m_Frametimer->stop(); + this->m_Frametimer->stop(); } void QmitkToFUtilView::OnToFCameraSelected(const QString selected) { - m_SelectedCamera = selected; - if ((selected.contains("CamBoard"))||(selected.contains("O3D"))) - { - MITK_INFO<<"Surface representation currently not available for CamBoard and O3. Intrinsic parameters missing."; - this->m_Controls->m_SurfaceCheckBox->setEnabled(false); - this->m_Controls->m_TextureCheckBox->setEnabled(false); - this->m_Controls->m_KinectTextureCheckBox->setEnabled(false); - this->m_Controls->m_SurfaceCheckBox->setChecked(false); - this->m_Controls->m_TextureCheckBox->setChecked(false); - this->m_Controls->m_KinectTextureCheckBox->setChecked(false); - } - else - { - this->m_Controls->m_SurfaceCheckBox->setEnabled(true); - this->m_Controls->m_TextureCheckBox->setEnabled(true); - this->m_Controls->m_KinectTextureCheckBox->setEnabled(true); - } + m_SelectedCamera = selected; + if ((selected.contains("CamBoard"))||(selected.contains("O3D"))) + { + MITK_INFO<<"Surface representation currently not available for CamBoard and O3. Intrinsic parameters missing."; + this->m_Controls->m_SurfaceCheckBox->setEnabled(false); + this->m_Controls->m_TextureCheckBox->setEnabled(false); + this->m_Controls->m_KinectTextureCheckBox->setEnabled(false); + this->m_Controls->m_SurfaceCheckBox->setChecked(false); + this->m_Controls->m_TextureCheckBox->setChecked(false); + this->m_Controls->m_KinectTextureCheckBox->setChecked(false); + } + else + { + this->m_Controls->m_SurfaceCheckBox->setEnabled(true); + this->m_Controls->m_TextureCheckBox->setEnabled(true); + this->m_Controls->m_KinectTextureCheckBox->setEnabled(true); + } } void QmitkToFUtilView::OnSurfaceCheckboxChecked(bool checked) { - if(checked) - { - //initialize the surface once - MITK_DEBUG << "OnSurfaceCheckboxChecked true"; - this->m_SurfaceNode->SetData(this->m_Surface); - this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); - - //we need to initialize (reinit) the surface, to make it fit into the renderwindow - this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( - this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); - - //the default camera position is rather unfortunate, - //that's why we set our own position according to the surface center - mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); - vtkCamera* camera3d = GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera(); - //1m distance to camera should be a nice default value for most cameras - camera3d->SetPosition(0,0,-1000); - camera3d->SetViewUp(0,-1,0); - camera3d->SetFocalPoint(0,0,surfaceCenter[2]); - camera3d->SetViewAngle(40); - camera3d->SetClippingRange(1, 10000); - } + if(checked) + { + //initialize the surface once + MITK_DEBUG << "OnSurfaceCheckboxChecked true"; + this->m_SurfaceNode->SetData(this->m_Surface); + this->m_SurfaceNode->SetMapper(mitk::BaseRenderer::Standard3D, m_ToFSurfaceVtkMapper3D); + + //we need to initialize (reinit) the surface, to make it fit into the renderwindow + this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( + this->m_Surface->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_3DWINDOWS, true); + + //the default camera position is rather unfortunate, + //that's why we set our own position according to the surface center + mitk::Point3D surfaceCenter= this->m_Surface->GetGeometry()->GetCenter(); + vtkCamera* camera3d = GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer()->GetActiveCamera(); + //1m distance to camera should be a nice default value for most cameras + camera3d->SetPosition(0,0,-1000); + camera3d->SetViewUp(0,-1,0); + camera3d->SetFocalPoint(0,0,surfaceCenter[2]); + camera3d->SetViewAngle(40); + camera3d->SetClippingRange(1, 10000); + } } void QmitkToFUtilView::OnUpdateCamera() { - //##### Code for surface ##### - if (m_Controls->m_SurfaceCheckBox->isChecked()) + //##### Code for surface ##### + if (m_Controls->m_SurfaceCheckBox->isChecked()) + { + // update surface + m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); + + //if the user wants to see the texture, it has to be updated for every frame + if(m_Controls->m_KinectTextureCheckBox->isChecked() && (m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) { - // update surface - m_ToFDistanceImageToSurfaceFilter->SetTextureIndex(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedImageIndex()); - - //if the user wants to see the texture, it has to be updated for every frame - if(m_Controls->m_KinectTextureCheckBox->isChecked() && (m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) - { - //remove the vtkScalarsToColors object, if there was one. - this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(NULL); - //set RGB-iamge as texture - this->m_ToFSurfaceVtkMapper3D->SetTexture((this->m_ToFImageGrabber->GetOutput(3)->GetVtkImageData())); - } - else - { - //we have to delete the texture, if there was one. - this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); - //get the colortransferfunction from the visualization widget - this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction()); - } - //update pipeline - this->m_Surface->Update(); + //remove the vtkScalarsToColors object, if there was one. + this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(NULL); + //set RGB-iamge as texture + this->m_ToFSurfaceVtkMapper3D->SetTexture((this->m_ToFImageGrabber->GetOutput(3)->GetVtkImageData())); } - //##### End code for surface ##### else { - // update pipeline - this->m_MitkDistanceImage->Update(); + //we have to delete the texture, if there was one. + this->m_ToFSurfaceVtkMapper3D->SetTexture(NULL); + //get the colortransferfunction from the visualization widget + this->m_ToFSurfaceVtkMapper3D->SetVtkScalarsToColors(m_Controls->m_ToFVisualisationSettingsWidget->GetSelectedColorTransferFunction()); } + //update pipeline + this->m_Surface->Update(); + } + //##### End code for surface ##### + else + { + // update pipeline + this->m_MitkDistanceImage->Update(); + } - this->RequestRenderWindowUpdate(); + this->RequestRenderWindowUpdate(); - this->m_2DDisplayCount++; - if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) - { - this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; - MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter/1000); - this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); - } + this->m_2DDisplayCount++; + if ((this->m_2DDisplayCount % this->m_StepsForFramerate) == 0) + { + this->m_2DTimeAfter = this->m_RealTimeClock->GetCurrentStamp() - this->m_2DTimeBefore; + MITK_INFO << " 2D-Display-framerate (fps): " << this->m_StepsForFramerate / (this->m_2DTimeAfter/1000); + this->m_2DTimeBefore = this->m_RealTimeClock->GetCurrentStamp(); + } } void QmitkToFUtilView::OnTextureCheckBoxChecked(bool checked) { - if(m_SurfaceNode.IsNotNull()) + if(m_SurfaceNode.IsNotNull()) + { + if (checked) + { + this->m_SurfaceNode->SetBoolProperty("scalar visibility", true); + } + else { - if (checked) - { - this->m_SurfaceNode->SetBoolProperty("scalar visibility", true); - } - else - { - this->m_SurfaceNode->SetBoolProperty("scalar visibility", false); - } + this->m_SurfaceNode->SetBoolProperty("scalar visibility", false); } + } } void QmitkToFUtilView::OnKinectRGBTextureCheckBoxChecked(bool checked) { - if((m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) + if((m_SelectedCamera.contains("Kinect")) && (m_ToFImageGrabber->GetBoolProperty("RGB"))) + { + if (checked) { - if (checked) - { - //define the dimensions of the texture - this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(0)); - this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(1)); - } + //define the dimensions of the texture + this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageWidth(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(0)); + this->m_ToFDistanceImageToSurfaceFilter->SetTextureImageHeight(this->m_ToFImageGrabber->GetOutput(3)->GetDimension(1)); } + } } void QmitkToFUtilView::OnChangeCoronalWindowOutput(int index) { - this->OnToFCameraStopped(); - if(index == 0) - { - if(this->m_IntensityImageNode.IsNotNull()) - this->m_IntensityImageNode->SetVisibility(false); - if(this->m_RGBImageNode.IsNotNull()) - this->m_RGBImageNode->SetVisibility(true); - } - else if(index == 1) - { - if(this->m_IntensityImageNode.IsNotNull()) - this->m_IntensityImageNode->SetVisibility(true); - if(this->m_RGBImageNode.IsNotNull()) - this->m_RGBImageNode->SetVisibility(false); - } - this->RequestRenderWindowUpdate(); - this->OnToFCameraStarted(); + this->OnToFCameraStopped(); + if(index == 0) + { + if(this->m_IntensityImageNode.IsNotNull()) + this->m_IntensityImageNode->SetVisibility(false); + if(this->m_RGBImageNode.IsNotNull()) + this->m_RGBImageNode->SetVisibility(true); + } + else if(index == 1) + { + if(this->m_IntensityImageNode.IsNotNull()) + this->m_IntensityImageNode->SetVisibility(true); + if(this->m_RGBImageNode.IsNotNull()) + this->m_RGBImageNode->SetVisibility(false); + } + this->RequestRenderWindowUpdate(); + this->OnToFCameraStarted(); } mitk::DataNode::Pointer QmitkToFUtilView::ReplaceNodeData( std::string nodeName, mitk::BaseData* data ) { - mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); - if (node.IsNull()) - { - node = mitk::DataNode::New(); - node->SetData(data); - node->SetName(nodeName); - node->SetBoolProperty("binary",false); - this->GetDataStorage()->Add(node); - } - else - { - node->SetData(data); - } - return node; + mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(nodeName); + if (node.IsNull()) + { + node = mitk::DataNode::New(); + node->SetData(data); + node->SetName(nodeName); + node->SetBoolProperty("binary",false); + this->GetDataStorage()->Add(node); + } + else + { + node->SetData(data); + } + return node; } void QmitkToFUtilView::UseToFVisibilitySettings(bool useToF) { - // set node properties - if (m_DistanceImageNode.IsNotNull()) + //We need this property for every node. + mitk::RenderingModeProperty::Pointer renderingModePropertyForTransferFunction = mitk::RenderingModeProperty::New(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); + + // set node properties + if (m_DistanceImageNode.IsNotNull()) + { + this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); + this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_DistanceImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); + } + if (m_AmplitudeImageNode.IsNotNull()) + { + if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("RGB"))) { - this->m_DistanceImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); - this->m_DistanceImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); - this->m_DistanceImageNode->SetBoolProperty("use color",!useToF); - this->m_DistanceImageNode->GetPropertyList()->DeleteProperty("LookupTable"); + this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } - if (m_AmplitudeImageNode.IsNotNull()) + else { - if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("RGB"))) - { - this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); - } - else - { - this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - } - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); - this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); - this->m_AmplitudeImageNode->SetBoolProperty("use color",!useToF); - this->m_AmplitudeImageNode->GetPropertyList()->DeleteProperty("LookupTable"); + this->m_AmplitudeImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); } - if (m_IntensityImageNode.IsNotNull()) + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("coronal")->GetRenderWindow() ) ); + this->m_AmplitudeImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_AmplitudeImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); + } + if (m_IntensityImageNode.IsNotNull()) + { + if (m_SelectedCamera.contains("Kinect")) { - if (m_SelectedCamera.contains("Kinect")) - { - this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); - } - else - { - this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); - this->m_IntensityImageNode->SetBoolProperty("use color",!useToF); - this->m_IntensityImageNode->GetPropertyList()->DeleteProperty("LookupTable"); - } + this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } - if ((m_RGBImageNode.IsNotNull())) + else { - if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("IR"))) - { - this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); - } - else - { - this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); - this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); - } + this->m_IntensityImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); + this->m_IntensityImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + this->m_IntensityImageNode->SetProperty("Image Rendering.Mode", renderingModePropertyForTransferFunction); } - // initialize images - if (m_MitkDistanceImage.IsNotNull()) + } + if ((m_RGBImageNode.IsNotNull())) + { + if ((m_SelectedCamera.contains("Kinect"))&&(m_ToFImageGrabber->GetBoolProperty("IR"))) { - this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( - this->m_MitkDistanceImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); + this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( false )); } - if(this->m_SurfaceNode.IsNotNull()) + else + { + this->m_RGBImageNode->SetProperty( "visible" , mitk::BoolProperty::New( true )); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("axial")->GetRenderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("sagittal")->GetRenderWindow() ) ); + this->m_RGBImageNode->SetVisibility( !useToF, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + } + } + // initialize images + if (m_MitkDistanceImage.IsNotNull()) + { + this->GetRenderWindowPart()->GetRenderingManager()->InitializeViews( + this->m_MitkDistanceImage->GetTimeSlicedGeometry(), mitk::RenderingManager::REQUEST_UPDATE_2DWINDOWS, true); + } + if(this->m_SurfaceNode.IsNotNull()) + { + QHash renderWindowHashMap = this->GetRenderWindowPart()->GetQmitkRenderWindows(); + QHashIterator i(renderWindowHashMap); + while (i.hasNext()){ + i.next(); + this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->GetRenderWindow()) ); + } + this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + } + //disable/enable gradient background + this->GetRenderWindowPart()->EnableDecorations(!useToF, QStringList(QString("background"))); + + if((this->m_RGBImageNode.IsNotNull())) + { + bool RGBImageHasDifferentResolution = false; + m_ToFImageGrabber->GetCameraDevice()->GetBoolProperty("RGBImageHasDifferentResolution",RGBImageHasDifferentResolution); + if(RGBImageHasDifferentResolution) { - QHash renderWindowHashMap = this->GetRenderWindowPart()->GetQmitkRenderWindows(); - QHashIterator i(renderWindowHashMap); - while (i.hasNext()){ - i.next(); - this->m_SurfaceNode->SetVisibility( false, mitk::BaseRenderer::GetInstance(i.value()->GetRenderWindow()) ); - } - this->m_SurfaceNode->SetVisibility( true, mitk::BaseRenderer::GetInstance(GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderWindow() ) ); + //update the display geometry by using the RBG image node. Only for renderwindow coronal + mitk::RenderingManager::GetInstance()->InitializeView( GetRenderWindowPart()->GetRenderWindow("coronal")->GetRenderWindow(), this->m_RGBImageNode->GetData()->GetGeometry() ); } - //disable/enable gradient background - this->GetRenderWindowPart()->EnableDecorations(!useToF, QStringList(QString("background"))); + } } diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h index 86f31022e3..f7f1067ec8 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilView.h @@ -1,193 +1,193 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkToFUtilView_h #define QmitkToFUtilView_h #include #include #include #include #include class QTimer; #include #include #include #include #include #include #include #include #include /*! \brief QmitkToFUtilView Application that allows simple playing, recording, visualization, processing and measurement of Time-of-Flight (ToF) data. Currently the following features are implemented:
  • Connecting and showing ToF data from various cameras (PMD CamCube 2/3, PMD CamBoard, PMD O3, MESA SwissRanger)
  • Recording and playing of ToF data
  • Color coded visualization of ToF images
  • Preprocessing of the distance data: Threshold, median, average and bilateral filtering; surface generation
  • Simple measurement and PointSet definition
\sa QmitkFunctionality \ingroup Functionalities */ class QmitkToFUtilView : public QmitkAbstractView, public mitk::IZombieViewPart { - // this is needed for all Qt objects that should have a Qt meta-object - // (everything that derives from QObject and wants to have signal/slots) - Q_OBJECT + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT public: - static const std::string VIEW_ID; + static const std::string VIEW_ID; - QmitkToFUtilView(); - ~QmitkToFUtilView(); + QmitkToFUtilView(); + ~QmitkToFUtilView(); - virtual void CreateQtPartControl(QWidget *parent); - /// \brief Called when the functionality is activated. - virtual void Activated(); - /// \brief Called when the functionality is deactivated. In this case the zombie view of this functionality becomes active! - virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer zombieView); + virtual void CreateQtPartControl(QWidget *parent); + /// \brief Called when the functionality is activated. + virtual void Activated(); + /// \brief Called when the functionality is deactivated. In this case the zombie view of this functionality becomes active! + virtual void ActivatedZombieView(berry::IWorkbenchPartReference::Pointer zombieView); - virtual void Deactivated(); - virtual void Visible(); - virtual void Hidden(); + virtual void Deactivated(); + virtual void Visible(); + virtual void Hidden(); - void SetFocus(); + void SetFocus(); protected slots: - /*! + /*! \brief Slot triggered from the timer to update the images and visualization */ - void OnUpdateCamera(); - /*! + void OnUpdateCamera(); + /*! \brief Slot called when the "Connect" button of the ConnectionWidget is pressed */ - void OnToFCameraConnected(); - /*! + void OnToFCameraConnected(); + /*! \brief Slot called when the "Disconnect" button of the ConnectionWidget is pressed */ - void OnToFCameraDisconnected(); - /*! + void OnToFCameraDisconnected(); + /*! \brief Slot called when the camera selection in the ConnectionWidget has changed */ - void OnToFCameraSelected(const QString selected); - /*! + void OnToFCameraSelected(const QString selected); + /*! \brief Slot called when the "Start" button of the RecorderWidget is pressed */ - void OnToFCameraStarted(); - /*! + void OnToFCameraStarted(); + /*! \brief Slot called when the "Stop" button of the RecorderWidget is pressed */ - void OnToFCameraStopped(); - /*! + void OnToFCameraStopped(); + /*! \brief Slot invoked when the texture checkbox is checked. Enables the scalar visibility of the surface */ - /** + /** * @brief OnSurfaceCheckboxChecked Slot beeing called, if the "surface"-checkbox is clicked. This method initializes the surface once, if it is necessary. * @param checked Is it checked or not? */ - void OnSurfaceCheckboxChecked(bool checked); + void OnSurfaceCheckboxChecked(bool checked); - void OnTextureCheckBoxChecked(bool checked); - /*! + void OnTextureCheckBoxChecked(bool checked); + /*! \brief Slot invoked when the video texture checkbox is checked. Enables the texture of the surface */ - void OnKinectRGBTextureCheckBoxChecked(bool checked); - /*! + void OnKinectRGBTextureCheckBoxChecked(bool checked); + /*! \brief Slot invoked when user alters the coronal window input from RGB to Intensity or vice versa. */ - void OnChangeCoronalWindowOutput(int index); - /*! + void OnChangeCoronalWindowOutput(int index); + /*! \brief Slot invoked when acquisition mode of Kinect is changed */ - void OnKinectAcquisitionModeChanged(); + void OnKinectAcquisitionModeChanged(); protected: - /*! + /*! \brief initialize the visibility settings of ToF data (images + surface) \param useToF true: distance image: widget1, amplitude image: widget 2, intensity image: widget 3; false: standard */ - void UseToFVisibilitySettings(bool useToF); + void UseToFVisibilitySettings(bool useToF); - Ui::QmitkToFUtilViewControls* m_Controls; + Ui::QmitkToFUtilViewControls* m_Controls; - QmitkStdMultiWidget* m_MultiWidget; + QmitkStdMultiWidget* m_MultiWidget; - QTimer* m_Frametimer; ///< Timer used to continuously update the images + QTimer* m_Frametimer; ///< Timer used to continuously update the images - QString m_SelectedCamera; ///< String holding the selected camera + QString m_SelectedCamera; ///< String holding the selected camera - mitk::Image::Pointer m_MitkDistanceImage; ///< member holding a pointer to the distance image of the selected camera - mitk::Image::Pointer m_MitkAmplitudeImage; ///< member holding a pointer to the amplitude image of the selected camera - mitk::Image::Pointer m_MitkIntensityImage; ///< member holding a pointer to the intensity image of the selected camera - mitk::Surface::Pointer m_Surface; ///< member holding a pointer to the surface generated from the distance image of the selected camera + mitk::Image::Pointer m_MitkDistanceImage; ///< member holding a pointer to the distance image of the selected camera + mitk::Image::Pointer m_MitkAmplitudeImage; ///< member holding a pointer to the amplitude image of the selected camera + mitk::Image::Pointer m_MitkIntensityImage; ///< member holding a pointer to the intensity image of the selected camera + mitk::Surface::Pointer m_Surface; ///< member holding a pointer to the surface generated from the distance image of the selected camera - mitk::DataNode::Pointer m_DistanceImageNode; ///< DataNode holding the distance image of the selected camera - mitk::DataNode::Pointer m_AmplitudeImageNode; ///< DataNode holding the amplitude image of the selected camera - mitk::DataNode::Pointer m_IntensityImageNode; ///< DataNode holding the intensity image of the selected camera - mitk::DataNode::Pointer m_RGBImageNode; ///< DataNode holding the rgb image of the selected camera - mitk::DataNode::Pointer m_SurfaceNode; ///< DataNode holding the surface generated from the distanc image of the selected camera + mitk::DataNode::Pointer m_DistanceImageNode; ///< DataNode holding the distance image of the selected camera + mitk::DataNode::Pointer m_AmplitudeImageNode; ///< DataNode holding the amplitude image of the selected camera + mitk::DataNode::Pointer m_IntensityImageNode; ///< DataNode holding the intensity image of the selected camera + mitk::DataNode::Pointer m_RGBImageNode; ///< DataNode holding the rgb image of the selected camera + mitk::DataNode::Pointer m_SurfaceNode; ///< DataNode holding the surface generated from the distanc image of the selected camera - // ToF processing and recording filter - mitk::ToFImageRecorder::Pointer m_ToFImageRecorder; ///< ToF image recorder used for lossless recording of ToF image data - mitk::ToFImageGrabber::Pointer m_ToFImageGrabber; ///< Source of a ToF image processing pipeline. Provides pointers to distance, amplitude and intensity image - mitk::ToFDistanceImageToSurfaceFilter::Pointer m_ToFDistanceImageToSurfaceFilter; ///< Filter for calculating a surface representation from a given distance image - mitk::ToFCompositeFilter::Pointer m_ToFCompositeFilter; ///< Filter combining several processing steps (thresholding, Median filtering, Bilateral filtering) + // ToF processing and recording filter + mitk::ToFImageRecorder::Pointer m_ToFImageRecorder; ///< ToF image recorder used for lossless recording of ToF image data + mitk::ToFImageGrabber::Pointer m_ToFImageGrabber; ///< Source of a ToF image processing pipeline. Provides pointers to distance, amplitude and intensity image + mitk::ToFDistanceImageToSurfaceFilter::Pointer m_ToFDistanceImageToSurfaceFilter; ///< Filter for calculating a surface representation from a given distance image + mitk::ToFCompositeFilter::Pointer m_ToFCompositeFilter; ///< Filter combining several processing steps (thresholding, Median filtering, Bilateral filtering) - int m_2DDisplayCount; ///< member used to determine whether frame rate output should be shown - // members for calculating the frame rate - mitk::RealTimeClock::Pointer m_RealTimeClock; ///< real time clock used to calculate the display framerate - int m_StepsForFramerate; ///< number of steps used for calculating the display framerate - double m_2DTimeBefore; ///< holds the time stamp at the beginning of the display framerate measurement - double m_2DTimeAfter; ///< holds the time stamp at the end of the display framerate measurement + int m_2DDisplayCount; ///< member used to determine whether frame rate output should be shown + // members for calculating the frame rate + mitk::RealTimeClock::Pointer m_RealTimeClock; ///< real time clock used to calculate the display framerate + int m_StepsForFramerate; ///< number of steps used for calculating the display framerate + double m_2DTimeBefore; ///< holds the time stamp at the beginning of the display framerate measurement + double m_2DTimeAfter; ///< holds the time stamp at the end of the display framerate measurement - mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< member holding the intrinsic parameters of the camera + mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< member holding the intrinsic parameters of the camera private: - /*! + /*! \brief helper method to replace data of the specified node. If node does not exist it will be created \param nodeName Name of the node \param data Data object to be replaced \return returns the node */ - mitk::DataNode::Pointer ReplaceNodeData(std::string nodeName, mitk::BaseData* data); + mitk::DataNode::Pointer ReplaceNodeData(std::string nodeName, mitk::BaseData* data); - void ProcessVideoTransform(); + void ProcessVideoTransform(); - /*! + /*! \brief Reset all GUI related things to default. E.g. show sagittal and coronal slices in the renderwindows. */ - void ResetGUIToDefault(); + void ResetGUIToDefault(); - mitk::ToFSurfaceVtkMapper3D::Pointer m_ToFSurfaceVtkMapper3D; + mitk::ToFSurfaceVtkMapper3D::Pointer m_ToFSurfaceVtkMapper3D; }; #endif // _QMITKTOFUTILVIEW_H_INCLUDED diff --git a/Plugins/org.mitk.simulation/CMakeLists.txt b/Plugins/org.mitk.simulation/CMakeLists.txt new file mode 100644 index 0000000000..66f2590747 --- /dev/null +++ b/Plugins/org.mitk.simulation/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_simulation) + +MACRO_CREATE_MITK_CTK_PLUGIN( + EXPORT_DIRECTIVE SIMULATION_INIT_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDENCIES Properties Qmitk Simulation +) diff --git a/Plugins/org.mitk.simulation/files.cmake b/Plugins/org.mitk.simulation/files.cmake new file mode 100644 index 0000000000..cfe1fc0b72 --- /dev/null +++ b/Plugins/org.mitk.simulation/files.cmake @@ -0,0 +1,31 @@ +set(SRC_CPP_FILES + mitkGetSimulationPreferences.cpp +) + +set(INTERNAL_CPP_FILES + org_mitk_simulation_Activator.cpp +) + +set(MOC_H_FILES + src/internal/org_mitk_simulation_Activator.h +) + +set(CACHED_RESOURCE_FILES + resources/simulation.png + resources/simulationTemplate.png +) + +set(QRC_FILES + resources/Simulation.qrc +) + +set(CPP_FILES +) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach() + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach() diff --git a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake b/Plugins/org.mitk.simulation/manifest_headers.cmake similarity index 52% copy from Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake copy to Plugins/org.mitk.simulation/manifest_headers.cmake index 912e7b0cf4..893c3d887f 100644 --- a/Plugins/org.mitk.gui.qt.simulation/manifest_headers.cmake +++ b/Plugins/org.mitk.simulation/manifest_headers.cmake @@ -1,5 +1,6 @@ -set(Plugin-Name "MITK Simulation") +set(Plugin-Name "MITK Simulation Initialization") set(Plugin-Version "0.1") set(Plugin-Vendor "DKFZ, Medical and Biological Informatics") set(Plugin-ContactAddress "http://www.mitk.org") -set(Require-Plugin org.mitk.gui.qt.common) +set(Require-Plugin org.mitk.gui.common) +set(Plugin-ActivationPolicy eager) diff --git a/Plugins/org.mitk.simulation/resources/Simulation.qrc b/Plugins/org.mitk.simulation/resources/Simulation.qrc new file mode 100644 index 0000000000..00b2d1b9fb --- /dev/null +++ b/Plugins/org.mitk.simulation/resources/Simulation.qrc @@ -0,0 +1,8 @@ + + + simulation.png + + + simulationTemplate.png + + diff --git a/Plugins/org.mitk.simulation/resources/simulation.png b/Plugins/org.mitk.simulation/resources/simulation.png new file mode 100644 index 0000000000..3e0ce703ea Binary files /dev/null and b/Plugins/org.mitk.simulation/resources/simulation.png differ diff --git a/Plugins/org.mitk.simulation/resources/simulationTemplate.png b/Plugins/org.mitk.simulation/resources/simulationTemplate.png new file mode 100644 index 0000000000..fdf69c0bbd Binary files /dev/null and b/Plugins/org.mitk.simulation/resources/simulationTemplate.png differ diff --git a/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.cpp b/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.cpp new file mode 100644 index 0000000000..06c1e94ab4 --- /dev/null +++ b/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +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 "org_mitk_simulation_Activator.h" +#include +#include +#include +#include +#include +#include +#include +#include + +template +T* GetPropertyService(ctkPluginContext* context) +{ + if (context == NULL) + return NULL; + + mitk::LoadPropertiesModule(); + + ctkServiceReference serviceRef = context->getServiceReference(); + + return serviceRef + ? context->getService(serviceRef) + : NULL; +} + +static void InitSOFAPlugins() +{ + berry::IPreferences::Pointer preferences = mitk::GetSimulationPreferences(); + + if (preferences.IsNull()) + return; + + QString pluginPaths = preferences->GetByteArray("plugin paths", "").c_str(); + + if (pluginPaths.isEmpty()) + return; + + QStringList pluginPathList = pluginPaths.split(';', QString::SkipEmptyParts); + QStringListIterator it(pluginPathList); + + typedef sofa::helper::system::PluginManager PluginManager; + PluginManager& pluginManager = PluginManager::getInstance(); + + while (it.hasNext()) + { + std::string path = it.next().toStdString(); + std::ostringstream errlog; + + pluginManager.loadPlugin(path, &errlog); + + if (errlog.str().empty()) + pluginManager.getPluginMap()[path].initExternalModule(); + } +} + +static void SetPropertyFilters(ctkPluginContext* context) +{ + mitk::PropertyFilters* propertyFilters = GetPropertyService(context); + + if (propertyFilters == NULL) + return; + + mitk::PropertyFilter simulationFilter; + + simulationFilter.AddEntry("layer", mitk::PropertyFilter::Blacklist); + simulationFilter.AddEntry("name", mitk::PropertyFilter::Blacklist); + simulationFilter.AddEntry("path", mitk::PropertyFilter::Blacklist); + simulationFilter.AddEntry("selected", mitk::PropertyFilter::Blacklist); + simulationFilter.AddEntry("visible", mitk::PropertyFilter::Blacklist); + + propertyFilters->AddFilter("Simulation", simulationFilter); + propertyFilters->AddFilter("SimulationTemplate", simulationFilter); +} + +void mitk::org_mitk_simulation_Activator::start(ctkPluginContext* context) +{ + RegisterSimulationObjectFactory(); + InitSOFAPlugins(); + SetPropertyFilters(context); + + QmitkNodeDescriptorManager* nodeDescriptorManager = QmitkNodeDescriptorManager::GetInstance(); + + if (nodeDescriptorManager != NULL) + { + mitk::NodePredicateDataType::Pointer isSimulation = mitk::NodePredicateDataType::New("Simulation"); + nodeDescriptorManager->AddDescriptor(new QmitkNodeDescriptor("Simulation", ":/Simulation/simulation.png", isSimulation, nodeDescriptorManager)); + + mitk::NodePredicateDataType::Pointer isSimulationTemplate = mitk::NodePredicateDataType::New("SimulationTemplate"); + nodeDescriptorManager->AddDescriptor(new QmitkNodeDescriptor("SimulationTemplate", ":/Simulation/simulationTemplate.png", isSimulationTemplate, nodeDescriptorManager)); + } +} + +void mitk::org_mitk_simulation_Activator::stop(ctkPluginContext*) +{ +} + +Q_EXPORT_PLUGIN2(org_mitk_simulation, mitk::org_mitk_simulation_Activator) diff --git a/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.h b/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.h new file mode 100644 index 0000000000..ffcb990bdd --- /dev/null +++ b/Plugins/org.mitk.simulation/src/internal/org_mitk_simulation_Activator.h @@ -0,0 +1,34 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef org_mitk_simulation_Activator_h +#define org_mitk_simulation_Activator_h + +#include + +namespace mitk +{ + class org_mitk_simulation_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_INTERFACES(ctkPluginActivator) + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + }; +} +#endif diff --git a/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.cpp b/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.cpp new file mode 100644 index 0000000000..d10b8403ac --- /dev/null +++ b/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.cpp @@ -0,0 +1,28 @@ +/*=================================================================== + +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 "mitkGetSimulationPreferences.h" +#include +#include +#include + +berry::IPreferences::Pointer mitk::GetSimulationPreferences() +{ + berry::ServiceRegistry& serviceRegistry = berry::Platform::GetServiceRegistry(); + berry::IPreferencesService::Pointer preferencesService = serviceRegistry.GetServiceById(berry::IPreferencesService::ID); + berry::IPreferences::Pointer preferences = preferencesService->GetSystemPreferences(); + return preferences->Node("/org.mitk.views.simulation"); +} diff --git a/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.h b/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.h new file mode 100644 index 0000000000..debded83a3 --- /dev/null +++ b/Plugins/org.mitk.simulation/src/mitkGetSimulationPreferences.h @@ -0,0 +1,28 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGetSimulationPreferences_h +#define mitkGetSimulationPreferences_h + +#include +#include + +namespace mitk +{ + SIMULATION_INIT_EXPORT berry::IPreferences::Pointer GetSimulationPreferences(); +} + +#endif