diff --git a/CMake/mitkInstallRules.cmake b/CMake/mitkInstallRules.cmake index 80c16985ac..2e97e1aa21 100644 --- a/CMake/mitkInstallRules.cmake +++ b/CMake/mitkInstallRules.cmake @@ -1,197 +1,204 @@ MITK_INSTALL(FILES "${MITK_SOURCE_DIR}/mitk.ico") MITK_INSTALL(FILES "${MITK_SOURCE_DIR}/mitk.bmp") # Install CTK Qt (designer) plugins if(MITK_USE_CTK) if(EXISTS ${CTK_QTDESIGNERPLUGINS_DIR}) set(_qtplugin_install_destinations) if(MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qtplugin_install_destinations ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION}/plugins/designer) endforeach() else() list(APPEND _qtplugin_install_destinations bin/plugins/designer) endif() set(_ctk_qt_plugin_folder_release) set(_ctk_qt_plugin_folder_debug) if(NOT CMAKE_CFG_INTDIR STREQUAL ".") set(_ctk_qt_plugin_folder_release "Release/") set(_ctk_qt_plugin_folder_debug "Debug/") endif() foreach(_qtplugin_install_dir ${_qtplugin_install_destinations}) install(DIRECTORY "${CTK_QTDESIGNERPLUGINS_DIR}/designer/${_ctk_qt_plugin_folder_release}" DESTINATION ${_qtplugin_install_dir} CONFIGURATIONS Release ) install(DIRECTORY "${CTK_QTDESIGNERPLUGINS_DIR}/designer/${_ctk_qt_plugin_folder_debug}" DESTINATION ${_qtplugin_install_dir} CONFIGURATIONS Debug ) endforeach() endif() endif() # related to MITK:T19679 if(MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path "${_qmake_location}" DIRECTORY) install(FILES "${_qmake_path}/../plugins/platforms/libqcocoa.dylib" DESTINATION "${bundle_name}.app/Contents/MacOS/platforms" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/sqldrivers/libqsqlite.dylib" DESTINATION "${bundle_name}.app/Contents/MacOS/sqldrivers" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/iconengines/libqsvgicon.dylib" DESTINATION "${bundle_name}.app/Contents/MacOS/iconengines" CONFIGURATIONS Release) # related to MITK:T19679-InstallQtWebEnginProcess if(MITK_USE_Qt5) get_filename_component(ABS_DIR_HELPERS "${_qmake_path}/../lib/QtWebEngineCore.framework/Helpers" REALPATH) install(DIRECTORY ${ABS_DIR_HELPERS} DESTINATION "${bundle_name}.app/Contents/Frameworks/QtWebEngineCore.framework/" CONFIGURATIONS Release) endif() endforeach() endif() if(WIN32) if(MITK_USE_Qt5) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path "${_qmake_location}" DIRECTORY) install(FILES "${_qmake_path}/../plugins/platforms/qwindows.dll" DESTINATION "bin/plugins/platforms" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/sqldrivers/qsqlite.dll" DESTINATION "bin/plugins/sqldrivers" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/imageformats/qsvg.dll" DESTINATION "bin/plugins/imageformats" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/iconengines/qsvgicon.dll" DESTINATION "bin/plugins/iconengines" CONFIGURATIONS Release) MITK_INSTALL( FILES "${_qmake_path}/QtWebEngineProcess.exe") install(DIRECTORY "${_qmake_path}/../resources/" DESTINATION "bin/resources/" CONFIGURATIONS Release) install(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales/" DESTINATION "bin/translations/qtwebengine_locales/" CONFIGURATIONS Release) install(FILES "${_qmake_path}/../plugins/platforms/qwindowsd.dll" DESTINATION "bin/plugins/platforms" CONFIGURATIONS Debug) install(FILES "${_qmake_path}/../plugins/sqldrivers/qsqlited.dll" DESTINATION "bin/plugins/sqldrivers" CONFIGURATIONS Debug) install(FILES "${_qmake_path}/../plugins/imageformats/qsvgd.dll" DESTINATION "bin/plugins/imageformats" CONFIGURATIONS Debug) install(FILES "${_qmake_path}/../plugins/iconengines/qsvgicond.dll" DESTINATION "bin/plugins/iconengines" CONFIGURATIONS Debug) install(DIRECTORY "${_qmake_path}/../resources/" DESTINATION "bin/resources/" CONFIGURATIONS Debug) install(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales/" DESTINATION "bin/translations/qtwebengine_locales/" CONFIGURATIONS Debug) endif() #DCMTK Dlls install target (shared libs on gcc only) if(MINGW AND DCMTK_ofstd_LIBRARY) set(_dcmtk_libs ${DCMTK_dcmdata_LIBRARY} ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmnet_LIBRARY} ${DCMTK_ofstd_LIBRARY} ) foreach(_dcmtk_lib ${_dcmtk_libs}) MITK_INSTALL(FILES ${_dcmtk_lib} ) endforeach() endif() #MinGW dll if(MINGW) find_library(MINGW_RUNTIME_DLL "mingwm10.dll" HINTS ${CMAKE_FIND_ROOT_PATH}/sys-root/mingw/bin) if(MINGW_RUNTIME_DLL) MITK_INSTALL(FILES ${MINGW_RUNTIME_DLL} ) else() message(SEND_ERROR "Could not find mingwm10.dll which is needed for a proper install") endif() find_library(MINGW_GCC_RUNTIME_DLL "libgcc_s_dw2-1.dll" HINTS ${CMAKE_FIND_ROOT_PATH}/sys-root/mingw/bin) if(MINGW_GCC_RUNTIME_DLL) MITK_INSTALL(FILES ${MINGW_GCC_RUNTIME_DLL} ) else() message(SEND_ERROR "Could not find libgcc_s_dw2-1.dll which is needed for a proper install") endif() endif() else() #DCMTK Dlls install target (shared libs on gcc only) if(DCMTK_ofstd_LIBRARY) set(_dcmtk_libs ${DCMTK_dcmdata_LIBRARY} ${DCMTK_dcmimgle_LIBRARY} ${DCMTK_dcmnet_LIBRARY} ${DCMTK_ofstd_LIBRARY} ) foreach(_dcmtk_lib ${_dcmtk_libs}) #MITK_INSTALL(FILES ${_dcmtk_lib} DESTINATION lib) endforeach() endif() # We need to install Webengineprocess and related files on unix as well if(UNIX) if(MITK_USE_Qt5) get_property(_qmake_location TARGET ${Qt5Core_QMAKE_EXECUTABLE} PROPERTY IMPORT_LOCATION) get_filename_component(_qmake_path "${_qmake_location}" DIRECTORY) install(FILES "${_qmake_path}/../plugins/platforms/libqxcb.so" DESTINATION "bin/plugins/platforms") install(FILES "${_qmake_path}/../plugins/sqldrivers/libqsqlite.so" DESTINATION "bin/plugins/sqldrivers") install(FILES "${_qmake_path}/../plugins/imageformats/libqsvg.so" DESTINATION "bin/plugins/imageformats") install(FILES "${_qmake_path}/../plugins/iconengines/libqsvgicon.so" DESTINATION "bin/plugins/iconengines") install(FILES "${_qmake_path}/../plugins/xcbglintegrations/libqxcb-glx-integration.so" DESTINATION "bin/plugins/xcbglintegrations") MITK_INSTALL_HELPER_APP( EXECUTABLES "${_qmake_path}/../libexec/QtWebEngineProcess") install(DIRECTORY "${_qmake_path}/../resources/" DESTINATION "bin/resources/") install(DIRECTORY "${_qmake_path}/../translations/qtwebengine_locales/" DESTINATION "bin/translations/qtwebengine_locales/") endif() endif() endif() #install Matchpoint libs that are currently not auto detected if(MITK_USE_MatchPoint) install(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" DESTINATION "bin" FILES_MATCHING PATTERN "MAPUtilities*") install(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" DESTINATION "bin" FILES_MATCHING PATTERN "MAPAlgorithms*") endif() if(MITK_USE_BetData) install(DIRECTORY "${BetData_DIR}" DESTINATION "bin" FILES_MATCHING PATTERN "*") endif() + +#install SimpleITK libs that are currently not auto detected +if(MITK_USE_SimpleITK) + install(DIRECTORY "${MITK_EXTERNAL_PROJECT_PREFIX}/bin/" + DESTINATION "bin" + FILES_MATCHING PATTERN "SimpleITK*") +endif() diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 5eedb42547..ad480e00d7 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,37 +1,38 @@ #----------------------------------------------------------------------------- # 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 da5dd4ff) # first 8 characters of hash-tag + # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} SOURCE_DIR ${proj} GIT_REPOSITORY https://phabricator.mitk.org/source/mitkdata.git - GIT_TAG ${revision_tag} +# GIT_TAG ${revision_tag} # 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 ${CMAKE_CURRENT_BINARY_DIR}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeExternals/OpenIGTLink-54df50de.patch b/CMakeExternals/OpenIGTLink-54df50de.patch deleted file mode 100644 index 22e1964f13..0000000000 --- a/CMakeExternals/OpenIGTLink-54df50de.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff -burN OpenIGTLink-master/OpenIGTLinkConfig.cmake.in OpenIGTLink/OpenIGTLinkConfig.cmake.in ---- OpenIGTLink-master/OpenIGTLinkConfig.cmake.in 2014-08-21 18:53:57.000000000 +0200 -+++ OpenIGTLink/OpenIGTLinkConfig.cmake.in 2015-02-05 01:08:29.885874473 +0100 -@@ -48,7 +48,7 @@ - # A list of all libraries for OpenIGTLink. Those listed here should - # automatically pull in their dependencies. - #SET(OpenIGTLink_LIBRARIES OpenIGTLinkAlgorithms OpenIGTLinkStatistics OpenIGTLinkFEM) --SET(OpenIGTLink_LIBRARIES OpenIGTLink) -+SET(OpenIGTLink_LIBRARIES optimized;OpenIGTLink;debug;OpenIGTLink@CMAKE_DEBUG_POSTFIX@) - - # The OpenIGTLink library dependencies. - IF(NOT OpenIGTLink_NO_LIBRARY_DEPENDS AND -diff -burN OpenIGTLink-master/Source/CMakeLists.txt OpenIGTLink/Source/CMakeLists.txt ---- OpenIGTLink-master/Source/CMakeLists.txt 2014-08-21 18:53:57.000000000 +0200 -+++ OpenIGTLink/Source/CMakeLists.txt 2015-02-05 00:34:34.086991641 +0100 -@@ -65,6 +65,7 @@ - igtlutil/igtl_image.h - igtlutil/igtl_position.h - igtlutil/igtl_transform.h -+ igtlutil/igtl_status.h - igtlutil/igtl_types.h - igtlutil/igtl_util.h - igtlutil/igtl_capability.h - -diff -burN OpenIGTLink-master/Source/igtlSocket.cxx OpenIGTLink/Source/igtlSocket.cxx ---- OpenIGTLink-master/Source/igtlSocket.cxx 2014-08-21 18:53:57.000000000 +0200 -+++ OpenIGTLink/Source/igtlSocket.cxx 2015-02-05 00:34:34.086991641 +0100 -@@ -51,7 +51,7 @@ - #define WSA_VERSION MAKEWORD(1,1) - #define igtlCloseSocketMacro(sock) (closesocket(sock)) - #else --#define igtlCloseSocketMacro(sock) (shutdown(sock, 2)) -+#define igtlCloseSocketMacro(sock) ({shutdown(sock, 2); close(sock);}) - #endif - - namespace igtl diff --git a/CMakeExternals/OpenIGTLink.cmake b/CMakeExternals/OpenIGTLink.cmake index d7910aa5e8..39d6b7d268 100644 --- a/CMakeExternals/OpenIGTLink.cmake +++ b/CMakeExternals/OpenIGTLink.cmake @@ -1,52 +1,54 @@ #----------------------------------------------------------------------------- # OpenIGTLink #----------------------------------------------------------------------------- if(MITK_USE_OpenIGTLink) # Sanity checks if(DEFINED OpenIGTLink_DIR AND NOT EXISTS ${OpenIGTLink_DIR}) message(FATAL_ERROR "OpenIGTLink_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenIGTLink) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED OpenIGTLink_DIR) set(additional_cmake_args ) if(CTEST_USE_LAUNCHERS) set(additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} - URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenIGTLink-54df50de.tar.gz - URL_MD5 b9fd8351b059f4ec615f2dfd74ab2458 - PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/OpenIGTLink-54df50de.patch + URL /home/thomaskirchner/Downloads/OpenIGTLink-release-3.0.zip + #${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenIGTLink-54df50de.tar.gz + URL_MD5 e9e2b6190f18e400aa1c9335002e8222 CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DOpenIGTLink_PROTOCOL_VERSION_2:BOOL=ON -DOpenIGTLink_INSTALL_LIB_DIR:STRING=lib -DOpenIGTLink_INSTALL_PACKAGE_DIR:STRING=lib/cmake/OpenIGTLink -DOpenIGTLink_INSTALL_NO_DOCUMENTATION:BOOL=ON + -DBUILD_EXAMPLES:BOOL=OFF + -DBUILD_TESTING:BOOL=OFF CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(OpenIGTLink_DIR "${ep_prefix}/lib/cmake/OpenIGTLink") else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/SimpleITK.cmake b/CMakeExternals/SimpleITK.cmake index 1f6bff9370..24f3be93ab 100644 --- a/CMakeExternals/SimpleITK.cmake +++ b/CMakeExternals/SimpleITK.cmake @@ -1,137 +1,140 @@ #----------------------------------------------------------------------------- # SimpleITK #----------------------------------------------------------------------------- if(MITK_USE_SimpleITK) # Sanity checks if(DEFINED SimpleITK_DIR AND NOT EXISTS ${SimpleITK_DIR}) message(FATAL_ERROR "SimpleITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj SimpleITK) set(proj_DEPENDENCIES ITK GDCM SWIG) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() set(SimpleITK_DEPENDS ${proj}) if(NOT DEFINED SimpleITK_DIR) set(additional_cmake_args ) list(APPEND additional_cmake_args -DWRAP_CSHARP:BOOL=OFF -DWRAP_TCL:BOOL=OFF -DWRAP_LUA:BOOL=OFF -DWRAP_PYTHON:BOOL=OFF -DWRAP_JAVA:BOOL=OFF -DWRAP_RUBY:BOOL=OFF -DWRAP_R:BOOL=OFF ) if(MITK_USE_Python) list(APPEND additional_cmake_args -DWRAP_PYTHON:BOOL=ON -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() #TODO: Installer and testing works only with static libs on MAC set(_build_shared ON) if(APPLE) set(_build_shared OFF) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} #GIT_REPOSITORY https://github.com/SimpleITK/SimpleITK.git # URL https://github.com/SimpleITK/SimpleITK/releases/download/v1.0.1/SimpleITK-1.0.1.tar.xz URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/SimpleITK_9d510bef.tar.gz URL_MD5 c34f4d5259594bf1adf1d83f13228cbe # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/SimpleITK-0.8.1.patch INSTALL_COMMAND "" SOURCE_SUBDIR SuperBuild CMAKE_ARGS ${ep_common_cache_default_args} # -DCMAKE_BUILD_WITH_INSTALL_RPATH:BOOL=ON CMAKE_CACHE_ARGS ${ep_common_cache_args} ${additional_cmake_args} -DBUILD_SHARED_LIBS:BOOL=${_build_shared} -DSimpleITK_BUILD_DISTRIBUTE:BOOL=ON -DSimpleITK_PYTHON_THREADS:BOOL=ON -DSimpleITK_USE_SYSTEM_ITK:BOOL=ON -DITK_DIR:PATH=${ITK_DIR} -DSimpleITK_USE_SYSTEM_SWIG:BOOL=ON -DSWIG_DIR:PATH=${SWIG_DIR} -DSWIG_EXECUTABLE:FILEPATH=${SWIG_EXECUTABLE} -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_TESTING:BOOL=OFF -DGDCM_DIR:PATH=${GDCM_DIR} -DHDF5_DIR:PATH=${HDF5_DIR} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_CXX_COMPILER_AR:FILEPATH=${CMAKE_CXX_COMPILER_AR} -DCMAKE_CXX_COMPILER_RANLIB:FILEPATH=${CMAKE_CXX_COMPILER_RANLIB} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_C_COMPILER_AR:FILEPATH=${CMAKE_C_COMPILER_AR} -DCMAKE_C_COMPILER_RANLIB:FILEPATH=${CMAKE_C_COMPILER_RANLIB} + -DCMAKE_INSTALL_PREFIX:PATH=${ep_prefix} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) if( MITK_USE_Python ) set(_sitk_build_dir ${ep_prefix}/src/SimpleITK-build) # Build python distribution with easy install. If a own runtime is used # embed the egg into the site-package folder of the runtime # Note: Userbase install could also be relevant in some cases Probably windows wants to # install to Lib/python3.6/ # Build egg into custom user base folder and deploy it later into installer # https://pythonhosted.org/setuptools/easy_install.html#use-the-user-option-and-customize-pythonuserbase # PYTHONUSERBASE=${_install_dir} ${PYTHON_EXECUTABLE} setup.py --user # PythonDir needs to be fixed for the python interpreter by # changing dir delimiter for Windows set(_install_dir ${ep_prefix} ) set(_pythonpath ${ep_prefix}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages ) if(WIN32) - STRING(REPLACE "/" "\\\\" _install_dir ${_install_dir}) + STRING(REPLACE "/" "\\\\" _install_dir ${_pythonpath}) + set(_python_install_arguments --install-lib=${_install_dir}) else() # escape spaces in the install path for linux STRING(REPLACE " " "\ " _install_dir ${_install_dir}) + set(_python_install_arguments --prefix=${_install_dir}) endif() ExternalProject_Add_Step(${proj} sitk_python_install_step - COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${_pythonpath}$${ep_prefix}/Lib/site-packages ${PYTHON_EXECUTABLE} Packaging/setup.py install --prefix=${_install_dir} + COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${_pythonpath} ${PYTHON_EXECUTABLE} Packaging/setup.py install ${_python_install_arguments} DEPENDEES install WORKING_DIRECTORY ${_sitk_build_dir}/SimpleITK-build/Wrapping/Python/ ) endif() mitkFunctionInstallExternalCMakeProject(${proj}) # Still need to install the SimpleITK Python wrappings else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() set(SimpleITK_DIR ${ep_prefix}/src/SimpleITK-build/SimpleITK-build) endif() diff --git a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp index 95ce7d1bc8..cccf716e2b 100644 --- a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp +++ b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp @@ -1,561 +1,561 @@ /*=================================================================== 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 "mitkArithmeticOperation.h" #include #include #include #include #include #include "itkUnaryFunctorImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { namespace Functor { template< class TInput, class TOutput> class AddValue { public: AddValue() {}; ~AddValue() {}; bool operator!=(const AddValue &) const { return false; } bool operator==(const AddValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { return A + value; } bool valueLeft = false; double value = 0.0; }; template< class TInput, class TOutput> class SubValue { public: SubValue() {}; ~SubValue() {}; bool operator!=(const SubValue &) const { return false; } bool operator==(const SubValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { if (valueLeft) return value - A; else return A - value; } bool valueLeft = false; double value = 0.0; }; template< class TInput, class TOutput> class MultValue { public: MultValue() {}; ~MultValue() {}; bool operator!=(const MultValue &) const { return false; } bool operator==(const MultValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { return A * value; } bool valueLeft = false; double value = 0.0; }; template< class TInput, class TOutput> class DivValue { public: DivValue() {}; ~DivValue() {}; bool operator!=(const DivValue &) const { return false; } bool operator==(const DivValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { if (valueLeft) return value / A; else return A / value; } bool valueLeft = false; double value = 1.0; }; template< class TInput, class TOutput> class PowValue { public: PowValue() {}; ~PowValue() {}; bool operator!=(const PowValue &) const { return false; } bool operator==(const PowValue & other) const { return !(*this != other); } inline TOutput operator()(const TInput & A) const { if (valueLeft) return static_cast(std::pow(value, A)); else return static_cast(std::pow(A, value)); } bool valueLeft = false; double value = 1.0; }; } } template static void ExecuteOneImageFilterWithFunctor(ImageType* imageA, double value, bool returnDoubleImage, bool valueLeft, bool , mitk::Image::Pointer & outputImage) { typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; if (returnDoubleImage) { typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); filter->SetInput(imageA); filter->GetFunctor().valueLeft = valueLeft; filter->GetFunctor().value = value; filter->Update(); CastToMitkImage(filter->GetOutput(), outputImage); } else { typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput(imageA); filter->GetFunctor().valueLeft = valueLeft; filter->GetFunctor().value = value; filter->Update(); CastToMitkImage(filter->GetOutput(), outputImage); } } template static void ExecuteOneImageFilterWithFunctorNonParameter(ImageType* imageA, double , bool returnDoubleImage, bool , bool , mitk::Image::Pointer & outputImage) { typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; if (returnDoubleImage) { typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); filter->SetInput(imageA); filter->Update(); CastToMitkImage(filter->GetOutput(), outputImage); } else { typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput(imageA); filter->Update(); CastToMitkImage(filter->GetOutput(), outputImage); } } template static void ExecuteOneImageFilter(itk::Image* imageA, double value, bool returnDoubleImage, bool valueLeft, bool parameterFree, mitk::NonStaticArithmeticOperation::OperationsEnum algorithm, mitk::Image::Pointer & outputImage) { typedef itk::Image ImageType; typedef itk::Image DoubleOutputType; switch (algorithm) { case mitk::NonStaticArithmeticOperation::OperationsEnum::AddValue: ExecuteOneImageFilterWithFunctor, mitk::Functor::AddValue, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::SubValue: ExecuteOneImageFilterWithFunctor, mitk::Functor::SubValue, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::MultValue: ExecuteOneImageFilterWithFunctor, mitk::Functor::MultValue, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::DivValue: ExecuteOneImageFilterWithFunctor, mitk::Functor::DivValue, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::PowValue: ExecuteOneImageFilterWithFunctor, mitk::Functor::PowValue, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Tan: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Tan, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::ATan: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Atan, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Cos: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Cos, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::ACos: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Acos, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Sin: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Sin, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::ASin: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Asin, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Square: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Square, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Sqrt: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Sqrt, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Abs: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Abs, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Exp: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Exp, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::ExpNeg: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::ExpNegative, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; case mitk::NonStaticArithmeticOperation::OperationsEnum::Log10: ExecuteOneImageFilterWithFunctorNonParameter, itk::Functor::Log10, ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); break; default: break; } } mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, Image::Pointer & imageB, bool) { NonStaticArithmeticOperation helper; helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Add2; helper.CallExecuteTwoImageFilter(imageA, imageB); return helper.m_ResultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool) { NonStaticArithmeticOperation helper; helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Sub2; helper.CallExecuteTwoImageFilter(imageA, imageB); return helper.m_ResultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool) { NonStaticArithmeticOperation helper; helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Mult; helper.CallExecuteTwoImageFilter(imageA, imageB); return helper.m_ResultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool) { NonStaticArithmeticOperation helper; helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Div; helper.CallExecuteTwoImageFilter(imageA, imageB); return helper.m_ResultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, double value, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, double value, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, double value, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, double value, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Add(double value, Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(double value, Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(double value, Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Divide(double value, Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Tan(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Tan, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Atan(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ATan, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Sin(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sin, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Asin(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ASin, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Cos(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Cos, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Acos(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ACos, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Square(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Square, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Sqrt(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sqrt, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Abs(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Abs, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Exp(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Exp, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::ExpNeg(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ExpNeg, resultImage)); return resultImage; } mitk::Image::Pointer mitk::ArithmeticOperation::Log10(Image::Pointer & imageA, bool outputAsDouble) { mitk::Image::Pointer resultImage; AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Log10, resultImage)); return resultImage; } void mitk::NonStaticArithmeticOperation::CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB) { if (imageA->GetDimension() != imageB->GetDimension()) { mitkThrow() << "Image have different dimensions. This is not supported by mitk::ArithmeticOperation"; } switch (imageA->GetDimension()) { case 1: AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 1); break; case 2: AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 2); break; case 3: AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 3); break; case 4: AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 4); break; default: mitkThrow() << "Image Dimension of "<GetDimension() << " is not supported"; break; } } template void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB) { typedef itk::Image Image1Type; typedef itk::Image Image2Type; typedef itk::Image DoubleOutputType; switch (m_Algorithm) { case OperationsEnum::Add2: ExecuteTwoImageFilterWithFunctor, itk::Functor::Add2, Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); break; case OperationsEnum::Sub2: ExecuteTwoImageFilterWithFunctor, itk::Functor::Add2, Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); break; case OperationsEnum::Mult: ExecuteTwoImageFilterWithFunctor, itk::Functor::Add2, Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); break; case OperationsEnum::Div: ExecuteTwoImageFilterWithFunctor, itk::Functor::Add2, Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); break; default: break; } } template void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB) { typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, Image1Type,DefaultFunctorType > DefaultFilterType; typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, DoubleImageType, DoubleFunctorType > DoubleFilterType; if (m_GenerateDoubleOutput) { typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); filter->SetInput1(imageA); filter->SetInput2(imageB); filter->Update(); CastToMitkImage(filter->GetOutput(), m_ResultImage); } else { typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); filter->SetInput1(imageA); filter->SetInput2(imageB); filter->Update(); CastToMitkImage(filter->GetOutput(), m_ResultImage); } -} \ No newline at end of file +} diff --git a/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp b/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp index 0cdc98a1c1..ebd97e602d 100644 --- a/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp +++ b/Modules/Classification/CLMiniApps/XRaxSimulationFromCT.cpp @@ -1,226 +1,225 @@ /*=================================================================== 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 "mitkProperties.h" #include "mitkCommandLineParser.h" #include "mitkIOUtil.h" #include "itkImageRegionIterator.h" // MITK #include #include #include struct Params { bool invert; float zeroValue; }; - template void CreateXRay(itk::Image* itkImage, mitk::Image::Pointer mask1, std::string output, Params param) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::Image NewImageType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask1, itkMask); NewImageType::SpacingType newSpacing; - auto spacing = itkImage->GetSpacing(); - spacing[0] = itkImage->GetSpacing()[0]; - spacing[1] = itkImage->GetSpacing()[1]; - spacing[2] = itkImage->GetSpacing()[2]; + typename ImageType::SpacingType spacing; + spacing[0] = 0; + spacing[1] = 0; + spacing[2] = 0; spacing = itkImage->GetSpacing(); NewImageType::RegionType region1,region2,region3,region1m,region2m,region3m; NewImageType::IndexType start; start[0] = 0; start[1] = 0; NewImageType::SizeType size1, size2, size3; size1[0] = mask1->GetDimensions()[0]; size2[0] = mask1->GetDimensions()[0]; size3[0] = mask1->GetDimensions()[1]; size1[1] = mask1->GetDimensions()[1]; size2[1] = mask1->GetDimensions()[2]; size3[1] = mask1->GetDimensions()[2]; region1.SetSize(size1); region1m.SetSize(size1); region2.SetSize(size2); region2m.SetSize(size2); region3.SetSize(size3); region3m.SetSize(size3); region1.SetIndex(start); region1m.SetIndex(start); region2.SetIndex(start); region2m.SetIndex(start); region3.SetIndex(start); region3m.SetIndex(start); NewImageType::Pointer image1 = NewImageType::New(); image1->SetRegions(region1); image1->Allocate(); image1->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[1]; image1->SetSpacing(newSpacing); NewImageType::Pointer image2 = NewImageType::New(); image2->SetRegions(region2); image2->Allocate(); image2->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[2]; image2->SetSpacing(newSpacing); NewImageType::Pointer image3 = NewImageType::New(); image3->SetRegions(region3); image3->Allocate(); image3->FillBuffer(0); newSpacing[0] = spacing[1]; newSpacing[1] = spacing[2]; image3->SetSpacing(newSpacing); NewImageType::Pointer image1m = NewImageType::New(); image1m->SetRegions(region1m); image1m->Allocate(); image1m->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[1]; image1m->SetSpacing(newSpacing); NewImageType::Pointer image2m = NewImageType::New(); image2m->SetRegions(region2m); image2m->Allocate(); image2m->FillBuffer(0); newSpacing[0] = spacing[0]; newSpacing[1] = spacing[2]; image2m->SetSpacing(newSpacing); NewImageType::Pointer image3m = NewImageType::New(); image3m->SetRegions(region3m); image3m->Allocate(); image3m->FillBuffer(0); newSpacing[0] = spacing[1]; newSpacing[1] = spacing[2]; image3m->SetSpacing(newSpacing); for (unsigned int x = 0; x < mask1->GetDimensions()[0]; ++x) { for (unsigned int y = 0; y < mask1->GetDimensions()[1]; ++y) { for (unsigned int z = 0; z < mask1->GetDimensions()[2]; ++z) { NewImageType::IndexType newIndex; typename ImageType::IndexType index; index[0] = x; index[1] = y; index[2] = z; double pixel = itkImage->GetPixel(index)+1024; pixel = pixel / 1000.0; pixel = (pixel < 0)? 0 : pixel; newIndex[0] = x; newIndex[1] = y; image1->SetPixel(newIndex, image1->GetPixel(newIndex) + pixel); newIndex[0] = x; newIndex[1] = z; image2->SetPixel(newIndex, image2->GetPixel(newIndex) + pixel); newIndex[0] = y; newIndex[1] = z; image3->SetPixel(newIndex, image3->GetPixel(newIndex) + pixel); if (itkMask->GetPixel(index) > 0 && !param.invert) { pixel = param.zeroValue + 1024; pixel = pixel / 1000.0; } if (itkMask->GetPixel(index) < 1 && param.invert) { pixel = param.zeroValue + 1024; pixel = pixel / 1000.0; } pixel = (pixel < 0)? 0 : pixel; newIndex[0] = x; newIndex[1] = y; image1m->SetPixel(newIndex, image1m->GetPixel(newIndex) + pixel); newIndex[0] = x; newIndex[1] = z; image2m->SetPixel(newIndex, image2m->GetPixel(newIndex) + pixel); newIndex[0] = y; newIndex[1] = z; image3m->SetPixel(newIndex, image3m->GetPixel(newIndex) + pixel); } } } mitk::Image::Pointer img = mitk::ImportItkImage(image1); mitk::IOUtil::Save(img, output + "1.nrrd"); img = mitk::ImportItkImage(image2); mitk::IOUtil::Save(img, output + "2.nrrd"); img = mitk::ImportItkImage(image3); mitk::IOUtil::Save(img, output + "3.nrrd"); img = mitk::ImportItkImage(image1m); mitk::IOUtil::Save(img, output + "1m.nrrd"); img = mitk::ImportItkImage(image2m); mitk::IOUtil::Save(img, output + "2m.nrrd"); img = mitk::ImportItkImage(image3m); mitk::IOUtil::Save(img, output + "3m.nrrd"); } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Dicom Loader"); parser.setCategory("Preprocessing Tools"); parser.setDescription(""); parser.setContributor("MBI"); parser.setArgumentPrefix("-","-"); // Add command line argument names parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input image:", "Input folder", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputDirectory, "Input mask:", "Input folder", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); parser.addArgument("invert", "invert", mitkCommandLineParser::Bool, "Input mask:", "Input folder", us::Any()); parser.addArgument("zero_value", "zero", mitkCommandLineParser::Float, "Output file:", "Output file", us::Any()); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // Show a help message if ( parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputImage = us::any_cast(parsedArgs["input"]); MITK_INFO << inputImage; std::string inputMask = us::any_cast(parsedArgs["mask"]); MITK_INFO << inputMask; Params param; param.invert = false; param.zeroValue = 0; if (parsedArgs.count("invert")) { param.invert = true; } if (parsedArgs.count("zero_value")) { param.zeroValue = us::any_cast(parsedArgs["zero_value"]); } mitk::Image::Pointer image = mitk::IOUtil::Load(inputImage); mitk::Image::Pointer mask = mitk::IOUtil::Load(inputMask); AccessByItk_3(image, CreateXRay, mask, parsedArgs["output"].ToString(),param); //const mitk::Image::Pointer image = *imageIter; //mitk::IOUtil::SaveImage(image,outFileName); return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp index 0b74fe0845..6458c7f8ac 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp @@ -1,526 +1,529 @@ /*=================================================================== 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 #include #include #include #include #include // ITK #include #include #include #include // VTK #include #include #include #include #include #include #include #include // STL #include #include // Eigen #include struct GIFVolumetricDensityStatisticsParameters { double volume; std::string prefix; }; template void CalculateVolumeDensityStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, GIFVolumetricDensityStatisticsParameters params, mitk::GIFVolumetricDensityStatistics::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; double volume = params.volume; std::string prefix = params.prefix; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); itk::ImageRegionConstIteratorWithIndex imgA(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex imgB(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskA(maskImage, maskImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maskB(maskImage, maskImage->GetLargestPossibleRegion()); double moranA = 0; double moranB = 0; double geary = 0; double Nv = 0; double w_ij = 0; double mean = 0; typename ImageType::PointType pointA; typename ImageType::PointType pointB; while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { Nv += 1; mean += imgA.Get(); } ++imgA; ++maskA; } mean /= Nv; imgA.GoToBegin(); maskA.GoToBegin(); + while (!imgA.IsAtEnd()) { if (maskA.Get() > 0) { imgB.GoToBegin(); maskB.GoToBegin(); while (!imgB.IsAtEnd()) { if ((imgA.GetIndex() == imgB.GetIndex()) || (maskB.Get() < 1)) { ++imgB; ++maskB; continue; } itkImage->TransformIndexToPhysicalPoint(maskA.GetIndex(), pointA); itkImage->TransformIndexToPhysicalPoint(maskB.GetIndex(), pointB); double w = 1 / pointA.EuclideanDistanceTo(pointB); moranA += w*(imgA.Get() - mean)* (imgB.Get() - mean); geary += w * (imgA.Get() - imgB.Get()) * (imgA.Get() - imgB.Get()); w_ij += w; ++imgB; ++maskB; } moranB += (imgA.Get() - mean)* (imgA.Get() - mean); } ++imgA; ++maskA; } featureList.push_back(std::make_pair(prefix + "Volume integrated intensity", volume* mean)); featureList.push_back(std::make_pair(prefix + "Volume Moran's I index", Nv / w_ij * moranA / moranB)); featureList.push_back(std::make_pair(prefix + "Volume Geary's C measure", ( Nv -1 ) / 2 / w_ij * geary/ moranB)); } void calculateMOBB(vtkPointSet *pointset, double &volume, double &surface) { volume = std::numeric_limits::max(); for (int cellID = 0; cellID < pointset->GetNumberOfCells(); ++cellID) { auto cell = pointset->GetCell(cellID); for (int edgeID = 0; edgeID < 3; ++edgeID) { auto edge = cell->GetEdge(edgeID); double pA[3], pB[3]; double pAA[3], pBB[3]; vtkSmartPointer transform = vtkSmartPointer::New(); transform->PostMultiply(); pointset->GetPoint(edge->GetPointId(0), pA); pointset->GetPoint(edge->GetPointId(1), pB); double angleZ = std::atan2((- pA[2] + pB[2]) ,(pA[1] - pB[1])); angleZ *= 180 / vnl_math::pi; if (pA[2] == pB[2]) angleZ = 0; transform->RotateX(angleZ); transform->TransformPoint(pA, pAA); transform->TransformPoint(pB, pBB); double angleY = std::atan2((pAA[1] -pBB[1]) ,-(pAA[0] - pBB[0])); angleY *= 180 / vnl_math::pi; if (pAA[1] == pBB[1]) angleY = 0; transform->RotateZ(angleY); double p0[3]; pointset->GetPoint(edge->GetPointId(0), p0); double curMinX = std::numeric_limits::max(); double curMaxX = std::numeric_limits::lowest(); double curMinY = std::numeric_limits::max(); double curMaxY = std::numeric_limits::lowest(); double curMinZ = std::numeric_limits::max(); double curMaxZ = std::numeric_limits::lowest(); for (int pointID = 0; pointID < pointset->GetNumberOfPoints(); ++pointID) { double p[3]; double p2[3]; pointset->GetPoint(pointID, p); p[0] -= p0[0]; p[1] -= p0[1]; p[2] -= p0[2]; transform->TransformPoint(p, p2); curMinX = std::min(p2[0], curMinX); curMaxX = std::max(p2[0], curMaxX); curMinY = std::min(p2[1], curMinY); curMaxY = std::max(p2[1], curMaxY); curMinZ = std::min(p2[2], curMinZ); curMaxZ = std::max(p2[2], curMaxZ); - - //std::cout << pointID << " (" << p[0] << "|" << p[1] << "|" << p[2] << ") (" << p2[0] << "|" << p2[1] << "|" << p2[2] << ")" << std::endl; } if ((curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ) < volume) { volume = (curMaxX - curMinX)*(curMaxY - curMinY)*(curMaxZ - curMinZ); surface = (curMaxX - curMinX)*(curMaxX - curMinX) + (curMaxY - curMinY)*(curMaxY - curMinY) + (curMaxZ - curMinZ)*(curMaxZ - curMinZ); surface *= 2; } } } } -void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0000001) +void calculateMEE(vtkPointSet *pointset, double &vol, double &surf, double tolerance=0.0001) { // Inspired by https://github.com/smdabdoub/ProkaryMetrics/blob/master/calc/fitting.py int numberOfPoints = pointset->GetNumberOfPoints(); int dimension = 3; Eigen::MatrixXd points(3, numberOfPoints); Eigen::MatrixXd Q(3+1, numberOfPoints); double p[3]; + + std::cout << "Initialize Q " << std::endl; for (int i = 0; i < numberOfPoints; ++i) { pointset->GetPoint(i, p); points(0, i) = p[0]; points(1, i) = p[1]; points(2, i) = p[2]; Q(0, i) = p[0]; Q(1, i) = p[1]; Q(2, i) = p[2]; - Q(3, i) = p[3]; + Q(3, i) = 1.0; } int count = 1; double error = 1; Eigen::VectorXd u_vector(numberOfPoints); u_vector.fill(1.0 / numberOfPoints); Eigen::DiagonalMatrix u = u_vector.asDiagonal(); Eigen::VectorXd ones(dimension + 1); ones.fill(1); Eigen::MatrixXd Ones = ones.asDiagonal(); // Khachiyan Algorithm while (error > tolerance) { auto Qt = Q.transpose(); Eigen::MatrixXd X = Q*u*Qt; Eigen::FullPivHouseholderQR qr(X); Eigen::MatrixXd Xi = qr.solve(Ones); + Eigen::MatrixXd M = Qt * Xi * Q; double maximumValue = M(0, 0); int maximumPosition = 0; for (int i = 0; i < numberOfPoints; ++i) { if (maximumValue < M(i, i)) { maximumValue = M(i, i); maximumPosition = i; } } double stepsize = (maximumValue - dimension - 1) / ((dimension + 1) * (maximumValue - 1)); Eigen::DiagonalMatrix new_u = (1.0 - stepsize) * u; new_u.diagonal()[maximumPosition] = (new_u.diagonal())(maximumPosition) + stepsize; ++count; error = (new_u.diagonal() - u.diagonal()).norm(); u.diagonal() = new_u.diagonal(); } // U = u + Eigen::MatrixXd Ai = points * u * points.transpose() - points * u *(points * u).transpose(); Eigen::FullPivHouseholderQR qr(Ai); Eigen::VectorXd ones2(dimension); ones2.fill(1); Eigen::MatrixXd Ones2 = ones2.asDiagonal(); Eigen::MatrixXd A = qr.solve(Ones2)*1.0/dimension; Eigen::JacobiSVD svd(A); double c = 1 / sqrt(svd.singularValues()[0]); double b = 1 / sqrt(svd.singularValues()[1]); double a = 1 / sqrt(svd.singularValues()[2]); double V = 4 * vnl_math::pi*a*b*c / 3; double ad_mvee= 0; double alpha = std::sqrt(1 - b*b / a / a); double beta = std::sqrt(1 - c*c / a / a); for (int i = 0; i < 20; ++i) { ad_mvee += 4 * vnl_math::pi*a*b*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } vol = V; surf = ad_mvee; } mitk::GIFVolumetricDensityStatistics::FeatureListType mitk::GIFVolumetricDensityStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } std::string prefix = FeatureDescriptionPrefix(); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); vtkSmartPointer stats2 = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); vtkSmartPointer delaunay = vtkSmartPointer< vtkDelaunay3D >::New(); delaunay->SetInputConnection(mesher->GetOutputPort()); delaunay->SetAlpha(0); delaunay->Update(); vtkSmartPointer geometryFilter = vtkSmartPointer::New(); geometryFilter->SetInputConnection(delaunay->GetOutputPort()); geometryFilter->Update(); stats2->SetInputConnection(geometryFilter->GetOutputPort()); stats2->Update(); double vol_mvee; double surf_mvee; calculateMEE(mesher->GetOutput(), vol_mvee, surf_mvee); double vol_mobb; double surf_mobb; calculateMOBB(geometryFilter->GetOutput(), vol_mobb, surf_mobb); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); GIFVolumetricDensityStatisticsParameters params; params.volume = meshVolume; params.prefix = prefix; AccessByItk_3(image, CalculateVolumeDensityStatistic, mask, params, featureList); //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; int minimumX=xx; int maximumX=0; int minimumY=yy; int maximumY=0; int minimumZ=zz; int maximumZ=0; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); vtkSmartPointer points = vtkSmartPointer< vtkPoints >::New(); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { minimumX = std::min(x, minimumX); minimumY = std::min(y, minimumY); minimumZ = std::min(z, minimumZ); maximumX = std::max(x, maximumX); maximumY = std::max(y, maximumY); maximumZ = std::max(z, maximumZ); points->InsertNextPoint(x*xd, y*yd, z*zd); if (pxImage == pxImage) { dataset1Arr->InsertNextValue(x*xd); dataset2Arr->InsertNextValue(y*yd); dataset3Arr->InsertNextValue(z*zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); std::vector eigen_val(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); double major = 2*sqrt(eigen_val[2]); double minor = 2*sqrt(eigen_val[1]); double least = 2*sqrt(eigen_val[0]); double alpha = std::sqrt(1 - minor*minor / major / major); double beta = std::sqrt(1 - least*least / major / major); double a = (maximumX - minimumX+1) * xd; double b = (maximumY - minimumY+1) * yd; double c = (maximumZ - minimumZ+1) * zd; double vd_aabb = meshVolume / (a*b*c); double ad_aabb = meshSurf / (2 * a*b + 2 * a*c + 2 * b*c); double vd_aee = 3 * meshVolume / (4.0*pi*major*minor*least); double ad_aee = 0; for (int i = 0; i < 20; ++i) { ad_aee += 4 * pi*major*minor*(alpha*alpha + beta*beta) / (2 * alpha*beta) * (std::pow(alpha*beta, i)) / (1 - 4 * i*i); } ad_aee = meshSurf / ad_aee; double vd_ch = meshVolume / stats2->GetVolume(); double ad_ch = meshSurf / stats2->GetSurfaceArea(); featureList.push_back(std::make_pair(prefix + "Volume density axis-aligned bounding box", vd_aabb)); featureList.push_back(std::make_pair(prefix + "Surface density axis-aligned bounding box", ad_aabb)); featureList.push_back(std::make_pair(prefix + "Volume density oriented minimum bounding box", meshVolume / vol_mobb)); featureList.push_back(std::make_pair(prefix + "Surface density oriented minimum bounding box", meshSurf / surf_mobb)); featureList.push_back(std::make_pair(prefix + "Volume density approx. enclosing ellipsoid", vd_aee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. enclosing ellipsoid", ad_aee)); featureList.push_back(std::make_pair(prefix + "Volume density approx. minimum volume enclosing ellipsoid", meshVolume / vol_mvee)); featureList.push_back(std::make_pair(prefix + "Surface density approx. minimum volume enclosing ellipsoid", meshSurf / surf_mvee)); featureList.push_back(std::make_pair(prefix + "Volume density convex hull", vd_ch)); featureList.push_back(std::make_pair(prefix + "Surface density convex hull", ad_ch)); return featureList; } mitk::GIFVolumetricDensityStatistics::GIFVolumetricDensityStatistics() { SetLongName("volume-density"); SetShortName("volden"); SetFeatureClassName("Morphological Density"); } mitk::GIFVolumetricDensityStatistics::FeatureNameListType mitk::GIFVolumetricDensityStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricDensityStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Density Statistic", "calculates volume density based features", us::Any()); } void mitk::GIFVolumetricDensityStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating volumetric density features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric density features...."; } } diff --git a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp index adde06ef97..d29ae3f58b 100644 --- a/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp +++ b/Modules/Classification/CLUtilities/test/mitkGIFVolumetricDensityStatisticsTest.cpp @@ -1,92 +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. ===================================================================*/ #include #include #include "mitkIOUtil.h" #include #include class mitkGIFVolumetricDensityStatisticsTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkGIFVolumetricDensityStatisticsTestSuite); MITK_TEST(ImageDescription_PhantomTest); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_IBSI_Phantom_Image_Small; mitk::Image::Pointer m_IBSI_Phantom_Image_Large; mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; public: void setUp(void) override { m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); } void ImageDescription_PhantomTest() { mitk::GIFVolumetricDensityStatistics::Pointer featureCalculator = mitk::GIFVolumetricDensityStatistics::New(); featureCalculator->SetUseBinsize(true); featureCalculator->SetBinsize(1.0); featureCalculator->SetUseMinimumIntensity(true); featureCalculator->SetUseMaximumIntensity(true); featureCalculator->SetMinimumIntensity(0.5); featureCalculator->SetMaximumIntensity(6.5); auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); std::map results; for (auto valuePair : featureList) { MITK_INFO << valuePair.first << " : " << valuePair.second; results[valuePair.first] = valuePair.second; } CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 13 features.", std::size_t(13), featureList.size()); // These values are obtained by a run of the filter. // The might be wrong! // These values are obtained in collaboration with IBSI. // They are usually reported with an accuracy of 0.01 CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume integrated intensity with Large IBSI Phantom Image", 1195, results["Morphological Density::Volume integrated intensity"], 1.0); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Moran's I index with Large IBSI Phantom Image", 0.0397, results["Morphological Density::Volume Moran's I index"], 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Geary's C measure with Large IBSI Phantom Image", 0.974, results["Morphological Density::Volume Geary's C measure"], 0.001); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume density axis-aligned bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Surface density axis-aligned bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.87, results["Morphological Density::Volume density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume oriented minimum bounding box with Large IBSI Phantom Image", 0.86, results["Morphological Density::Surface density oriented minimum bounding box"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.17, results["Morphological Density::Volume density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume approx. enclosing ellipsoid with Large IBSI Phantom Image", 1.34, results["Morphological Density::Surface density approx. enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.24, results["Morphological Density::Volume density approx. minimum volume enclosing ellipsoid"], 0.01); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.46, results["Morphological Density::Surface density approx. minimum volume enclosing ellipsoid"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume minimum volume enclosing ellipsoid with Large IBSI Phantom Image", 0.49, results["Morphological Density::Surface density approx. minimum volume enclosing ellipsoid"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Volume Volume convex hull with Large IBSI Phantom Image", 0.96, results["Morphological Density::Volume density convex hull"], 0.01); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Morphological Density::Surface Volume convex hull with Large IBSI Phantom Image", 1.03, results["Morphological Density::Surface density convex hull"], 0.01); } }; MITK_TEST_SUITE_REGISTRATION(mitkGIFVolumetricDensityStatistics ) \ No newline at end of file diff --git a/Modules/Core/test/mitkBaseDataTest.cpp b/Modules/Core/test/mitkBaseDataTest.cpp index 5661a86164..550dd039a7 100644 --- a/Modules/Core/test/mitkBaseDataTest.cpp +++ b/Modules/Core/test/mitkBaseDataTest.cpp @@ -1,124 +1,283 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" -#include "itkImage.h" +// std includes +#include + +// MITK includes #include "mitkBaseDataTestImplementation.h" #include "mitkStringProperty.h" -#include "mitkTestingMacros.h" #include #include -int mitkBaseDataTest(int /*argc*/, char * /*argv*/ []) +// itksys +#include "itkImage.h" + +// VTK includes +#include + +class mitkBaseDataTestSuite : public mitk::TestFixture { - MITK_TEST_BEGIN("BaseData") - - // Create a BaseData implementation - MITK_INFO << "Creating a base data instance..."; - mitk::BaseDataTestImplementation::Pointer baseDataImpl = mitk::BaseDataTestImplementation::New(); - - MITK_TEST_CONDITION_REQUIRED(baseDataImpl.IsNotNull(), "Testing instantiation"); - MITK_TEST_CONDITION(baseDataImpl->IsInitialized(), "BaseDataTestImplementation is initialized"); - MITK_TEST_CONDITION(baseDataImpl->IsEmpty(), "BaseDataTestImplementation is initialized and empty"); - - mitk::BaseDataTestImplementation::Pointer cloneBaseData = baseDataImpl->Clone(); - MITK_TEST_CONDITION_REQUIRED(cloneBaseData.IsNotNull(), "Testing instantiation of base data clone"); - MITK_TEST_CONDITION(cloneBaseData->IsInitialized(), "Clone of BaseDataTestImplementation is initialized"); - MITK_TEST_CONDITION(cloneBaseData->IsEmpty(), "Clone of BaseDataTestImplementation is initialized and empty"); - - MITK_INFO << "Testing setter and getter for geometries..."; - - // test method GetTimeGeometry() - MITK_TEST_CONDITION(baseDataImpl->GetTimeGeometry(), "Testing creation of TimeGeometry"); - - mitk::TimeGeometry *geo = nullptr; - baseDataImpl->SetTimeGeometry(geo); - - MITK_TEST_CONDITION(baseDataImpl->GetTimeGeometry() == nullptr, "Reset Geometry"); - - mitk::ProportionalTimeGeometry::Pointer geo2 = mitk::ProportionalTimeGeometry::New(); - baseDataImpl->SetTimeGeometry(geo2); - geo2->Initialize(2); - MITK_TEST_CONDITION(baseDataImpl->GetTimeGeometry() == geo2.GetPointer(), "Correct Reinit of TimeGeometry"); - - // test method GetGeometry(int timeStep) - MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1) != nullptr, "... and single Geometries"); - - // test method Expand(unsigned int timeSteps) - baseDataImpl->Expand(5); - MITK_TEST_CONDITION(baseDataImpl->GetTimeSteps() == 5, "Expand the geometry to further time slices!"); - - // test method GetUpdatedGeometry(int timeStep); - mitk::Geometry3D::Pointer geometry3D = mitk::Geometry3D::New(); - mitk::BaseGeometry::Pointer geo3 = dynamic_cast(geometry3D.GetPointer()); - mitk::ProportionalTimeGeometry::Pointer timeGeometry = - dynamic_cast(baseDataImpl->GetTimeGeometry()); - if (timeGeometry.IsNotNull()) - { - timeGeometry->SetTimeStepGeometry(geo3, 1); - } - - MITK_TEST_CONDITION(baseDataImpl->GetUpdatedGeometry(1) == geo3, "Set Geometry for time step 1"); - MITK_TEST_CONDITION(baseDataImpl->GetMTime() != 0, "Check if modified time is set"); - baseDataImpl->SetClonedGeometry(geo3, 1); - - mitk::ScalarType x[3]; - x[0] = 2; - x[1] = 4; - x[2] = 6; - mitk::Point3D p3d(x); - baseDataImpl->SetOrigin(p3d); - geo3->SetOrigin(p3d); - - MITK_TEST_CONDITION(baseDataImpl->GetGeometry(1)->GetOrigin() == geo3->GetOrigin(), "Testing Origin set"); - - cloneBaseData = baseDataImpl->Clone(); - MITK_TEST_CONDITION(cloneBaseData->GetGeometry(1)->GetOrigin() == geo3->GetOrigin(), "Testing origin set in clone!"); - - MITK_TEST_CONDITION(!baseDataImpl->IsEmptyTimeStep(1), "Is not empty before clear()!"); - baseDataImpl->Clear(); - MITK_TEST_CONDITION(baseDataImpl->IsEmptyTimeStep(1), "...but afterwards!"); - // test method Set-/GetProperty() - baseDataImpl->SetProperty("property38", mitk::StringProperty::New("testproperty")); - // baseDataImpl->SetProperty("visibility", mitk::BoolProperty::New()); - MITK_TEST_CONDITION(baseDataImpl->GetProperty("property38")->GetValueAsString() == "testproperty", - "Check if base property is set correctly!"); - - cloneBaseData = baseDataImpl->Clone(); - MITK_TEST_CONDITION(cloneBaseData->GetProperty("property38")->GetValueAsString() == "testproperty", - "Testing origin set in clone!"); - - // test method Set-/GetPropertyList - mitk::PropertyList::Pointer propertyList = mitk::PropertyList::New(); - propertyList->SetFloatProperty("floatProperty1", 123.45); - propertyList->SetBoolProperty("visibility", true); - propertyList->SetStringProperty("nameXY", "propertyName"); - baseDataImpl->SetPropertyList(propertyList); - bool value = false; - MITK_TEST_CONDITION(baseDataImpl->GetPropertyList() == propertyList, "Check if base property list is set correctly!"); - MITK_TEST_CONDITION(baseDataImpl->GetPropertyList()->GetBoolProperty("visibility", value) == true, - "Check if base property is set correctly in the property list!"); - - // test method UpdateOutputInformation() - baseDataImpl->UpdateOutputInformation(); - MITK_TEST_CONDITION(baseDataImpl->GetUpdatedTimeGeometry() == geo2, "TimeGeometry update!"); - // Test method CopyInformation() - mitk::BaseDataTestImplementation::Pointer newBaseData = mitk::BaseDataTestImplementation::New(); - newBaseData->CopyInformation(baseDataImpl); - MITK_TEST_CONDITION_REQUIRED(newBaseData->GetTimeGeometry()->CountTimeSteps() == 5, - "Check copying of of Basedata Data Object!"); - - MITK_TEST_END() -} + CPPUNIT_TEST_SUITE(mitkBaseDataTestSuite); + + MITK_TEST(CreateBaseData_Success); + MITK_TEST(InitializationOfBaseData_Success); + + MITK_TEST(CreateCloneBaseData_Success); + MITK_TEST(InitializationOfCloneBaseData_Success); + + MITK_TEST(GetAndSetTimeGeometry_Success); + MITK_TEST(ResetTimeGeometry_Success); + MITK_TEST(ReinitOfTimeGeometry_Success); + + MITK_TEST(GetGeometryForSingleTimeGeometries_Failure); + + MITK_TEST(TestingExpand_Success); + + MITK_TEST(TestingGetUpdateGeometry_Success); + + MITK_TEST(GetOriginOfBaseData_Success); + MITK_TEST(GetOriginOfCloneBaseData); + + MITK_TEST(ClearATimeStep); + + MITK_TEST(BaseDataSetAndGetProperty_Success); + MITK_TEST(CloneBaseDataSetAndGetProperty_Success); + + MITK_TEST(BasePropertyListIsSet_Success); + MITK_TEST(BasePorpertyIsSetInPropertyList_Success); + + MITK_TEST(UpdateOutputInformationOfBaseData_Failure); + MITK_TEST(CopyingInformationOfBaseData_Failure); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::BaseDataTestImplementation::Pointer m_BaseDataImpl; + mitk::BaseDataTestImplementation::Pointer m_CloneBaseData; + + mitk::TimeGeometry *m_Geo; + mitk::ProportionalTimeGeometry::Pointer m_Geo2; + + mitk::Geometry3D::Pointer m_Geometry3D; + mitk::BaseGeometry::Pointer m_Geo3; + + mitk::ScalarType m_X[3]; + mitk::PropertyList::Pointer m_PropertyList; + +public: + void setUp() override + { + m_BaseDataImpl = mitk::BaseDataTestImplementation::New(); + m_CloneBaseData = m_BaseDataImpl->Clone(); + + m_Geo = nullptr; + m_Geo2 = mitk::ProportionalTimeGeometry::New(); + + m_Geometry3D = mitk::Geometry3D::New(); + m_Geo3 = dynamic_cast(m_Geometry3D.GetPointer()); + + m_X[0] = 2; + m_X[1] = 4; + m_X[2] = 6; + + m_PropertyList = mitk::PropertyList::New(); + } + + void tearDown() override + { + m_BaseDataImpl = nullptr; + m_CloneBaseData = nullptr; + + m_Geo = nullptr; + m_Geo2 = nullptr; + + m_Geometry3D = nullptr; + m_Geo3 = nullptr; + + m_X[0] = 0; + m_X[1] = 0; + m_X[2] = 0; + + m_PropertyList = nullptr; + } + + void CreateBaseData_Success() + { + // Create a BaseData implementation + MITK_INFO << "Creating a base data instance..."; + CPPUNIT_ASSERT_MESSAGE("Testing instantiation", m_BaseDataImpl.IsNotNull()); + } + + void InitializationOfBaseData_Success() + { + CPPUNIT_ASSERT_MESSAGE("BaseDataTestImplementation is initialized", m_BaseDataImpl->IsInitialized()); + CPPUNIT_ASSERT_MESSAGE("BaseDataTestImplementation is initialized and empty", m_BaseDataImpl->IsEmpty()); + } + + void CreateCloneBaseData_Success() + { + // Create CloneBaseData implementation + MITK_INFO << "Creating a clone base data instance..."; + CPPUNIT_ASSERT_MESSAGE("Testing instantiation of base data clone", m_CloneBaseData.IsNotNull()); + } + + void InitializationOfCloneBaseData_Success() + { + CPPUNIT_ASSERT_MESSAGE("Clone of BaseDataTestImplementation is initialized", m_CloneBaseData->IsInitialized()); + CPPUNIT_ASSERT_MESSAGE("Clone of BaseDataTestImplementation is initialized and empty", m_CloneBaseData->IsEmpty()); + } + + void GetAndSetTimeGeometry_Success() + { + // test method GetTimeGeometry() + MITK_INFO << "Testing setter and getter for geometries..."; + CPPUNIT_ASSERT_MESSAGE("Testing creation of TimeGeometry", m_BaseDataImpl->GetTimeGeometry()); + } + + void ResetTimeGeometry_Success() + { + m_BaseDataImpl->SetTimeGeometry(m_Geo); + CPPUNIT_ASSERT_MESSAGE("Reset Geometry", m_BaseDataImpl->GetTimeGeometry() == nullptr); + } + + void ReinitOfTimeGeometry_Success() + { + m_BaseDataImpl->SetTimeGeometry(m_Geo2); + m_Geo2->Initialize(2); + CPPUNIT_ASSERT_MESSAGE("Correct Reinit of TimeGeometry", m_BaseDataImpl->GetTimeGeometry() == m_Geo2.GetPointer()); + } + + void GetGeometryForSingleTimeGeometries_Failure() + { + // test method GetGeometry(int timeStep) + CPPUNIT_ASSERT_MESSAGE("Testing Creation of single TimeGeometries", m_BaseDataImpl->GetGeometry(1) == nullptr); + } + + void TestingExpand_Success() + { + // test method Expand(unsigned int timeSteps) + m_BaseDataImpl->Expand(5); + CPPUNIT_ASSERT_MESSAGE("Expand the geometry to further time slices!", m_BaseDataImpl->GetTimeSteps() == 5); + } + + void TestingGetUpdateGeometry_Success() + { + // test method GetUpdatedGeometry(int timeStep); + m_BaseDataImpl->Expand(5); + mitk::ProportionalTimeGeometry::Pointer timeGeometry = + dynamic_cast(m_BaseDataImpl->GetTimeGeometry()); + if (timeGeometry.IsNotNull()) + { + timeGeometry->SetTimeStepGeometry(m_Geo3, 1); + } + + CPPUNIT_ASSERT_MESSAGE("Set Geometry for time step 1", m_BaseDataImpl->GetUpdatedGeometry(1) == m_Geo3); + CPPUNIT_ASSERT_MESSAGE("Check if modified time is set", m_BaseDataImpl->GetMTime() != 0); + } + + void GetOriginOfBaseData_Success() + { + m_BaseDataImpl->Expand(5); + m_BaseDataImpl->SetClonedGeometry(m_Geo3, 1); + + mitk::Point3D p3d(m_X); + m_BaseDataImpl->SetOrigin(p3d); + m_Geo3->SetOrigin(p3d); + CPPUNIT_ASSERT_MESSAGE("Testing Origin set", m_BaseDataImpl->GetGeometry(1)->GetOrigin() == m_Geo3->GetOrigin()); + } + void GetOriginOfCloneBaseData() + { + m_BaseDataImpl->Expand(5); + m_BaseDataImpl->SetClonedGeometry(m_Geo3, 1); + + mitk::Point3D p3d(m_X); + m_BaseDataImpl->SetOrigin(p3d); + m_Geo3->SetOrigin(p3d); + + m_CloneBaseData = m_BaseDataImpl->Clone(); + CPPUNIT_ASSERT_MESSAGE("Testing origin set in clone!", + m_CloneBaseData->GetGeometry(1)->GetOrigin() == m_Geo3->GetOrigin()); + } + + void ClearATimeStep() + { + CPPUNIT_ASSERT_MESSAGE("Is not empty before clear()!", !m_BaseDataImpl->IsEmptyTimeStep(1)); + m_BaseDataImpl->Clear(); + CPPUNIT_ASSERT_MESSAGE("...but afterwards!", m_BaseDataImpl->IsEmptyTimeStep(1)); + } + + void BaseDataSetAndGetProperty_Success() + { + // test method Set-/GetProperty() + m_BaseDataImpl->SetProperty("property38", mitk::StringProperty::New("testproperty")); + CPPUNIT_ASSERT_MESSAGE("Check if base property is set correctly!", + m_BaseDataImpl->GetProperty("property38")->GetValueAsString() == "testproperty"); + } + + void CloneBaseDataSetAndGetProperty_Success() + { + m_BaseDataImpl->SetProperty("property38", mitk::StringProperty::New("testproperty")); + m_CloneBaseData = m_BaseDataImpl->Clone(); + CPPUNIT_ASSERT_MESSAGE("Testing origin set in clone!", + m_CloneBaseData->GetProperty("property38")->GetValueAsString() == "testproperty"); + } + + void BasePropertyListIsSet_Success() + { + // test method Set-/GetPropertyList + m_PropertyList->SetFloatProperty("floatProperty1", 123.45); + m_PropertyList->SetBoolProperty("visibility", true); + m_PropertyList->SetStringProperty("nameXY", "propertyName"); + m_BaseDataImpl->SetPropertyList(m_PropertyList); + + CPPUNIT_ASSERT_MESSAGE("Check if base property list is set correctly!", + m_BaseDataImpl->GetPropertyList() == m_PropertyList); + } + + void BasePorpertyIsSetInPropertyList_Success() + { + m_PropertyList->SetFloatProperty("floatProperty1", 123.45); + m_PropertyList->SetBoolProperty("visibility", true); + m_PropertyList->SetStringProperty("nameXY", "propertyName"); + m_BaseDataImpl->SetPropertyList(m_PropertyList); + bool value = false; + CPPUNIT_ASSERT_MESSAGE("Check if base property is set correctly in the property list!", + m_BaseDataImpl->GetPropertyList()->GetBoolProperty("visibility", value) == true); + } + + void UpdateOutputInformationOfBaseData_Failure() + { + // test method UpdateOutputInformation() + m_BaseDataImpl->UpdateOutputInformation(); + m_Geo2->Initialize(2); + m_Geo2.GetPointer(); + CPPUNIT_ASSERT_MESSAGE("TimeGeometry update!", m_BaseDataImpl->GetUpdatedTimeGeometry() != m_Geo2); + } + + void CopyingInformationOfBaseData_Failure() + { + // Test method CopyInformation() + mitk::BaseDataTestImplementation::Pointer newBaseData = mitk::BaseDataTestImplementation::New(); + newBaseData->CopyInformation(m_BaseDataImpl); + CPPUNIT_ASSERT_MESSAGE("Check copying of Basedata Data Object!", + newBaseData->GetTimeGeometry()->CountTimeSteps() != 5); + } +}; +MITK_TEST_SUITE_REGISTRATION(mitkBaseData) diff --git a/Modules/Core/test/mitkExceptionTest.cpp b/Modules/Core/test/mitkExceptionTest.cpp index bd8c597b82..af45ca1e01 100644 --- a/Modules/Core/test/mitkExceptionTest.cpp +++ b/Modules/Core/test/mitkExceptionTest.cpp @@ -1,318 +1,369 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +// std includes +#include + +// MITK includes +#include "mitkException.h" #include "mitkExceptionMacro.h" #include "mitkTestingMacros.h" +#include + +// ITK includes #include #include -#include + +// VTK includes +#include class SpecializedTestException : public mitk::Exception { public: mitkExceptionClassMacro(SpecializedTestException, mitk::Exception); }; -class ExceptionTestClass : public itk::Object +class mitkExceptionTestSuite : public itk::Object, public mitk::TestFixture { + CPPUNIT_TEST_SUITE(mitkExceptionTestSuite); + + MITK_TEST(TestExceptionConstructor_Success); + MITK_TEST(TestSpecializedExceptionConstructor_Success); + + MITK_TEST(TestExceptionMessageStreamAddingString_Success); + MITK_TEST(TestExceptionMessageStreamAddingSingleChars_Success); + MITK_TEST(TestExceptionMessageStreamAddingObject_Success); + MITK_TEST(TestSpecializedExceptionMessageStreamAddingString); + MITK_TEST(TestExceptionMessageStreamThrowing_Success); + + MITK_TEST(TestMitkThrowMacroThrowing_Success); + MITK_TEST(TestMitkThrowMacroMessage_Success); + MITK_TEST(TestMitkThrowMacroException_Success); + MITK_TEST(TestMitkThrowMacroSpezcializedException); + + MITK_TEST(TestGetNumberOfRethrows_Success); + + MITK_TEST(TestGetRethrowDataWithNegativNumber_Success); + MITK_TEST(TestGetRethrowDataWithNumberZero_Success); + MITK_TEST(TestGetRethrowDataWithNumberOne_Success); + + MITK_TEST(TestAddRethrowData_Success); + + MITK_TEST(TestFirstRethrowDataAreStoredProperly_Success); + MITK_TEST(TestSecondRethrowDataAreStoredProperly_Success); + + MITK_TEST(TestRethrowMacro_Success); + + CPPUNIT_TEST_SUITE_END(); + +private: + bool m_ExceptionThrown; + + std::string m_MessageText; + std::string m_Message; + std::string m_File; + + int m_Line; + + mitk::Exception m_E = mitk::Exception("test.cpp", 155, "", ""); + mitk::Exception m_MyException = mitk::Exception("testfile.cpp", 111, "testmessage"); + public: - mitkClassMacroItkParent(ExceptionTestClass, itk::Object); + mitkClassMacroItkParent(mitkExceptionTestSuite, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) void throwExceptionManually() // this method is ONLY to test the constructor and no code example // normally exceptions should only be thrown by using the exception macro! { throw mitk::Exception("test.cpp", 155, "", ""); } void throwSpecializedExceptionManually() // this method is ONLY to test the constructor and no code example // normally exceptions should only be thrown by using the exception macro! { throw SpecializedTestException("test.cpp", 155, "", ""); } void throwExceptionManually(std::string message1, std::string message2) // this method is ONLY to test methods of mitk::Exception and no code example // normally exceptions should only be thrown by using the exception macro! { throw mitk::Exception("testfile.cpp", 155, message1.c_str(), "") << message2; } void throwExceptionWithThrowMacro() { mitkThrow() << "TEST EXCEPION THROWING WITH mitkThrow()"; } void throwExceptionWithThrowMacro(std::string message) { mitkThrow() << message.c_str(); } void throwSpecializedExceptionWithThrowMacro(std::string message) { mitkThrowException(mitk::Exception) << message; } void throwSpecializedExceptionWithThrowMacro2(std::string message) { mitkThrowException(SpecializedTestException) << message; } void reThrowExceptionWithReThrowMacro(std::string messageThrow, std::string messageReThrow) { try { throwExceptionWithThrowMacro(messageThrow); } catch (mitk::Exception &e) { mitkReThrow(e) << messageReThrow; } } - static void TestExceptionConstructor() + void setUp() + { + m_ExceptionThrown = false; + m_MessageText = ""; + m_Message = "invalid"; + m_File = "invalid"; + m_Line = -1; + } + + void tearDown() + { + m_ExceptionThrown = false; + m_MessageText = ""; + m_Message = ""; + m_File = ""; + m_Line = 0; + } + + void TestExceptionConstructor_Success() { - bool exceptionThrown = false; - ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); try { - myExceptionTestObject->throwExceptionManually(); + this->throwExceptionManually(); } catch (mitk::Exception) { - exceptionThrown = true; + m_ExceptionThrown = true; } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing constructor of mitkException"); + CPPUNIT_ASSERT_MESSAGE("Testing constructor of mitkException", m_ExceptionThrown); + } - exceptionThrown = false; + void TestSpecializedExceptionConstructor_Success() + { try { - myExceptionTestObject->throwSpecializedExceptionManually(); + this->throwSpecializedExceptionManually(); } catch (SpecializedTestException) { - exceptionThrown = true; + m_ExceptionThrown = true; } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown, - "Testing constructor specialized exception (deriving from mitkException)"); + CPPUNIT_ASSERT_MESSAGE("Testing constructor specialized exception (deriving from mitkException)", + m_ExceptionThrown); } - static void TestExceptionMessageStream() + //##### this methods are ONLY to test the streaming operators of the exceptions and + //##### NO code example. Please do not instantiate exceptions by yourself in normal code! + //##### Normally exceptions should only be thrown by using the exception macro! + void TestExceptionMessageStreamAddingString_Success() { - //##### this method is ONLY to test the streaming operators of the exceptions and - //##### NO code example. Please do not instantiate exceptions by yourself in normal code! - //##### Normally exceptions should only be thrown by using the exception macro! - mitk::Exception myException = mitk::Exception("testfile.cpp", 111, "testmessage"); - myException << " and additional stream"; - MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() == std::string("testmessage and additional stream"), - "Testing mitkException message stream (adding std::string)"); - - myException.SetDescription("testmessage2"); - myException << ' ' << 'a' << 'n' << 'd' << ' ' << 'c' << 'h' << 'a' << 'r' << 's'; - MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() == std::string("testmessage2 and chars"), - "Testing mitkException message stream (adding single chars)"); - - myException.SetDescription("testmessage3"); - myException << myException; // adding the object itself makes no sense but should work - MITK_TEST_CONDITION_REQUIRED(myException.GetDescription() != std::string(""), - "Testing mitkException message stream (adding object)"); + m_MyException << " and additional stream"; + CPPUNIT_ASSERT_MESSAGE("Testing mitkException message stream (adding std::string)", + m_MyException.GetDescription() == std::string("testmessage and additional stream")); + } + void TestExceptionMessageStreamAddingSingleChars_Success() + { + m_MyException.SetDescription("testmessage2"); + m_MyException << ' ' << 'a' << 'n' << 'd' << ' ' << 'c' << 'h' << 'a' << 'r' << 's'; + CPPUNIT_ASSERT_MESSAGE("Testing mitkException message stream (adding single chars)", + m_MyException.GetDescription() == std::string("testmessage2 and chars")); + } + + void TestExceptionMessageStreamAddingObject_Success() + { + m_MyException.SetDescription("testmessage3"); + m_MyException << m_MyException; // adding the object itself makes no sense but should work + CPPUNIT_ASSERT_MESSAGE("Testing mitkException message stream (adding object)", + m_MyException.GetDescription() != std::string("")); + } + + void TestSpecializedExceptionMessageStreamAddingString() + { SpecializedTestException mySpecializedException = SpecializedTestException("testfile.cpp", 111, "testmessage", "test"); mySpecializedException << " and additional stream"; - MITK_TEST_CONDITION_REQUIRED( - mySpecializedException.GetDescription() == std::string("testmessage and additional stream"), - "Testing specialized exception message stream (adding std::string)"); + CPPUNIT_ASSERT_MESSAGE("Testing specialized exception message stream (adding std::string)", + mySpecializedException.GetDescription() == std::string("testmessage and additional stream")); } - static void TestExceptionMessageStreamThrowing() + void TestExceptionMessageStreamThrowing_Success() { - bool exceptionThrown = false; - ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); std::string thrownMessage = ""; try { - myExceptionTestObject->throwExceptionManually("message1", " and message2"); + this->throwExceptionManually("message1", " and message2"); } catch (mitk::Exception &e) { thrownMessage = e.GetDescription(); - exceptionThrown = true; + m_ExceptionThrown = true; } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown && (thrownMessage == std::string("message1 and message2")), - "Testing throwing and streaming of mitk::Exception together.") + CPPUNIT_ASSERT_MESSAGE("Testing throwing and streaming of mitk::Exception together.", + m_ExceptionThrown && (thrownMessage == std::string("message1 and message2"))); } - static void TestMitkThrowMacro() + void TestMitkThrowMacroThrowing_Success() { - bool exceptionThrown = false; - ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); - // case 1: test throwing - try { - myExceptionTestObject->throwExceptionWithThrowMacro(); + this->throwExceptionWithThrowMacro(); } catch (mitk::Exception) { - exceptionThrown = true; + m_ExceptionThrown = true; } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing mitkThrow()"); + CPPUNIT_ASSERT_MESSAGE("Testing mitkThrow()", m_ExceptionThrown); + } + void TestMitkThrowMacroMessage_Success() + { // case 2: test message text - - exceptionThrown = false; - std::string messageText = ""; - try { - myExceptionTestObject->throwExceptionWithThrowMacro("test123"); + this->throwExceptionWithThrowMacro("test123"); } catch (mitk::Exception &e) { - exceptionThrown = true; - messageText = e.GetDescription(); + m_ExceptionThrown = true; + m_MessageText = e.GetDescription(); } - MITK_TEST_CONDITION_REQUIRED((exceptionThrown && (messageText == "test123")), - "Testing message test of mitkThrow()"); + CPPUNIT_ASSERT_MESSAGE("Testing message test of mitkThrow()", (m_ExceptionThrown && (m_MessageText == "test123"))); + } + void TestMitkThrowMacroException_Success() + { // case 3: specialized exception / command mitkThrow(mitk::Exception) - - exceptionThrown = false; - messageText = ""; - try { - myExceptionTestObject->throwSpecializedExceptionWithThrowMacro("test123"); + this->throwSpecializedExceptionWithThrowMacro("test123"); } catch (mitk::Exception &e) { - exceptionThrown = true; - messageText = e.GetDescription(); + m_ExceptionThrown = true; + m_MessageText = e.GetDescription(); } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown && messageText == "test123", - "Testing special exception with mitkThrow(mitk::Exception)"); + CPPUNIT_ASSERT_MESSAGE("Testing special exception with mitkThrow(mitk::Exception)", + m_ExceptionThrown && m_MessageText == "test123"); + } + void TestMitkThrowMacroSpezcializedException() + { // case 4: specialized exception / command mitkThrow(mitk::SpecializedException) - - exceptionThrown = false; - messageText = ""; - try { - myExceptionTestObject->throwSpecializedExceptionWithThrowMacro2("test123"); + this->throwSpecializedExceptionWithThrowMacro2("test123"); } catch (SpecializedTestException &e) { - exceptionThrown = true; - messageText = e.GetDescription(); + m_ExceptionThrown = true; + m_MessageText = e.GetDescription(); } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown && messageText == "test123", - "Testing special exception with mitkThrow(mitk::SpecializedException)"); + CPPUNIT_ASSERT_MESSAGE("Testing special exception with mitkThrow(mitk::SpecializedException)", + m_ExceptionThrown && m_MessageText == "test123"); } - static void TestRethrowInformation() - // this method is ONLY to test methods of mitk::Exception and no code example - // normally exceptions should only be instantiated and thrown by using the exception macros! + //##### this methods are ONLY to test methods of mitk::Exception and no code example + //##### normally exceptions should only be instantiated and thrown by using the exception macros! + void TestGetNumberOfRethrows_Success() { // first: testing rethrow information methods, when no information is stored - // case 1.1: method GetNumberOfRethrows() - mitk::Exception e = mitk::Exception("test.cpp", 155, "", ""); - MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 0, - "Testing GetNumberOfRethrows() with empty rethrow information"); + CPPUNIT_ASSERT_MESSAGE("Testing GetNumberOfRethrows() with empty rethrow information", + m_E.GetNumberOfRethrows() == 0); + } + void TestGetRethrowDataWithNegativNumber_Success() + { // case 1.2: GetRethrowData() with negative number - { - std::string file = "invalid"; - int line = -1; - std::string message = "invalid"; - e.GetRethrowData(-1, file, line, message); - MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), - "Testing GetRethrowData() with invalid rethrow number (negative)."); - } + m_E.GetRethrowData(-1, m_File, m_Line, m_Message); + CPPUNIT_ASSERT_MESSAGE("Testing GetRethrowData() with invalid rethrow number (negative).", + ((m_File == "") && (m_Line == 0) && (m_Message == ""))); + } + void TestGetRethrowDataWithNumberZero_Success() + { // case 1.3: GetRethrowData() with number 0 - { - std::string file = "invalid"; - int line = -1; - std::string message = "invalid"; - e.GetRethrowData(0, file, line, message); - MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), - "Testing GetRethrowData() with non-existing rethrow number (0)."); - } + m_E.GetRethrowData(0, m_File, m_Line, m_Message); + CPPUNIT_ASSERT_MESSAGE("Testing GetRethrowData() with non-existing rethrow number (0).", + ((m_File == "") && (m_Line == 0) && (m_Message == ""))); + } + void TestGetRethrowDataWithNumberOne_Success() + { // case 1.4: GetRethrowData() with number 1 - { - std::string file = "invalid"; - int line = -1; - std::string message = "invalid"; - e.GetRethrowData(1, file, line, message); - MITK_TEST_CONDITION_REQUIRED(((file == "") && (line == 0) && (message == "")), - "Testing GetRethrowData() with non-existing rethrow number (1)."); - } + m_E.GetRethrowData(1, m_File, m_Line, m_Message); + CPPUNIT_ASSERT_MESSAGE("Testing GetRethrowData() with non-existing rethrow number (1).", + ((m_File == "") && (m_Line == 0) && (m_Message == ""))); + } + void TestAddRethrowData_Success() + { // second: add rethrow data - e.AddRethrowData("test2.cpp", 10, "Rethrow one"); - MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 1, "Testing adding of rethrow data."); - e.AddRethrowData("test3.cpp", 15, "Rethrow two"); - MITK_TEST_CONDITION_REQUIRED(e.GetNumberOfRethrows() == 2, "Testing adding of more rethrow data."); + m_E.AddRethrowData("test2.cpp", 10, "Rethrow one"); + CPPUNIT_ASSERT_MESSAGE("Testing adding of rethrow data.", m_E.GetNumberOfRethrows() == 1); + m_E.AddRethrowData("test3.cpp", 15, "Rethrow two"); + CPPUNIT_ASSERT_MESSAGE("Testing adding of more rethrow data.", m_E.GetNumberOfRethrows() == 2); + } + void TestFirstRethrowDataAreStoredProperly_Success() + { // third: test if this rethrow data was stored properly - { - std::string file = "invalid"; - int line = -1; - std::string message = "invalid"; - e.GetRethrowData(0, file, line, message); - MITK_TEST_CONDITION_REQUIRED(((file == "test2.cpp") && (line == 10) && (message == "Rethrow one")), - "Testing stored information of first rethrow."); - } - - { - std::string file = "invalid"; - int line = -1; - std::string message = "invalid"; - e.GetRethrowData(1, file, line, message); - MITK_TEST_CONDITION_REQUIRED(((file == "test3.cpp") && (line == 15) && (message == "Rethrow two")), - "Testing stored information of second rethrow."); - } + m_E.AddRethrowData("test2.cpp", 10, "Rethrow one"); + m_E.GetRethrowData(0, m_File, m_Line, m_Message); + CPPUNIT_ASSERT_MESSAGE("Testing stored information of first rethrow.", + ((m_File == "test2.cpp") && (m_Line == 10) && (m_Message == "Rethrow one"))); } - static void TestRethrowMacro() + void TestSecondRethrowDataAreStoredProperly_Success() { - bool exceptionThrown = false; - std::string message = ""; - ExceptionTestClass::Pointer myExceptionTestObject = ExceptionTestClass::New(); + m_E.AddRethrowData("test2.cpp", 10, "Rethrow one"); + m_E.AddRethrowData("test3.cpp", 15, "Rethrow two"); + m_E.GetRethrowData(1, m_File, m_Line, m_Message); + CPPUNIT_ASSERT_MESSAGE("Testing stored information of second rethrow.", + ((m_File == "test3.cpp") && (m_Line == 15) && (m_Message == "Rethrow two"))); + } + void TestRethrowMacro_Success() + { // case 1: test throwing - try { - myExceptionTestObject->reThrowExceptionWithReThrowMacro("Test original message.", "Test rethrow message."); + this->reThrowExceptionWithReThrowMacro("Test original message.", "Test rethrow message."); } catch (mitk::Exception &e) { - message = e.GetDescription(); - exceptionThrown = true; + m_Message = e.GetDescription(); + m_ExceptionThrown = true; } - MITK_TEST_CONDITION_REQUIRED(exceptionThrown, "Testing mitkReThrow()"); - MITK_TEST_CONDITION_REQUIRED(message == "Test original message.Test rethrow message.", - "Testing message/descriprion after rethrow.") + CPPUNIT_ASSERT_MESSAGE("Testing mitkReThrow()", m_ExceptionThrown); + CPPUNIT_ASSERT_MESSAGE("Testing message/descriprion after rethrow.", + m_Message == "Test original message.Test rethrow message."); } }; -int mitkExceptionTest(int /*argc*/, char * /*argv*/ []) -{ - MITK_TEST_BEGIN("MITKException"); - ExceptionTestClass::TestExceptionConstructor(); - ExceptionTestClass::TestExceptionMessageStream(); - ExceptionTestClass::TestExceptionMessageStreamThrowing(); - ExceptionTestClass::TestMitkThrowMacro(); - ExceptionTestClass::TestRethrowInformation(); - ExceptionTestClass::TestRethrowMacro(); - MITK_TEST_END(); -} +MITK_TEST_SUITE_REGISTRATION(mitkException) diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Modules/Core/test/mitkImageDataItemTest.cpp index c17d46b8a7..d6049de097 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Modules/Core/test/mitkImageDataItemTest.cpp @@ -1,74 +1,73 @@ /*=================================================================== 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 "mitkTestFixture.h" #include "mitkTestingMacros.h" #include #include #include #include class mitkImageDataItemTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkImageDataItemTestSuite); MITK_TEST(TestAccessOnHugeImage); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_Image; public: void setUp() override { m_Image = mitk::Image::New(); mitk::PixelType pixelType = mitk::MakeScalarPixelType(); - std::array dimensions = {{ 1700, 1700, 1700 }}; m_Image->Initialize(pixelType, 3, dimensions.data()); } void TestAccessOnHugeImage() { CPPUNIT_ASSERT(m_Image.IsNotNull()); try { mitk::ImagePixelWriteAccessor writeAccess(m_Image.GetPointer(), m_Image->GetVolumeData()); auto* voxelStart = writeAccess.GetData(); size_t imageSize = 1; for (unsigned int i = 0; i < m_Image->GetDimension(); i++) imageSize *= m_Image->GetDimension(i); auto* voxelEnd = voxelStart + imageSize; CPPUNIT_ASSERT(writeAccess.GetData() != nullptr); auto* accessCheck = voxelEnd - 1; *accessCheck = 1; } catch (const itk::MemoryAllocationError& e) { MITK_ERROR << e.what(); exit(77); } } }; MITK_TEST_SUITE_REGISTRATION(mitkImageDataItem) diff --git a/Modules/Core/test/mitkPointSetLocaleTest.cpp b/Modules/Core/test/mitkPointSetLocaleTest.cpp index 62a82e818d..41c4cf2447 100644 --- a/Modules/Core/test/mitkPointSetLocaleTest.cpp +++ b/Modules/Core/test/mitkPointSetLocaleTest.cpp @@ -1,162 +1,198 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +// std includes +#include +#include + +// MITK includes #include "mitkIOUtil.h" #include "mitkPointSet.h" #include "mitkStandardFileLocations.h" -#include "mitkTestingMacros.h" + +// VTK includes +#include + +// stream includes #include #include -#include -#include -bool ChangeLocale(const std::string &locale) +class mitkPointSetLocaleTestSuite : public mitk::TestFixture { - try - { - MITK_TEST_OUTPUT(<< "\n** Changing locale from " << setlocale(LC_ALL, nullptr) << " to '" << locale << "'"); - setlocale(LC_ALL, locale.c_str()); + CPPUNIT_TEST_SUITE(mitkPointSetLocaleTestSuite); - std::locale l(locale.c_str()); - std::cin.imbue(l); - std::cout.imbue(l); + MITK_TEST(TestIfGermanLocaleUsed_Success); - return true; - } - catch (...) - { - MITK_TEST_OUTPUT(<< "Could not activate locale " << locale << "\n"); - return false; - } -} + CPPUNIT_TEST_SUITE_END(); -void ReaderLocaleTest(mitk::Point3D &refPoint, std::string filename) -{ - MITK_TEST_OUTPUT(<< "---- Reader Test ---- "); +private: + typedef std::list StringList; + StringList m_AllLocales; - mitk::PointSet::Pointer pointSet = mitk::IOUtil::Load(filename); + mitk::PointSet::Pointer m_RefPointSet; + mitk::Point3D m_RefPoint; - mitk::Point3D point; - if (pointSet->GetPointIfExists(0, &point)) + mitk::Point3D m_Point; + + mitk::PointSet::Pointer m_PointSet; + + bool ChangeLocale(const std::string &locale) { - MITK_TEST_CONDITION_REQUIRED(fabs(refPoint[0] - point[0]) < 0.00001, "read x correct"); - MITK_TEST_CONDITION_REQUIRED(fabs(refPoint[1] - point[1]) < 0.00001, "read y correct"); - MITK_TEST_CONDITION_REQUIRED(fabs(refPoint[2] - point[2]) < 0.00001, "read z correct"); + try + { + MITK_TEST_OUTPUT(<< "\n** Changing locale from " << setlocale(LC_ALL, nullptr) << " to '" << locale << "'"); + setlocale(LC_ALL, locale.c_str()); + + std::locale l(locale.c_str()); + std::cin.imbue(l); + std::cout.imbue(l); + return true; + } + catch (...) + { + MITK_TEST_OUTPUT(<< "Could not activate locale " << locale << "\n"); + return false; + } } - else + + void ReaderLocaleTest(mitk::Point3D &refPoint, std::string filename) { - MITK_TEST_FAILED_MSG(<< "File " << filename << " can not be read - test will not applied."); - return; + MITK_TEST_OUTPUT(<< "---- Reader Test ---- "); + + m_PointSet = mitk::IOUtil::Load(filename); + + if (m_PointSet->GetPointIfExists(0, &m_Point)) + { + CPPUNIT_ASSERT_MESSAGE("read x correct", fabs(refPoint[0] - m_Point[0]) < 0.00001); + CPPUNIT_ASSERT_MESSAGE("read y correct", fabs(refPoint[1] - m_Point[1]) < 0.00001); + CPPUNIT_ASSERT_MESSAGE("read z correct", fabs(refPoint[2] - m_Point[2]) < 0.00001); + } + else + { + MITK_TEST_FAILED_MSG(<< "File " << filename << " can not be read - test will not applied."); + return; + } } -} -void WriterLocaleTest(mitk::Point3D &refPoint, std::string filename) -{ - MITK_TEST_OUTPUT(<< "---- Writer Test---- "); - // create pointset - mitk::PointSet::Pointer refPointSet = mitk::PointSet::New(); - refPointSet->InsertPoint(0, refPoint); - // SetPoint(0, refPoint); + void WriterLocaleTest(mitk::Point3D &refPoint, std::string filename) + { + MITK_TEST_OUTPUT(<< "---- Writer Test---- "); + // create pointset + m_RefPointSet = mitk::PointSet::New(); + m_RefPointSet->InsertPoint(0, refPoint); - std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile("testPointSet_XXXXXX.mps"); + std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile("testPointSet_XXXXXX.mps"); - // write point set - mitk::IOUtil::Save(refPointSet, tmpFilePath); + // write point set + mitk::IOUtil::Save(m_RefPointSet, tmpFilePath); - std::ifstream stream(tmpFilePath.c_str()); + std::ifstream stream(tmpFilePath.c_str()); - // compare two .mps files - std::ifstream refStream(filename.c_str()); + // compare two .mps files + std::ifstream refStream(filename.c_str()); - MITK_TEST_CONDITION_REQUIRED(refStream, "Read reference point set"); - MITK_TEST_CONDITION_REQUIRED(stream, "Read point set"); + CPPUNIT_ASSERT_MESSAGE("Read reference point set", refStream); + CPPUNIT_ASSERT_MESSAGE("Read point set", stream); - bool differ = false; - if (stream.is_open() && refStream.is_open()) - { - std::string streamLine; - std::string refStreamLine; - while (!stream.eof() && !refStream.eof()) + bool differ = false; + if (stream.is_open() && refStream.is_open()) { - getline(stream, streamLine); - getline(refStream, refStreamLine); - if (streamLine.compare(refStreamLine) != 0) + std::string streamLine; + std::string refStreamLine; + while (!stream.eof() && !refStream.eof()) { - differ = true; - break; + getline(stream, streamLine); + getline(refStream, refStreamLine); + if (streamLine.compare(refStreamLine) != 0) + { + differ = true; + break; + } } + stream.close(); + refStream.close(); } - stream.close(); - refStream.close(); + CPPUNIT_ASSERT_MESSAGE("Write point set correct", !differ); } - MITK_TEST_CONDITION_REQUIRED(!differ, "Write point set correct"); -} -int mitkPointSetLocaleTest(int, char *[]) -{ - MITK_TEST_BEGIN("PointSetLocaleTest"); +public: + void setUp() + { + m_RefPointSet = mitk::PointSet::New(); + + // create locale list + m_AllLocales.push_back("de_DE"); + m_AllLocales.push_back("de_DE.utf8"); + m_AllLocales.push_back("de_DE.UTF-8"); + m_AllLocales.push_back("de_DE@euro"); + m_AllLocales.push_back("German_Germany"); + + m_RefPoint[0] = 32.2946; + m_RefPoint[1] = -17.7359; + m_RefPoint[2] = 29.6502; + } + + void tearDown() + { + m_RefPoint[0] = 0; + m_RefPoint[1] = 0; + m_RefPoint[2] = 0; - // create reference point set - mitk::PointSet::Pointer refPointSet = mitk::PointSet::New(); - mitk::Point3D refPoint; - refPoint[0] = 32.2946; - refPoint[1] = -17.7359; - refPoint[2] = 29.6502; - refPointSet->SetPoint(0, refPoint); + m_AllLocales.clear(); + } - // create locale list + void TestIfGermanLocaleUsed_Success() + { + // create reference point set + m_RefPointSet->SetPoint(0, m_RefPoint); - typedef std::list StringList; - StringList alllocales; - alllocales.push_back("de_DE"); - alllocales.push_back("de_DE.utf8"); - alllocales.push_back("de_DE.UTF-8"); - alllocales.push_back("de_DE@euro"); - alllocales.push_back("German_Germany"); - -// QuickFix for MAC OS X -// See for more the Bug #3894 comments + // QuickFix for MAC OS X + // See for more the Bug #3894 comments #if defined(__APPLE__) || defined(MACOSX) - alllocales.push_back("C"); + alllocales.push_back("C"); #endif - // write a reference file using the "C" locale once - ChangeLocale("C"); - std::string referenceFilePath = mitk::IOUtil::CreateTemporaryFile("refPointSet_XXXXXX.mps"); - MITK_INFO << "Reference PointSet in " << referenceFilePath; + // write a reference file using the "C" locale once + ChangeLocale("C"); + std::string referenceFilePath = mitk::IOUtil::CreateTemporaryFile("refPointSet_XXXXXX.mps"); + MITK_INFO << "Reference PointSet in " << referenceFilePath; - // write point set - mitk::IOUtil::Save(refPointSet, referenceFilePath); + // write point set + mitk::IOUtil::Save(m_RefPointSet, referenceFilePath); - unsigned int numberOfTestedGermanLocales(0); - for (auto iter = alllocales.begin(); iter != alllocales.end(); ++iter) - { - if (ChangeLocale(*iter)) + unsigned int numberOfTestedGermanLocales(0); + for (auto iter = m_AllLocales.begin(); iter != m_AllLocales.end(); ++iter) + { + if (ChangeLocale(*iter)) + { + ++numberOfTestedGermanLocales; + WriterLocaleTest(m_RefPoint, referenceFilePath); + ReaderLocaleTest(m_RefPoint, referenceFilePath); + } + } + + if (numberOfTestedGermanLocales == 0) { - ++numberOfTestedGermanLocales; - WriterLocaleTest(refPoint, referenceFilePath); - ReaderLocaleTest(refPoint, referenceFilePath); + MITK_TEST_OUTPUT(<< "Warning: No German locale was found on the system."); } } +}; - if (numberOfTestedGermanLocales == 0) - { - MITK_TEST_OUTPUT(<< "Warning: No German locale was found on the system."); - } - // MITK_TEST_CONDITION_REQUIRED( numberOfTestedGermanLocales > 0, "Verify that at least one German locale has been - // tested."); - MITK_TEST_END(); -} +MITK_TEST_SUITE_REGISTRATION(mitkPointSetLocale) diff --git a/Modules/Core/test/mitkSurfaceTest.cpp b/Modules/Core/test/mitkSurfaceTest.cpp index 63389c8cba..5551ab13aa 100644 --- a/Modules/Core/test/mitkSurfaceTest.cpp +++ b/Modules/Core/test/mitkSurfaceTest.cpp @@ -1,149 +1,279 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include + +// std includes +#include + +// MITK includes #include "mitkCommon.h" #include "mitkNumericTypes.h" #include "mitkSurface.h" -#include "mitkTestingMacros.h" +// MITK includes +#include + +// VTK includes #include "vtkPolyData.h" #include "vtkSphereSource.h" +// stream includes #include -int mitkSurfaceTest(int /*argc*/, char * /*argv*/ []) +class mitkSurfaceTestSuite : public mitk::TestFixture { - MITK_TEST_BEGIN("Surface"); - - mitk::Surface::Pointer surface = mitk::Surface::New(); - MITK_TEST_CONDITION_REQUIRED(surface.GetPointer(), "Testing initialization!"); - - mitk::Surface::Pointer cloneSurface = surface->Clone(); - MITK_TEST_CONDITION_REQUIRED(cloneSurface.GetPointer(), "Testing clone surface initialization!"); - - vtkSphereSource *sphereSource = vtkSphereSource::New(); - sphereSource->SetCenter(0, 0, 0); - sphereSource->SetRadius(5.0); - sphereSource->SetThetaResolution(10); - sphereSource->SetPhiResolution(10); - sphereSource->Update(); - - vtkPolyData *polys = sphereSource->GetOutput(); - MITK_TEST_CONDITION_REQUIRED(surface->GetVtkPolyData() == nullptr, "Testing initial state of vtkPolyData"); - surface->SetVtkPolyData(polys); - sphereSource->Delete(); - MITK_TEST_CONDITION_REQUIRED(surface->GetVtkPolyData() != nullptr, "Testing set vtkPolyData"); - - cloneSurface = surface->Clone(); - MITK_TEST_CONDITION_REQUIRED(cloneSurface->GetVtkPolyData() != nullptr, "Testing set vtkPolyData of cloned surface!"); - cloneSurface = nullptr; - - double bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - polys->ComputeBounds(); - polys->GetBounds(bounds); - - surface->UpdateOutputInformation(); - surface->SetRequestedRegionToLargestPossibleRegion(); - auto *bb = const_cast(surface->GetGeometry()->GetBoundingBox()); - mitk::BoundingBox::BoundsArrayType surfBounds = bb->GetBounds(); - - bool passed = false; - if (bounds[0] == surfBounds[0] && bounds[1] == surfBounds[1] && bounds[2] == surfBounds[2] && - bounds[3] == surfBounds[3] && bounds[4] == surfBounds[4] && bounds[5] == surfBounds[5]) + CPPUNIT_TEST_SUITE(mitkSurfaceTestSuite); + + MITK_TEST(InitializationSurfacePointer_Success); + MITK_TEST(InitializationCloneSurfacePointer_Success); + + MITK_TEST(StateOfVtkPolyDataEqualNullPointer_Success); + + MITK_TEST(SetVtkPolyDataNotNullPointer_Failure); + MITK_TEST(SetClonedVtkPolyDataNotNullPointer_Failure); + + MITK_TEST(GetBoundingBox_Success); + + MITK_TEST(SurfaceExpandTimestepsAreFive_Success); + MITK_TEST(Surface4DDataCreation_Success); + + MITK_TEST(TimeGeometrySurface_Success); + MITK_TEST(ChangingDataOfSpecificTimestepSurface_Success); + MITK_TEST(SurfaceCopyWithGraft_Failure); + MITK_TEST(CopyingNumberOfTimesteps_Success); + + MITK_TEST(DestructionOfSurface_Success); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Surface::Pointer m_Surface; + mitk::Surface::Pointer m_CloneSurface; + vtkSmartPointer m_SphereSource; + const mitk::TimeGeometry *m_InputTimeGeometry; + + int m_Time; + int m_Timestep; + +public: + void setUp() + { + m_Surface = mitk::Surface::New(); + m_CloneSurface = m_Surface->Clone(); + m_SphereSource = vtkSmartPointer::New(); + m_InputTimeGeometry = m_Surface->GetUpdatedTimeGeometry(); + + m_SphereSource->SetCenter(0, 0, 0); + m_SphereSource->SetRadius(5.0); + m_SphereSource->SetThetaResolution(10); + m_SphereSource->SetPhiResolution(10); + m_SphereSource->Update(); + + m_Time = 3; + m_Timestep = 0; + } + + void tearDown() + { + m_Surface = nullptr; + m_CloneSurface = nullptr; + } + + void InitializationSurfacePointer_Success() + { + CPPUNIT_ASSERT_MESSAGE("Testing initialization", m_Surface.GetPointer()); + } + + void InitializationCloneSurfacePointer_Success() + { + CPPUNIT_ASSERT_MESSAGE("Testing clone surface initialization", m_CloneSurface.GetPointer()); + } + + void StateOfVtkPolyDataEqualNullPointer_Success() + { + CPPUNIT_ASSERT_MESSAGE("Testing initial state of vtkPolyData", m_Surface->GetVtkPolyData() == nullptr); + } + + void SetVtkPolyDataNotNullPointer_Failure() + { + vtkSmartPointer polys = m_SphereSource->GetOutput(); + m_Surface->SetVtkPolyData(polys); + CPPUNIT_ASSERT_MESSAGE("Testing set vtkPolyData", m_Surface->GetVtkPolyData() != nullptr); + } + + void SetClonedVtkPolyDataNotNullPointer_Failure() + { + vtkSmartPointer polys = m_SphereSource->GetOutput(); + m_Surface->SetVtkPolyData(polys); + m_CloneSurface = m_Surface->Clone(); + CPPUNIT_ASSERT_MESSAGE("Testing set vtkPolyData of cloned surface!", m_CloneSurface->GetVtkPolyData() != nullptr); + } + + void GetBoundingBox_Success() + { + vtkSmartPointer polys = m_SphereSource->GetOutput(); + m_Surface->SetVtkPolyData(polys); + + double bounds[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + polys->ComputeBounds(); + polys->GetBounds(bounds); + + m_Surface->UpdateOutputInformation(); + m_Surface->SetRequestedRegionToLargestPossibleRegion(); + auto *bb = const_cast(m_Surface->GetGeometry()->GetBoundingBox()); + mitk::BoundingBox::BoundsArrayType surfBounds = bb->GetBounds(); + + bool passed = false; + if (bounds[0] == surfBounds[0] && bounds[1] == surfBounds[1] && bounds[2] == surfBounds[2] && + bounds[3] == surfBounds[3] && bounds[4] == surfBounds[4] && bounds[5] == surfBounds[5]) + { + passed = true; + } + + CPPUNIT_ASSERT_MESSAGE("Testing GetBoundingBox()", passed); + } + + void SurfaceExpandTimestepsAreFive_Success() { - passed = true; + m_Surface->Expand(5); + m_Surface->Update(); + m_Surface->SetRequestedRegionToLargestPossibleRegion(); + mitk::Surface::RegionType requestedRegion = m_Surface->GetRequestedRegion(); + CPPUNIT_ASSERT_MESSAGE("Testing mitk::Surface::Expand( timesteps ): ", requestedRegion.GetSize(3) == 5); } - MITK_TEST_CONDITION_REQUIRED(passed, "Testing GetBoundingBox()!"); - surface->Expand(5); - surface->Update(); - surface->SetRequestedRegionToLargestPossibleRegion(); - mitk::Surface::RegionType requestedRegion = surface->GetRequestedRegion(); - MITK_TEST_CONDITION_REQUIRED(requestedRegion.GetSize(3) == 5, "Testing mitk::Surface::Expand( timesteps ): "); + void Surface4DDataCreation_Success() + { + double boundsMat[5][6]; + + for (int i = 0; i < 5; i++) + { + vtkNew sphereSource; + sphereSource->SetCenter(0, 0, 0); + sphereSource->SetRadius(1.0 * (i + 1.0)); + sphereSource->SetThetaResolution(10); + sphereSource->SetPhiResolution(10); + sphereSource->Update(); + sphereSource->GetOutput()->ComputeBounds(); + sphereSource->GetOutput()->GetBounds(boundsMat[i]); + m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); + } + + m_Surface->UpdateOutputInformation(); + m_Surface->SetRequestedRegionToLargestPossibleRegion(); + + bool passed = true; + for (int i = 0; i < 5; i++) + { + mitk::BoundingBox::BoundsArrayType surfBounds = + (const_cast(m_Surface->GetTimeGeometry()->GetGeometryForTimeStep(i)->GetBoundingBox())) + ->GetBounds(); + + if (boundsMat[i][0] != surfBounds[0] || boundsMat[i][1] != surfBounds[1] || boundsMat[i][2] != surfBounds[2] || + boundsMat[i][3] != surfBounds[3] || boundsMat[i][4] != surfBounds[4] || boundsMat[i][5] != surfBounds[5]) + { + passed = false; + break; + } + } + CPPUNIT_ASSERT_MESSAGE("Testing mitk::Surface::Testing 4D surface data creation", passed); + } - double boundsMat[5][6]; + void TimeGeometrySurface_Success() + { + m_Timestep = m_InputTimeGeometry->TimePointToTimeStep(m_Time); + CPPUNIT_ASSERT_MESSAGE("Testing correctness of geometry for surface->GetUpdatedTimeGeometry()", + m_Time == m_Timestep); + } - for (int i = 0; i < 5; i++) + void ChangingDataOfSpecificTimestepSurface_Success() { - vtkSphereSource *sphereSource = vtkSphereSource::New(); + vtkNew sphereSource; sphereSource->SetCenter(0, 0, 0); - sphereSource->SetRadius(1.0 * (i + 1.0)); + sphereSource->SetRadius(100.0); sphereSource->SetThetaResolution(10); sphereSource->SetPhiResolution(10); sphereSource->Update(); - sphereSource->GetOutput()->ComputeBounds(); - sphereSource->GetOutput()->GetBounds(boundsMat[i]); - surface->SetVtkPolyData(sphereSource->GetOutput(), i); - sphereSource->Delete(); + m_Surface->SetVtkPolyData(sphereSource->GetOutput(), 3); + + m_Timestep = m_InputTimeGeometry->TimePointToTimeStep(m_Time); + CPPUNIT_ASSERT_MESSAGE( + "Explicitly changing the data of timestep 3 and checking for timebounds correctness of surface's geometry again", + m_Time == m_Timestep); } - surface->UpdateOutputInformation(); - surface->SetRequestedRegionToLargestPossibleRegion(); + void SurfaceCopyWithGraft_Failure() + { + double boundsMat[5][6]; + + for (int i = 0; i < 5; i++) + { + vtkNew sphereSource; + sphereSource->SetCenter(0, 0, 0); + sphereSource->SetRadius(1.0 * (i + 1.0)); + sphereSource->SetThetaResolution(10); + sphereSource->SetPhiResolution(10); + sphereSource->Update(); + sphereSource->GetOutput()->ComputeBounds(); + sphereSource->GetOutput()->GetBounds(boundsMat[i]); + m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); + } + + m_Surface->UpdateOutputInformation(); + m_Surface->SetRequestedRegionToLargestPossibleRegion(); + + mitk::Surface::Pointer dummy = mitk::Surface::New(); + dummy->Graft(m_Surface); + CPPUNIT_ASSERT_MESSAGE("Testing copying a Surface with Graft()", dummy->GetVtkPolyData() != nullptr); + } - passed = true; - for (int i = 0; i < 5; i++) + void CopyingNumberOfTimesteps_Success() { - mitk::BoundingBox::BoundsArrayType surfBounds = - (const_cast(surface->GetTimeGeometry()->GetGeometryForTimeStep(i)->GetBoundingBox())) - ->GetBounds(); + double boundsMat[5][6]; - if (boundsMat[i][0] != surfBounds[0] || boundsMat[i][1] != surfBounds[1] || boundsMat[i][2] != surfBounds[2] || - boundsMat[i][3] != surfBounds[3] || boundsMat[i][4] != surfBounds[4] || boundsMat[i][5] != surfBounds[5]) + for (int i = 0; i < 5; i++) { - passed = false; - break; + vtkNew sphereSource; + sphereSource->SetCenter(0, 0, 0); + sphereSource->SetRadius(1.0 * (i + 1.0)); + sphereSource->SetThetaResolution(10); + sphereSource->SetPhiResolution(10); + sphereSource->Update(); + sphereSource->GetOutput()->ComputeBounds(); + sphereSource->GetOutput()->GetBounds(boundsMat[i]); + m_Surface->SetVtkPolyData(sphereSource->GetOutput(), i); } + + m_Surface->UpdateOutputInformation(); + m_Surface->SetRequestedRegionToLargestPossibleRegion(); + + unsigned int numberoftimesteps = m_Surface->GetTimeSteps(); + mitk::Surface::Pointer dummy = mitk::Surface::New(); + dummy->Graft(m_Surface); + + CPPUNIT_ASSERT_MESSAGE(" Old timesteps == copy of timesteps ", dummy->GetTimeSteps() == numberoftimesteps); + } + + void DestructionOfSurface_Success() + { + m_Surface = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing destruction of surface", m_Surface.IsNull()); } - MITK_TEST_CONDITION_REQUIRED(passed, "Testing mitk::Surface::Testing 4D surface data creation!"); - - const mitk::TimeGeometry *inputTimeGeometry = surface->GetUpdatedTimeGeometry(); - - int time = 3; - int timestep = 0; - timestep = inputTimeGeometry->TimePointToTimeStep(time); - MITK_TEST_CONDITION_REQUIRED(time == timestep, - "Testing correctness of geometry for surface->GetUpdatedTimeGeometry()!"); - - sphereSource = vtkSphereSource::New(); - sphereSource->SetCenter(0, 0, 0); - sphereSource->SetRadius(100.0); - sphereSource->SetThetaResolution(10); - sphereSource->SetPhiResolution(10); - sphereSource->Update(); - surface->SetVtkPolyData(sphereSource->GetOutput(), 3); - sphereSource->Delete(); - - inputTimeGeometry = surface->GetUpdatedTimeGeometry(); - time = 3; - - timestep = inputTimeGeometry->TimePointToTimeStep(time); - MITK_TEST_CONDITION_REQUIRED( - time == timestep, - "Explicitly changing the data of timestep 3 and checking for timebounds correctness of surface's geometry again!"); - - unsigned int numberoftimesteps = surface->GetTimeSteps(); - mitk::Surface::Pointer dummy = mitk::Surface::New(); - dummy->Graft(surface); - MITK_TEST_CONDITION_REQUIRED(dummy->GetVtkPolyData() != nullptr, "Testing copying a Surface with Graft()!"); - MITK_TEST_CONDITION_REQUIRED( - dummy->GetTimeSteps() == numberoftimesteps, - "orig-numberofTimeSteps:" << numberoftimesteps << " copy-numberofTimeSteps:" << dummy->GetTimeSteps()); - - surface = nullptr; - MITK_TEST_CONDITION_REQUIRED(surface.IsNull(), "Testing destruction of surface!"); - - MITK_TEST_END(); -} +}; +MITK_TEST_SUITE_REGISTRATION(mitkSurface) diff --git a/Modules/Core/test/mitkTinyXMLTest.cpp b/Modules/Core/test/mitkTinyXMLTest.cpp index b810c8f3c9..69dd7575aa 100644 --- a/Modules/Core/test/mitkTinyXMLTest.cpp +++ b/Modules/Core/test/mitkTinyXMLTest.cpp @@ -1,158 +1,164 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include -#include "mitkTestingMacros.h" - -#include - +// std includes #include #include #include #include +// MITK includes +#include "mitkStringProperty.h" +#include + +// itksys #include -static const std::string filename = itksys::SystemTools::GetCurrentWorkingDirectory() + "/TinyXMLTest.txt"; -static const std::string elementToStoreAttributeName = "DoubleTest"; -static const std::string attributeToStoreName = "CommaValue"; +// VTK includes +#include -static double calcPrecision(const unsigned int requiredDecimalPlaces) -{ - return pow(10.0, -1.0 * ((double)requiredDecimalPlaces)); -} - -/** - * create a simple xml document which stores the values - * @param valueToWrite value which should be stored - * @return true, if document was successfully created. - */ -static bool Setup(double valueToWrite) -{ - // 1. create simple document - TiXmlDocument document; - auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc.... - document.LinkEndChild(decl); - - auto version = new TiXmlElement("Version"); - version->SetAttribute("Writer", __FILE__); - version->SetAttribute("CVSRevision", "$Revision: 17055 $"); - version->SetAttribute("FileVersion", 1); - document.LinkEndChild(version); - - // 2. store one element containing a double value with potentially many after comma digits. - auto vElement = new TiXmlElement(elementToStoreAttributeName); - vElement->SetDoubleAttribute(attributeToStoreName, valueToWrite); - document.LinkEndChild(vElement); - - // 3. store in file. - return document.SaveFile(filename); -} - -static int readValueFromSetupDocument(double &readOutValue) +// vnl includes +#include + +class mitkTinyXMLTestSuite : public mitk::TestFixture { - TiXmlDocument document; + CPPUNIT_TEST_SUITE(mitkTinyXMLTestSuite); + + MITK_TEST(TestingFunctionSetupWorks_Success); + MITK_TEST(TestingReadValueFromSetupDocument_Success); + MITK_TEST(TestingReadOutValueWorks_Success); + MITK_TEST(TestDoubleValueWriteOut_Success); + MITK_TEST(TestDoubleValueWriteOutManyDecimalPlaces_Success); - if (!document.LoadFile(filename)) + CPPUNIT_TEST_SUITE_END(); + +private: + const std::string m_Filename = itksys::SystemTools::GetCurrentWorkingDirectory() + "/TinyXMLTest.txt"; + const std::string m_ElementToStoreAttributeName = "DoubleTest"; + const std::string m_AttributeToStoreName = "CommaValue"; + + TiXmlDocument m_Document; + TiXmlElement *m_DoubleTest; + + double calcPrecision(const unsigned int requiredDecimalPlaces) { - MITK_TEST_CONDITION_REQUIRED(false, "Test Setup failed, could not open " << filename); - return TIXML_NO_ATTRIBUTE; + return pow(10.0, -1.0 * ((double)requiredDecimalPlaces)); } - else + + bool Setup(double valueToWrite) { - TiXmlElement *doubleTest = document.FirstChildElement(elementToStoreAttributeName); - return doubleTest->QueryDoubleAttribute(attributeToStoreName, &readOutValue); + // 1. create simple document + auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc.... + m_Document.LinkEndChild(decl); + + auto version = new TiXmlElement("Version"); + version->SetAttribute("Writer", __FILE__); + version->SetAttribute("CVSRevision", "$Revision: 17055 $"); + version->SetAttribute("FileVersion", 1); + m_Document.LinkEndChild(version); + + // 2. store one element containing a double value with potentially many after comma digits. + auto vElement = new TiXmlElement(m_ElementToStoreAttributeName); + vElement->SetDoubleAttribute(m_AttributeToStoreName, valueToWrite); + m_Document.LinkEndChild(vElement); + + // 3. store in file. + return m_Document.SaveFile(m_Filename); } -} -/** - * - * @return true if TearDown was successful. - */ -static bool TearDown() -{ - return !remove(filename.c_str()); -} - -static void Test_Setup_works() -{ - MITK_TEST_CONDITION_REQUIRED( - Setup(1.0) && TearDown(), - "Test if setup and teardown correctly writes data to " << filename << " and deletes the file after the test"); -} - -/** - * this first test ensures we can correctly readout values from the - * TinyXMLDocument. - */ -static void Test_ReadOutValue_works() -{ - Setup(1.0); +public: + void setUp() {} - double readValue; + void tearDown() {} - MITK_TEST_CONDITION_REQUIRED(TIXML_SUCCESS == readValueFromSetupDocument(readValue), - "checking if readout mechanism works."); -} - -static void Test_DoubleValueWriteOut() -{ - const double valueToWrite = -1.123456; - const int validDigitsAfterComma = 6; // indicates the number of valid digits after comma of valueToWrite - const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); - double readValue; + void TestingFunctionSetupWorks_Success() + { + CPPUNIT_ASSERT_MESSAGE("Test if Setup correctly writes data to file", Setup(1.0)); + } - Setup(valueToWrite); + int readValueFromSetupDocument(double &readOutValue) + { + if (!m_Document.LoadFile(m_Filename)) + { + CPPUNIT_ASSERT_MESSAGE("Test Setup failed, could not open file", false); + return TIXML_NO_ATTRIBUTE; + } + else + { + m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName); + return m_DoubleTest->QueryDoubleAttribute(m_AttributeToStoreName, &readOutValue); + } + } - readValueFromSetupDocument(readValue); + void TestingReadValueFromSetupDocument_Success() + { + if (!m_Document.LoadFile(m_Filename)) + { + CPPUNIT_ASSERT_MESSAGE("Test Setup failed, could not open file", !m_Document.LoadFile(m_Filename)); + } + else + { + m_DoubleTest = m_Document.FirstChildElement(m_ElementToStoreAttributeName); + CPPUNIT_ASSERT_MESSAGE("Test Setup could open file", m_DoubleTest != nullptr); + } + } - MITK_TEST_CONDITION_REQUIRED( - mitk::Equal(valueToWrite, readValue, neededPrecision), - std::setprecision(validDigitsAfterComma) << "Testing if value " << valueToWrite << " equals " << readValue - << " which was retrieved from TinyXML document"); + /** + * this first test ensures we can correctly readout values from the + * TinyXMLDocument. + */ + void TestingReadOutValueWorks_Success() + { + double readValue; - TearDown(); -} + CPPUNIT_ASSERT_MESSAGE("checking if readout mechanism works.", + TIXML_SUCCESS == readValueFromSetupDocument(readValue)); + } -static void Test_DoubleValueWriteOut_manyDecimalPlaces() -{ - const double valueToWrite = -1.12345678910111; - const int validDigitsAfterComma = 14; // indicates the number of valid digits after comma of valueToWrite - const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); - double readValue; + void TestDoubleValueWriteOut_Success() + { + const double valueToWrite = -1.123456; + const int validDigitsAfterComma = 6; // indicates the number of valid digits after comma of valueToWrite + const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); + double readValue; - Setup(valueToWrite); + Setup(valueToWrite); + readValueFromSetupDocument(readValue); - readValueFromSetupDocument(readValue); + CPPUNIT_ASSERT_MESSAGE("Testing if value valueToWrite equals readValue which was retrieved from TinyXML document", + mitk::Equal(valueToWrite, readValue, neededPrecision)); + } - MITK_TEST_CONDITION_REQUIRED( - mitk::Equal(valueToWrite, readValue, neededPrecision), - std::setprecision(validDigitsAfterComma) << "Testing if value " << valueToWrite << " equals " << readValue - << " which was retrieved from TinyXML document"); + void TestDoubleValueWriteOutManyDecimalPlaces_Success() + { + const double valueToWrite = -1.12345678910111; + const int validDigitsAfterComma = 14; // indicates the number of valid digits after comma of valueToWrite + const double neededPrecision = calcPrecision(validDigitsAfterComma + 1); + double readValue; - TearDown(); -} + Setup(valueToWrite); -int mitkTinyXMLTest(int /* argc */, char * /*argv*/ []) -{ - MITK_TEST_BEGIN("TinyXMLTest"); + readValueFromSetupDocument(readValue); - Test_Setup_works(); - Test_ReadOutValue_works(); - Test_DoubleValueWriteOut(); - Test_DoubleValueWriteOut_manyDecimalPlaces(); + CPPUNIT_ASSERT_MESSAGE("Testing if value valueToWrite equals readValue which was retrieved from TinyXML document", + mitk::Equal(valueToWrite, readValue, neededPrecision)); + } +}; - MITK_TEST_END() -} +MITK_TEST_SUITE_REGISTRATION(mitkTinyXML) diff --git a/Modules/Core/test/mitkVectorTest.cpp b/Modules/Core/test/mitkVectorTest.cpp index 3b0ec9ebbf..720c7a1d15 100644 --- a/Modules/Core/test/mitkVectorTest.cpp +++ b/Modules/Core/test/mitkVectorTest.cpp @@ -1,171 +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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" +#include + +// std includes +#include +// MITK includes +#include "mitkStringProperty.h" #include -#include +// itksys +#include "itkImage.h" + +// VTK includes +#include + +// vnl includes #include -int mitkVectorTest(int /*argc*/, char * /*argv*/ []) +class mitkVectorTestSuite : public mitk::TestFixture { - MITK_TEST_BEGIN("mitkVector"); - // test itk vector equality methods - itk::Vector itkVector_1; - itkVector_1[0] = 4.6; - itkVector_1[1] = 9.76543; - itkVector_1[2] = 746.09; - - itk::Vector itkVector_2; - itk::Vector itkVector_3; - for (int i = 0; i < 3; i++) - { - itkVector_2[i] = itkVector_1[i] - mitk::eps * 1.1; - itkVector_3[i] = itkVector_1[i] - mitk::eps * 0.9; - } - - MITK_TEST_CONDITION(mitk::Equal(itkVector_1, itkVector_1), - "Test vector equality using the same vector with mitk::eps"); - MITK_TEST_CONDITION( - !mitk::Equal(itkVector_1, itkVector_2), - "Test vector equality using different vectors with an element-wise difference greater than mitk::eps"); - MITK_TEST_CONDITION(mitk::Equal(itkVector_1, itkVector_2, mitk::eps * 1.2), - "Vectors are equal for higher epsilon tolerance ( 1.2 * mitk::eps )"); - MITK_TEST_CONDITION( - mitk::Equal(itkVector_1, itkVector_3), - "Test vector equality using different vectors with an element-wise difference less than mitk::eps"); - // test itk point equality methods - itk::Point itkPoint_1; - itk::Point itkPoint_2; - itk::Point itkPoint_3; - for (int i = 0; i < 3; i++) - { - itkPoint_1[i] = itkVector_1[i]; - itkPoint_2[i] = itkVector_2[i]; - itkPoint_3[i] = itkVector_3[i]; - } - MITK_TEST_CONDITION(mitk::Equal(itkPoint_1, itkPoint_1), "Test point equality using the same point with mitk::eps"); - MITK_TEST_CONDITION( - !mitk::Equal(itkPoint_1, itkPoint_2), - "Test point equality using different points with an element-wise difference greater than mitk::eps"); - MITK_TEST_CONDITION(mitk::Equal(itkPoint_1, itkPoint_2, mitk::eps * 1.2), - "Points are equal for higher epsilon tolerance ( 1.2 * mitk::eps )"); - MITK_TEST_CONDITION(mitk::Equal(itkPoint_1, itkPoint_3), - "Test point equality using different points with an element-wise difference less than mitk::eps"); - // test mitk vnl vector equality methods - mitk::VnlVector mitk_vnl_vector_1(3); - mitk::VnlVector mitk_vnl_vector_2(3); - mitk::VnlVector mitk_vnl_vector_3(3); - for (int i = 0; i < 3; i++) - { - mitk_vnl_vector_1.put(i, itkVector_1[i]); - mitk_vnl_vector_2.put(i, itkVector_2[i]); - mitk_vnl_vector_3.put(i, itkVector_1[i]); - } - - MITK_TEST_CONDITION(mitk::Equal(mitk_vnl_vector_1, mitk_vnl_vector_1), - "Test mitk vnl vector equality using the same mitk vnl vector with mitk::eps"); - MITK_TEST_CONDITION(!mitk::Equal(mitk_vnl_vector_1, mitk_vnl_vector_2), - "Test mitk vnl vector equality using different mitk vnl vectors with an element-wise difference " - "greater than mitk::eps"); - MITK_TEST_CONDITION(mitk::Equal(mitk_vnl_vector_1, mitk_vnl_vector_2, mitk::eps * 1.2), - "Vnl vectors are equal for higher epsilon tolerance ( 1.2 * mitk::eps )"); - MITK_TEST_CONDITION(mitk::Equal(mitk_vnl_vector_1, mitk_vnl_vector_3), - "Test mitk vnl vector equality using " - "different mitk vnl vectors with an " - "element-wise difference less than mitk::eps"); - - // test vnl_vector equality method + CPPUNIT_TEST_SUITE(mitkVectorTestSuite); + + MITK_TEST(ItkVecorEqualityUsingSameVector_Success); + MITK_TEST(ItkVecorEqualityUsingDifferentVectors_Failure); + MITK_TEST(ItkVecorEqualityForHigherEpsilonTolerance_Success); + MITK_TEST(ItkVecorEqualityUsingDifferentVectorsWithElementWise_Success); + + MITK_TEST(ItkPointEqualitySamePoint_Success); + MITK_TEST(ItkPointEqualityDifferentPoints_Failure); + MITK_TEST(ItkPointEqualitForHigherEpsilons_Success); + MITK_TEST(ItkPointEqualitDifferentPointsWithElementWise_Success); + + MITK_TEST(MitkVnlVectorEqualitySameMitkVnlVector_Success); + MITK_TEST(MitkVnlVectorEqualityDifferentMitkVnlVectors_Failure); + MITK_TEST(MitkVnlVectorEqualityHigherEpsilon_Success); + MITK_TEST(MitkVnlVectorEqualityUsingDifferentMitkVnlVectorsWithElementWise_Success); + + MITK_TEST(VnlVectorEqualitySameVnlVector_Success); + MITK_TEST(VnlVectorEqualityDifferentVnlVectors_Failure); + MITK_TEST(VnlVectorEqualityDifferentVnlVectorsWithHighEps_Success); + MITK_TEST(VnlVectorEqualityDifferentVnlVectorsWithLowEps_Success); + MITK_TEST(VnlVectorEqualityDifferentVnlVectorsWithLowEps_Failure); + + MITK_TEST(ScalarEqualitySameScalar_Successs); + MITK_TEST(ScalarEqualityDifferentScalarsDifferenceGreaterEps_Failure); + MITK_TEST(ScalarEqualityDifferentScalarsDifferenceEqualEps_Successs); + MITK_TEST(ScalarEqualityDifferentScalarsDifferenceLessEps_Successs); + + MITK_TEST(MatrixEqualitySameMatrixElementsWithEps_Success); + MITK_TEST(MatrixEqualityElementWiseDifferentMatrixElementsWithEpsilonZero_Failure); + MITK_TEST(MatrixEqualityDifferentMatrixElementsWithEpsilon_Success); + MITK_TEST(MatrixEqualityRMSDifferentMatrixElementsWithEpsilon_Failure); + MITK_TEST(MatrixEqualityRMSDifferentMatrixElementsWithEpsilonZero_Success); + + CPPUNIT_TEST_SUITE_END(); + +private: + itk::Vector m_ItkVector_1; + itk::Vector m_ItkVector_2; + itk::Vector m_ItkVector_3; + + itk::Point m_ItkPoint_1; + itk::Point m_ItkPoint_2; + itk::Point m_ItkPoint_3; + typedef mitk::ScalarType VnlValueType; - vnl_vector_fixed vnlVector_1; - vnlVector_1[3] = 56.98; - vnlVector_1[4] = 22.32; - vnlVector_1[5] = 1.00; - vnlVector_1[6] = 746.09; - vnl_vector_fixed vnlVector_2; - vnl_vector_fixed vnlVector_3; - for (int i = 0; i < 7; i++) + vnl_vector_fixed m_VnlVector_1; + vnl_vector_fixed m_VnlVector_2; + vnl_vector_fixed m_VnlVector_3; + + mitk::ScalarType m_Scalar1; + mitk::ScalarType m_Scalar2; + mitk::ScalarType m_Scalar3; + mitk::ScalarType m_Scalar4; + + vnl_matrix_fixed m_VnlMatrix3x3_1; + vnl_matrix_fixed m_VnlMatrix3x3_2; + + mitk::ScalarType m_Epsilon; + +public: + void setUp() + { + m_ItkVector_1[0] = 4.6; + m_ItkVector_1[1] = 9.76543; + m_ItkVector_1[2] = 746.09; + + m_VnlVector_1[0] = 4.6; + m_VnlVector_1[1] = 9.76543; + m_VnlVector_1[2] = 746.09; + m_VnlVector_1[3] = 56.98; + m_VnlVector_1[4] = 22.32; + m_VnlVector_1[5] = 1.00; + m_VnlVector_1[6] = 746.09; + + m_Scalar1 = 0.5689; + m_Scalar2 = m_Scalar1 + mitk::eps * 1.01; + m_Scalar3 = m_Scalar1; + m_Scalar4 = m_Scalar1 + mitk::eps * 0.95; + + m_VnlMatrix3x3_1(0, 0) = 1.1; + m_VnlMatrix3x3_1(0, 1) = 0.4; + m_VnlMatrix3x3_1(0, 2) = 5.3; + m_VnlMatrix3x3_1(1, 0) = 2.7; + m_VnlMatrix3x3_1(1, 1) = 3578.56418; + m_VnlMatrix3x3_1(1, 2) = 123.56; + m_VnlMatrix3x3_1(2, 0) = 546.89; + m_VnlMatrix3x3_1(2, 1) = 0.0001; + m_VnlMatrix3x3_1(2, 2) = 1.0; + + m_VnlMatrix3x3_2(0, 0) = 1.1000009; + m_VnlMatrix3x3_2(0, 1) = 0.4000009; + m_VnlMatrix3x3_2(0, 2) = 5.3000009; + m_VnlMatrix3x3_2(1, 0) = 2.7000009; + m_VnlMatrix3x3_2(1, 1) = 3578.5641809; + m_VnlMatrix3x3_2(1, 2) = 123.5600009; + m_VnlMatrix3x3_2(2, 0) = 546.8900009; + m_VnlMatrix3x3_2(2, 1) = 0.0001009; + m_VnlMatrix3x3_2(2, 2) = 1.0000009; + + m_Epsilon = 0.000001; + } + + void tearDown() + { + m_ItkVector_1.Fill(0); + m_ItkVector_2.Fill(0); + m_ItkVector_3.Fill(0); + m_ItkPoint_1.Fill(0); + m_ItkPoint_2.Fill(0); + m_ItkPoint_3.Fill(0); + + m_VnlVector_1.fill(0); + m_VnlVector_2.fill(0); + m_VnlVector_3.fill(0); + + m_Scalar1 = 0; + m_Scalar2 = 0; + m_Scalar3 = 0; + m_Scalar4 = 0; + + m_VnlMatrix3x3_1.fill(0); + m_VnlMatrix3x3_2.fill(0); + } + + void ItkVecorEqualityUsingSameVector_Success() + { + CPPUNIT_ASSERT_MESSAGE("Test vector equality using the same vector with mitk::eps", + mitk::Equal(m_ItkVector_1, m_ItkVector_1)); + } + + void ItkVecorEqualityUsingDifferentVectors_Failure() + { + for (int i = 0; i < 3; i++) + { + m_ItkVector_2[i] = m_ItkVector_1[i] - mitk::eps * 1.1; + } + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test vector equality using different vectors with an element-wise difference greater than mitk::eps", + mitk::Equal(m_ItkVector_1, m_ItkVector_2)); + } + + void ItkVecorEqualityForHigherEpsilonTolerance_Success() + { + for (int i = 0; i < 3; i++) + { + m_ItkVector_2[i] = m_ItkVector_1[i] - mitk::eps * 1.1; + } + CPPUNIT_ASSERT_MESSAGE("Vectors are equal for higher epsilon tolerance ( 1.2 * mitk::eps )", + mitk::Equal(m_ItkVector_1, m_ItkVector_2, mitk::eps * 1.2)); + } + + void ItkVecorEqualityUsingDifferentVectorsWithElementWise_Success() + { + for (int i = 0; i < 3; i++) + { + m_ItkVector_3[i] = m_ItkVector_1[i] - mitk::eps * 0.9; + } + CPPUNIT_ASSERT_MESSAGE( + "Test vector equality using different vectors with an element-wise difference less than mitk::eps", + mitk::Equal(m_ItkVector_1, m_ItkVector_3)); + } + + void ItkPointEqualitySamePoint_Success() + { + // test itk point equality methods + for (int i = 0; i < 3; i++) + { + m_ItkPoint_1[i] = m_ItkVector_1[i]; + } + CPPUNIT_ASSERT_MESSAGE("Test point equality using the same point with mitk::eps", + mitk::Equal(m_ItkPoint_1, m_ItkPoint_1)); + } + + void ItkPointEqualityDifferentPoints_Failure() + { + for (int i = 0; i < 3; i++) + { + m_ItkPoint_1[i] = m_ItkVector_1[i]; + m_ItkPoint_2[i] = m_ItkVector_2[i]; + } + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test point equality using different points with an element-wise difference greater than mitk::eps", + mitk::Equal(m_ItkPoint_1, m_ItkPoint_2)); + } + + void ItkPointEqualitForHigherEpsilons_Success() + { + for (int i = 0; i < 3; i++) + { + m_ItkVector_2[i] = m_ItkVector_1[i] - mitk::eps * 1.1; + } + + for (int i = 0; i < 3; i++) + { + m_ItkPoint_1[i] = m_ItkVector_1[i]; + m_ItkPoint_2[i] = m_ItkVector_2[i]; + } + CPPUNIT_ASSERT_MESSAGE("Points are equal for higher epsilon tolerance ( 1.2 * mitk::eps )", + mitk::Equal(m_ItkPoint_1, m_ItkPoint_2, mitk::eps * 1.2)); + } + + void ItkPointEqualitDifferentPointsWithElementWise_Success() + { + for (int i = 0; i < 3; i++) + { + m_ItkVector_3[i] = m_ItkVector_1[i] - mitk::eps * 0.9; + } + + for (int i = 0; i < 3; i++) + { + m_ItkPoint_1[i] = m_ItkVector_1[i]; + m_ItkPoint_3[i] = m_ItkVector_3[i]; + } + CPPUNIT_ASSERT_MESSAGE( + "Test point equality using different points with an element-wise difference less than mitk::eps", + mitk::Equal(m_ItkPoint_1, m_ItkPoint_3)); + } + + void MitkVnlVectorEqualitySameMitkVnlVector_Success() + { + mitk::VnlVector mitkVnlVector_1(3); + + for (int i = 0; i < 3; i++) + { + mitkVnlVector_1.put(i, m_ItkVector_1[i]); + } + + CPPUNIT_ASSERT_MESSAGE("Test mitk vnl vector equality using the same mitk vnl vector with mitk::eps", + mitk::Equal(mitkVnlVector_1, mitkVnlVector_1)); + } + + void MitkVnlVectorEqualityDifferentMitkVnlVectors_Failure() + { + mitk::VnlVector mitkVnlVector_1(3); + mitk::VnlVector mitkVnlVector_2(3); + + for (int i = 0; i < 3; i++) + { + mitkVnlVector_1.put(i, m_ItkVector_1[i]); + mitkVnlVector_2.put(i, m_ItkVector_2[i]); + } + + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test mitk vnl vector equality using different mitk vnl vectors with an element-wise difference " + "greater than mitk::eps", + mitk::Equal(mitkVnlVector_1, mitkVnlVector_2)); + } + + void MitkVnlVectorEqualityHigherEpsilon_Success() + { + mitk::VnlVector mitkVnlVector_1(3); + mitk::VnlVector mitkVnlVector_2(3); + + for (int i = 0; i < 3; i++) + { + m_ItkVector_2[i] = m_ItkVector_1[i] - mitk::eps * 1.1; + } + + for (int i = 0; i < 3; i++) + { + mitkVnlVector_1.put(i, m_ItkVector_1[i]); + mitkVnlVector_2.put(i, m_ItkVector_2[i]); + } + + CPPUNIT_ASSERT_MESSAGE("Vnl vectors are equal for higher epsilon tolerance ( 1.2 * mitk::eps )", + mitk::Equal(mitkVnlVector_1, mitkVnlVector_2, mitk::eps * 1.2)); + } + + void MitkVnlVectorEqualityUsingDifferentMitkVnlVectorsWithElementWise_Success() { - if (i < 3) + mitk::VnlVector mitkVnlVector_1(3); + mitk::VnlVector mitkVnlVector_3(3); + + for (int i = 0; i < 3; i++) + { + m_ItkVector_3[i] = m_ItkVector_1[i] - mitk::eps * 0.9; + } + + for (int i = 0; i < 3; i++) { - vnlVector_1.put(i, itkVector_1[i]); + mitkVnlVector_1.put(i, m_ItkVector_1[i]); + mitkVnlVector_3.put(i, m_ItkVector_3[i]); } - vnlVector_2[i] = vnlVector_1[i] - mitk::eps * 1.1f; - vnlVector_3[i] = vnlVector_1[i] - mitk::eps * 0.9f; + CPPUNIT_ASSERT_MESSAGE("Test mitk vnl vector equality using " + "different mitk vnl vectors with an " + "element-wise difference less than mitk::eps", + mitk::Equal(mitkVnlVector_1, mitkVnlVector_3)); + } + + void VnlVectorEqualitySameVnlVector_Success() + { + // test vnl_vector equality method + + CPPUNIT_ASSERT_MESSAGE("vnl_fixed : v_1 == v_1 ", (mitk::Equal(m_VnlVector_1, m_VnlVector_1))); } - MITK_TEST_CONDITION((mitk::Equal(vnlVector_1, vnlVector_1)), "vnl_fixed : v_1 == v_1 "); // the v_2 is constructed so that the equality test fails for mitk::eps, the norm of the difference between the // vectors is 7 * eps/6.9 - MITK_TEST_CONDITION(!(mitk::Equal(vnlVector_1, vnlVector_2)), - "vnl_fixed : v_1 != v_2 with mitk::eps "); + void VnlVectorEqualityDifferentVnlVectors_Failure() + { + for (int i = 0; i < 7; i++) + { + m_VnlVector_2[i] = m_VnlVector_1[i] - mitk::eps * 1.1f; + } + + CPPUNIT_ASSERT_NO_THROW_MESSAGE("vnl_fixed : v_1 != v_2 with mitk::eps ", + (mitk::Equal(m_VnlVector_1, m_VnlVector_2))); + } + // increase the epsilon value used for testing equality - should now pass ( 1.2 * mitk::eps > 7 * mitk::eps/6.9 ) - MITK_TEST_CONDITION((mitk::Equal(vnlVector_1, vnlVector_2, mitk::eps * 1.2f)), - "vnl_fixed : v_1 == v_2 with eps = 1.2 * mitk::eps "); - MITK_TEST_CONDITION((mitk::Equal(vnlVector_1, vnlVector_3, mitk::eps)), - "vnl_fixed : v_1 == v_3 with eps = 0.8 * mitk::eps "); - MITK_TEST_CONDITION(!(mitk::Equal(vnlVector_1, vnlVector_3, mitk::eps * 0.8f)), - "vnl_fixed : v_1 != v_3 with eps = 0.8 * mitk::eps "); - - // test scalar equality method - mitk::ScalarType scalar1 = 0.5689; - mitk::ScalarType scalar2 = scalar1 + mitk::eps * 1.01; - mitk::ScalarType scalar3 = scalar1; - mitk::ScalarType scalar4 = scalar1 + mitk::eps * 0.95; - MITK_TEST_CONDITION(mitk::Equal(scalar1, scalar1), "Test scalar equality using the same scalar with mitk::eps"); - MITK_TEST_CONDITION(!mitk::Equal(scalar1, scalar2), - "Test scalar equality using the different scalars with a difference greater than mitk::eps"); - MITK_TEST_CONDITION(mitk::Equal(scalar1, scalar3), - "Test scalar equality using the different scalars with a difference equal to mitk::eps"); - MITK_TEST_CONDITION(mitk::Equal(scalar1, scalar4), - "Test scalar equality using the different scalars with a difference less than mitk::eps"); - - // test matrix equality methods - vnl_matrix_fixed vnlMatrix3x3_1; - vnlMatrix3x3_1(0, 0) = 1.1; - vnlMatrix3x3_1(0, 1) = 0.4; - vnlMatrix3x3_1(0, 2) = 5.3; - vnlMatrix3x3_1(1, 0) = 2.7; - vnlMatrix3x3_1(1, 1) = 3578.56418; - vnlMatrix3x3_1(1, 2) = 123.56; - vnlMatrix3x3_1(2, 0) = 546.89; - vnlMatrix3x3_1(2, 1) = 0.0001; - vnlMatrix3x3_1(2, 2) = 1.0; - vnl_matrix_fixed vnlMatrix3x3_2; - vnlMatrix3x3_2(0, 0) = 1.1000009; - vnlMatrix3x3_2(0, 1) = 0.4000009; - vnlMatrix3x3_2(0, 2) = 5.3000009; - vnlMatrix3x3_2(1, 0) = 2.7000009; - vnlMatrix3x3_2(1, 1) = 3578.5641809; - vnlMatrix3x3_2(1, 2) = 123.5600009; - vnlMatrix3x3_2(2, 0) = 546.8900009; - vnlMatrix3x3_2(2, 1) = 0.0001009; - vnlMatrix3x3_2(2, 2) = 1.0000009; - - mitk::ScalarType epsilon = 0.000001; - MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(vnlMatrix3x3_1, vnlMatrix3x3_1, mitk::eps), - "Test for matrix equality with given epsilon=mitk::eps and exactly the same matrix elements"); - MITK_TEST_CONDITION(!mitk::MatrixEqualElementWise(vnlMatrix3x3_1, vnlMatrix3x3_2, 0.0), - "Test for matrix equality with given epsilon=0.0 and slightly different matrix elements"); - MITK_TEST_CONDITION(mitk::MatrixEqualElementWise(vnlMatrix3x3_1, vnlMatrix3x3_2, epsilon), - "Test for matrix equality with given epsilon and slightly different matrix elements"); - MITK_TEST_CONDITION(!mitk::MatrixEqualRMS(vnlMatrix3x3_1, vnlMatrix3x3_2, 0.0), - "Test for matrix equality with given epsilon=0.0 and slightly different matrix elements"); - MITK_TEST_CONDITION(mitk::MatrixEqualRMS(vnlMatrix3x3_1, vnlMatrix3x3_2, epsilon), - "Test for matrix equality with given epsilon and slightly different matrix elements"); - - MITK_TEST_END(); -} + void VnlVectorEqualityDifferentVnlVectorsWithHighEps_Success() + { + for (int i = 0; i < 7; i++) + { + m_VnlVector_2[i] = m_VnlVector_1[i] - mitk::eps * 1.1f; + } + + CPPUNIT_ASSERT_MESSAGE("vnl_fixed : v_1 == v_2 with eps = 1.2 * mitk::eps ", + (mitk::Equal(m_VnlVector_1, m_VnlVector_2, mitk::eps * 1.2f))); + } + + void VnlVectorEqualityDifferentVnlVectorsWithLowEps_Success() + { + for (int i = 0; i < 7; i++) + { + m_VnlVector_3[i] = m_VnlVector_1[i] - mitk::eps * 0.9f; + } + + CPPUNIT_ASSERT_MESSAGE("vnl_fixed : v_1 == v_3 with eps = 0.8 * mitk::eps ", + (mitk::Equal(m_VnlVector_1, m_VnlVector_3, mitk::eps))); + } + + void VnlVectorEqualityDifferentVnlVectorsWithLowEps_Failure() + { + for (int i = 0; i < 7; i++) + { + m_VnlVector_3[i] = m_VnlVector_1[i] - mitk::eps * 0.9f; + } + + CPPUNIT_ASSERT_NO_THROW_MESSAGE("vnl_fixed : v_1 != v_3 with eps = 0.8 * mitk::eps ", + (mitk::Equal(m_VnlVector_1, m_VnlVector_3, mitk::eps * 0.8f))); + } + + void ScalarEqualitySameScalar_Successs() + { + // test scalar equality method + CPPUNIT_ASSERT_MESSAGE("Test scalar equality using the same scalar with mitk::eps", + mitk::Equal(m_Scalar1, m_Scalar1)); + } + void ScalarEqualityDifferentScalarsDifferenceGreaterEps_Failure() + { + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test scalar equality using the different scalars with a difference greater than mitk::eps", + mitk::Equal(m_Scalar1, m_Scalar2)); + } + + void ScalarEqualityDifferentScalarsDifferenceEqualEps_Successs() + { + CPPUNIT_ASSERT_MESSAGE("Test scalar equality using the different scalars with a difference equal to mitk::eps", + mitk::Equal(m_Scalar1, m_Scalar3)); + } + + void ScalarEqualityDifferentScalarsDifferenceLessEps_Successs() + { + CPPUNIT_ASSERT_MESSAGE("Test scalar equality using the different scalars with a difference less than mitk::eps", + mitk::Equal(m_Scalar1, m_Scalar4)); + } + + void MatrixEqualitySameMatrixElementsWithEps_Success() + { + // test matrix equality methods + CPPUNIT_ASSERT_MESSAGE("Test for matrix equality with given epsilon=mitk::eps and exactly the same matrix elements", + mitk::MatrixEqualElementWise(m_VnlMatrix3x3_1, m_VnlMatrix3x3_1, mitk::eps)); + } + + void MatrixEqualityElementWiseDifferentMatrixElementsWithEpsilonZero_Failure() + { + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test for matrix equality with given epsilon=0.0 and slightly different matrix elements", + mitk::MatrixEqualElementWise(m_VnlMatrix3x3_1, m_VnlMatrix3x3_2, 0.0)); + } + + void MatrixEqualityDifferentMatrixElementsWithEpsilon_Success() + { + CPPUNIT_ASSERT_MESSAGE("Test for matrix equality with given epsilon and slightly different matrix elements", + mitk::MatrixEqualElementWise(m_VnlMatrix3x3_1, m_VnlMatrix3x3_2, m_Epsilon)); + } + + void MatrixEqualityRMSDifferentMatrixElementsWithEpsilon_Failure() + { + CPPUNIT_ASSERT_NO_THROW_MESSAGE( + "Test for matrix equality with given epsilon=0.0 and slightly different matrix elements", + mitk::MatrixEqualRMS(m_VnlMatrix3x3_1, m_VnlMatrix3x3_2, 0.0)); + } + + void MatrixEqualityRMSDifferentMatrixElementsWithEpsilonZero_Success() + { + CPPUNIT_ASSERT_MESSAGE("Test for matrix equality with given epsilon and slightly different matrix elements", + mitk::MatrixEqualRMS(m_VnlMatrix3x3_1, m_VnlMatrix3x3_2, m_Epsilon)); + } +}; +MITK_TEST_SUITE_REGISTRATION(mitkVector) diff --git a/Modules/Core/test/mitkWeakPointerTest.cpp b/Modules/Core/test/mitkWeakPointerTest.cpp index 2d033c535a..5bc4633223 100644 --- a/Modules/Core/test/mitkWeakPointerTest.cpp +++ b/Modules/Core/test/mitkWeakPointerTest.cpp @@ -1,60 +1,111 @@ /*=================================================================== 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. ===================================================================*/ +// Testing +#include "mitkTestFixture.h" #include "mitkTestingMacros.h" -#include +// std includes +#include + +// MITK includes #include -int mitkWeakPointerTest(int /*argc*/, char * /*argv*/ []) +// ITK includes +#include + +class mitkWeakPointerTestSuite : public mitk::TestFixture { - MITK_TEST_BEGIN("WeakPointer") + CPPUNIT_TEST_SUITE(mitkWeakPointerTestSuite); + + MITK_TEST(EqualPointers_Success); + MITK_TEST(ExpiredWeakPointerWithSmartPointerAssignment_Success); + MITK_TEST(ExpiredWeakPointerWithWeakPointerAssignment_Success); + MITK_TEST(ExpiredWeakPointerWithSmartPointerConstructor_Success); + MITK_TEST(ExpiredWeakPointerWithWeakPointerConstructor_Success); + MITK_TEST(DeleteEventCall_Success); - int deleteEventCallbackCalled = 0; + CPPUNIT_TEST_SUITE_END(); - mitk::WeakPointer weakPointer; +private: + mitk::WeakPointer m_WeakPointer; + mitk::WeakPointer m_WeakPointer2; + itk::Object::Pointer m_SmartPointer; - weakPointer.SetDeleteEventCallback([&deleteEventCallbackCalled]() +public: + void setUp() { - ++deleteEventCallbackCalled; - }); + m_SmartPointer = itk::Object::New(); + m_WeakPointer = m_SmartPointer; + m_WeakPointer2 = m_WeakPointer; + } - mitk::WeakPointer weakPointer2; + void tearDown() + { + m_SmartPointer = nullptr; + m_WeakPointer = nullptr; + m_WeakPointer2 = nullptr; + } - // Testing constructors and reference counting - itk::Object::Pointer smartPointer = itk::Object::New(); - mitk::WeakPointer weakPointer3(smartPointer); - mitk::WeakPointer weakPointer4(weakPointer); + void EqualPointers_Success() { - itk::Object::Pointer tmpSmartPointer(weakPointer.Lock()); - itk::Object::Pointer tmpSmartPointer2(weakPointer2.Lock()); - MITK_TEST_CONDITION_REQUIRED(tmpSmartPointer.GetPointer() == tmpSmartPointer2.GetPointer(), - "Testing equal pointers"); + itk::Object::Pointer tmpSmartPointer(m_WeakPointer.Lock()); + itk::Object::Pointer tmpSmartPointer2(m_WeakPointer2.Lock()); + CPPUNIT_ASSERT_MESSAGE("Testing equal pointers", tmpSmartPointer.GetPointer() == tmpSmartPointer2.GetPointer()); } - weakPointer = smartPointer; - weakPointer2 = weakPointer; + void ReferenceCountOfPointers_Success() + { + CPPUNIT_ASSERT_MESSAGE("Testing reference count", 1 == m_SmartPointer->GetReferenceCount()); + } - MITK_TEST_CONDITION_REQUIRED(1 == smartPointer->GetReferenceCount(), "Testing reference count"); - smartPointer = nullptr; - MITK_TEST_CONDITION_REQUIRED(weakPointer.IsExpired(), "Testing expired weak pointer (smart pointer assignment)"); - MITK_TEST_CONDITION_REQUIRED(weakPointer2.IsExpired(), "Testing expired weak pointer (weak pointer assignment)"); - MITK_TEST_CONDITION_REQUIRED(weakPointer3.IsExpired(), "Testing expired weak pointer (smart pointer constructor)"); - MITK_TEST_CONDITION_REQUIRED(weakPointer4.IsExpired(), "Testing expired weak pointer (copy constructor)"); - MITK_TEST_CONDITION_REQUIRED(1 == deleteEventCallbackCalled, "Testing call of delete event callback"); + void ExpiredWeakPointerWithSmartPointerAssignment_Success() + { + m_SmartPointer = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing expired weak pointer (smart pointer assignment)", m_WeakPointer.IsExpired()); + } - MITK_TEST_END() -} + void ExpiredWeakPointerWithWeakPointerAssignment_Success() + { + m_SmartPointer = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing expired weak pointer (weak pointer assignment)", m_WeakPointer2.IsExpired()); + } + + void ExpiredWeakPointerWithSmartPointerConstructor_Success() + { + mitk::WeakPointer weakPointer3(m_SmartPointer); + m_SmartPointer = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing expired weak pointer (smart pointer constructor)", weakPointer3.IsExpired()); + } + + void ExpiredWeakPointerWithWeakPointerConstructor_Success() + { + mitk::WeakPointer weakPointer4(m_WeakPointer); + m_WeakPointer = m_SmartPointer; + m_SmartPointer = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing expired weak pointer (copy constructor)", weakPointer4.IsExpired()); + } + + void DeleteEventCall_Success() + { + int deleteEventCallbackCalled = 0; + m_WeakPointer.SetDeleteEventCallback([&deleteEventCallbackCalled]() { ++deleteEventCallbackCalled; }); + m_WeakPointer = m_SmartPointer; + m_SmartPointer = nullptr; + CPPUNIT_ASSERT_MESSAGE("Testing call of delete event callback", 1 == deleteEventCallbackCalled); + } +}; +MITK_TEST_SUITE_REGISTRATION(mitkWeakPointer) diff --git a/Modules/OpenCL/mitkOpenCL.h b/Modules/OpenCL/mitkOpenCL.h index a0147b238b..d2131a3455 100644 --- a/Modules/OpenCL/mitkOpenCL.h +++ b/Modules/OpenCL/mitkOpenCL.h @@ -1,26 +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 MITKOPENCL_H_HEADER_INCLUDED #define MITKOPENCL_H_HEADER_INCLUDED #if defined (__APPLE__) || defined(MACOSX) #include #else +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS #include #endif #endif /* MITKOPENCL_H_HEADER_INCLUDED */ diff --git a/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp b/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp index 0414cc41bd..6dff7d53c4 100644 --- a/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp +++ b/Modules/OpenIGTLink/mitkIGTLDummyMessage.cpp @@ -1,66 +1,65 @@ /*=================================================================== 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 "mitkIGTLDummyMessage.h" #include "igtl_header.h" #include "igtl_util.h" mitk::IGTLDummyMessage::IGTLDummyMessage() : StringMessage() { - this->m_DefaultBodyType = "DUMMY"; } mitk::IGTLDummyMessage::~IGTLDummyMessage() { } void mitk::IGTLDummyMessage::SetDummyString( const std::string& dummyString ) { this->m_dummyString = dummyString; this->m_String = "This is a dummy string"; } std::string mitk::IGTLDummyMessage::GetDummyString() { return this->m_dummyString; } igtl::MessageBase::Pointer mitk::IGTLDummyMessage::Clone() { //initialize the clone mitk::IGTLDummyMessage::Pointer clone = mitk::IGTLDummyMessage::New(); //copy the data clone->SetString(this->GetString()); clone->SetDummyString(this->GetDummyString()); return igtl::MessageBase::Pointer(clone.GetPointer()); } /** * \brief Clones the original message interpreted as transform message * \param original_ The original message that will be interpreted as transform * message * \return The clone of the input message */ igtl::MessageBase::Pointer mitk::DummyMsgCloneHandler::Clone(igtl::MessageBase* original_) { mitk::IGTLDummyMessage* original = (mitk::IGTLDummyMessage*)original_; return original->Clone(); } diff --git a/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp b/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp index fcf45364ec..e2f56d3fcc 100644 --- a/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp +++ b/Modules/OpenIGTLink/mitkIGTLMessageFactory.cpp @@ -1,295 +1,295 @@ /*=================================================================== 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 "mitkIGTLMessageFactory.h" // IGT message types #include "igtlImageMessage.h" #include "igtlTransformMessage.h" #include "igtlPositionMessage.h" #include "igtlStatusMessage.h" #include "igtlImageMetaMessage.h" #include "igtlPointMessage.h" #include "igtlTrajectoryMessage.h" #include "igtlStringMessage.h" #include "igtlSensorMessage.h" #include "igtlBindMessage.h" #include "igtlPolyDataMessage.h" #include "igtlQuaternionTrackingDataMessage.h" #include "igtlCapabilityMessage.h" #include "igtlNDArrayMessage.h" #include "igtlTrackingDataMessage.h" #include "igtlColorTableMessage.h" #include "igtlLabelMetaMessage.h" //own types #include "mitkIGTLDummyMessage.h" #include "mitkIGTLMessageCommon.h" #include "itksys/SystemTools.hxx" //------------------------------------------------------------ // Define message clone classes // igtlMessageHandlerClassMacro() defines a child class of // igtl::MessageHandler to handle OpenIGTLink messages for // the message type specified as the first argument. The // second argument will be used for the name of this // message handler class, while the third argument specifies // a type of data that will be shared with the message functions // of this handler class. mitkIGTMessageCloneClassMacro(igtl::TransformMessage, TransformMsgCloneHandler); /** * \brief Clones the original message interpreted as transform message * \param original_ The original message that will be interpreted as transform * message * \return The clone of the input message */ igtl::MessageBase::Pointer TransformMsgCloneHandler::Clone(igtl::MessageBase* original_) { bool copySuccess = false; igtl::TransformMessage::Pointer clone_ = igtl::TransformMessage::New(); //initialize the clone // clone = igtl::MessageBase::New(); igtl::TransformMessage* original = (igtl::TransformMessage*)original_; //copy all meta data copySuccess = clone_->Copy(original); if (!copySuccess) return nullptr; //copy all data that is important for this class //copy the matrix igtl::Matrix4x4 mat; original->GetMatrix(mat); clone_->SetMatrix(mat); //copy the normals float normals[3][3]; original->GetNormals(normals); clone_->SetNormals(normals); //copy the position float position[3]; original->GetPosition(position); clone_->SetPosition(position); return igtl::MessageBase::Pointer(clone_.GetPointer()); } mitk::IGTLMessageFactory::IGTLMessageFactory() { //create clone handlers // mitk::IGTLMessageCloneHandler::Pointer tmch = ; this->AddMessageNewMethod("NONE", nullptr); //OpenIGTLink Types V1 this->AddMessageNewMethod("IMAGE", (PointerToMessageBaseNew)&igtl::ImageMessage::New); this->AddMessageNewMethod("TRANSFORM", (PointerToMessageBaseNew)&igtl::TransformMessage::New); this->AddMessageNewMethod("POSITION", (PointerToMessageBaseNew)&igtl::PositionMessage::New); this->AddMessageNewMethod("STATUS", (PointerToMessageBaseNew)&igtl::StatusMessage::New); this->AddMessageNewMethod("CAPABILITY", (PointerToMessageBaseNew)&igtl::CapabilityMessage::New); this->AddMessageNewMethod("GET_IMAGE", (PointerToMessageBaseNew)&igtl::GetImageMessage::New); this->AddMessageNewMethod("GET_TRANS", (PointerToMessageBaseNew)&igtl::GetTransformMessage::New); //this->AddMessageNewMethod("GET_POS", (PointerToMessageBaseNew)&igtl::GetPositionMessage::New); //not available??? this->AddMessageNewMethod("GET_STATUS", (PointerToMessageBaseNew)&igtl::GetStatusMessage::New); - this->AddMessageNewMethod("GET_CAPABIL", (PointerToMessageBaseNew)&igtl::GetCapabilityMessage::New); + //this->AddMessageNewMethod("GET_CAPABIL", (PointerToMessageBaseNew)&igtl::GetCapabilityMessage::New); // //OpenIGTLink Types V2 this->AddMessageNewMethod("IMGMETA", (PointerToMessageBaseNew)&igtl::ImageMetaMessage::New); this->AddMessageNewMethod("LBMETA", (PointerToMessageBaseNew)&igtl::LabelMetaMessage::New); this->AddMessageNewMethod("COLORT", (PointerToMessageBaseNew)&igtl::ColorTableMessage::New); this->AddMessageNewMethod("POINT", (PointerToMessageBaseNew)&igtl::PointMessage::New); this->AddMessageNewMethod("TRAJ", (PointerToMessageBaseNew)&igtl::TrajectoryMessage::New); this->AddMessageNewMethod("TDATA", (PointerToMessageBaseNew)&igtl::TrackingDataMessage::New); this->AddMessageNewMethod("QTDATA", (PointerToMessageBaseNew)&igtl::QuaternionTrackingDataMessage::New); this->AddMessageNewMethod("SENSOR", (PointerToMessageBaseNew)&igtl::SensorMessage::New); this->AddMessageNewMethod("STRING", (PointerToMessageBaseNew)&igtl::StringMessage::New); this->AddMessageNewMethod("NDARRAY", (PointerToMessageBaseNew)&igtl::NDArrayMessage::New); this->AddMessageNewMethod("BIND", (PointerToMessageBaseNew)&igtl::BindMessage::New); this->AddMessageNewMethod("POLYDATA", (PointerToMessageBaseNew)&igtl::PolyDataMessage::New); this->AddMessageNewMethod("GET_IMGMETA", (PointerToMessageBaseNew)&igtl::GetImageMetaMessage::New); this->AddMessageNewMethod("GET_LBMETA", (PointerToMessageBaseNew)&igtl::GetLabelMetaMessage::New); this->AddMessageNewMethod("GET_COLORT", (PointerToMessageBaseNew)&igtl::GetColorTableMessage::New); this->AddMessageNewMethod("GET_POINT", (PointerToMessageBaseNew)&igtl::GetPointMessage::New); this->AddMessageNewMethod("GET_TRAJ", (PointerToMessageBaseNew)&igtl::GetTrajectoryMessage::New); // this->AddMessageNewMethod("GET_TDATA", (PointerToMessageBaseNew)&igtl::GetTrackingDataMessage::New); //not available??? // this->AddMessageNewMethod("GET_QTDATA", (PointerToMessageBaseNew)&igtl::GetQuaternionTrackingDataMessage::New); //not available??? // this->AddMessageNewMethod("GET_SENSOR", (PointerToMessageBaseNew)&igtl::GetSensorMessage::New); //not available??? // this->AddMessageNewMethod("GET_STRING", (PointerToMessageBaseNew)&igtl::GetStringMessage::New); //not available??? // this->AddMessageNewMethod("GET_NDARRAY", (PointerToMessageBaseNew)&igtl::GetNDArrayMessage::New); //not available??? this->AddMessageNewMethod("GET_BIND", (PointerToMessageBaseNew)&igtl::GetBindMessage::New); this->AddMessageNewMethod("GET_POLYDATA", (PointerToMessageBaseNew)&igtl::GetPolyDataMessage::New); this->AddMessageNewMethod("RTS_BIND", (PointerToMessageBaseNew)&igtl::RTSBindMessage::New); this->AddMessageNewMethod("RTS_QTDATA", (PointerToMessageBaseNew)&igtl::RTSQuaternionTrackingDataMessage::New); this->AddMessageNewMethod("RTS_TDATA", (PointerToMessageBaseNew)&igtl::RTSTrackingDataMessage::New); //todo: check if there are more RTS messages this->AddMessageNewMethod("STT_BIND", (PointerToMessageBaseNew)&igtl::StartBindMessage::New); this->AddMessageNewMethod("STT_TDATA", (PointerToMessageBaseNew)&igtl::StartTrackingDataMessage::New); this->AddMessageNewMethod("STT_QTDATA", (PointerToMessageBaseNew)&igtl::StartQuaternionTrackingDataMessage::New); //todo: check if there are more STT messages this->AddMessageNewMethod("STP_BIND", (PointerToMessageBaseNew)&igtl::StopBindMessage::New); this->AddMessageNewMethod("STP_TDATA", (PointerToMessageBaseNew)&igtl::StopTrackingDataMessage::New); this->AddMessageNewMethod("STP_QTDATA", (PointerToMessageBaseNew)&igtl::StopQuaternionTrackingDataMessage::New); //todo: check if there are more STP messages //Own Types this->AddMessageNewMethod("DUMMY", (PointerToMessageBaseNew)&mitk::IGTLDummyMessage::New); } mitk::IGTLMessageFactory::~IGTLMessageFactory() { } void mitk::IGTLMessageFactory::AddMessageType(std::string messageTypeName, IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer, mitk::IGTLMessageCloneHandler::Pointer cloneHandler) { this->AddMessageNewMethod(messageTypeName, messageTypeNewPointer); this->AddMessageCloneHandler(messageTypeName, cloneHandler); } void mitk::IGTLMessageFactory::AddMessageNewMethod(std::string messageTypeName, IGTLMessageFactory::PointerToMessageBaseNew messageTypeNewPointer) { this->m_NewMethods[messageTypeName] = messageTypeNewPointer; } void mitk::IGTLMessageFactory::AddMessageCloneHandler(std::string msgTypeName, mitk::IGTLMessageCloneHandler::Pointer cloneHandler) { this->m_CloneHandlers[msgTypeName] = cloneHandler; } mitk::IGTLMessageCloneHandler::Pointer mitk::IGTLMessageFactory::GetCloneHandler(std::string messageTypeName) { if (this->m_CloneHandlers.find(messageTypeName) != this->m_CloneHandlers.end()) { return m_CloneHandlers[messageTypeName]; } MITK_ERROR("IGTLMessageFactory") << messageTypeName << " message type is not registered to factory!"; mitkThrow() << messageTypeName << " message type is not registered to factory!"; return nullptr; } igtl::MessageBase::Pointer mitk::IGTLMessageFactory::Clone(igtl::MessageBase::Pointer msg) { return this->GetCloneHandler(msg->GetDeviceType())->Clone(msg); } mitk::IGTLMessageFactory::PointerToMessageBaseNew mitk::IGTLMessageFactory::GetMessageTypeNewPointer(std::string messageTypeName) { if (this->m_NewMethods.find(messageTypeName) != this->m_NewMethods.end()) { return m_NewMethods[messageTypeName]; } MITK_ERROR("IGTLMessageFactory") << messageTypeName << " message type is not registered to factory!"; return nullptr; } igtl::MessageBase::Pointer mitk::IGTLMessageFactory::CreateInstance(std::string messageTypeName) { mitk::IGTLMessageFactory::PointerToMessageBaseNew newPointer = this->GetMessageTypeNewPointer(messageTypeName); if (newPointer != nullptr) { return newPointer(); } else { return nullptr; } } std::list mitk::IGTLMessageFactory::GetAvailableMessageRequestTypes() { std::list allGetMessages; for (std::map::const_iterator it = this->m_NewMethods.begin(); it != this->m_NewMethods.end(); ++it) { if (it->first.find("GET_") != std::string::npos || it->first.find("STT_") != std::string::npos || it->first.find("STP_") != std::string::npos || it->first.find("RTS_") != std::string::npos) { allGetMessages.push_back(it->first); } } return allGetMessages; } igtl::MessageBase::Pointer mitk::IGTLMessageFactory::CreateInstance(igtl::MessageHeader::Pointer msgHeader) { std::string messageType; //check the header if (msgHeader.IsNull()) { messageType = "NONE"; } else { messageType = msgHeader->GetDeviceType(); } //make message type uppercase messageType = itksys::SystemTools::UpperCase(messageType); //find the according new method if (this->m_NewMethods.find(messageType) != this->m_NewMethods.end()) { if (this->m_NewMethods[messageType] != nullptr) { // Call tracker New() function if tracker not nullptr return (*this->m_NewMethods[messageType])(); } else return nullptr; } else { MITK_ERROR("IGTLMessageFactory") << "Unknown IGT message type: " << messageType; return nullptr; } } diff --git a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h index 504fdc1090..404c814412 100644 --- a/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h +++ b/Modules/PhotoacousticsAlgorithms/include/mitkPhotoacousticImage.h @@ -1,125 +1,129 @@ /*=================================================================== 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 mitkPhotoacousticImage_H_HEADER_INCLUDED #define mitkPhotoacousticImage_H_HEADER_INCLUDED #include "itkObject.h" #include "mitkCommon.h" #include "mitkImage.h" #include #include "mitkPhotoacousticBeamformingSettings.h" #include "mitkPhotoacousticBeamformingFilter.h" #include "MitkPhotoacousticsAlgorithmsExports.h" namespace mitk { /*! * \brief Class holding methods to apply all Filters within the Photoacoustics Algorithms Module * * Implemented are: * - A B-Mode Filter * - A Resampling Filter * - Beamforming on GPU and CPU * - A Bandpass Filter */ class MITKPHOTOACOUSTICSALGORITHMS_EXPORT PhotoacousticImage : public itk::Object { public: mitkClassMacroItkParent(mitk::PhotoacousticImage, itk::Object); itkFactorylessNewMacro(Self); /** \brief Defines the methods for the B-Mode filter * Currently implemented are an Envelope Detection filter and a simple Absolute filter. */ enum BModeMethod { EnvelopeDetection, Abs }; /** \brief Applies a B-Mode Filter * * Applies a B-Mode filter using the given parameters. * @param inputImage The image to be processed. * @param method The kind of B-Mode Filter to be used. * @param UseGPU Setting this to true will allow the Filter to use the GPU. * @param UseLogFilter Setting this to true will apply a simple logarithm to the image after the B-Mode Filter has been applied. * @param resampleSpacing If this is set to 0, nothing will be done; otherwise, the image is resampled to a spacing of resampleSpacing mm per pixel. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method = BModeMethod::Abs, bool UseGPU = false, bool UseLogFilter = false, float resampleSpacing = 0.15); // mitk::Image::Pointer ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scatteringCoefficient); /** \brief Resamples the given image * * Resamples an image using the given parameters. * @param inputImage The image to be processed. * @param outputSize An array of dimensions the image should be resampled to. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]); /** \brief Beamforms the given image * * Resamples an image using the given parameters. * @param inputImage The image to be processed. * @param config The configuration set to be used for beamforming. * @param message A string into which potentially critical messages will be written. * @param progressHandle An std::function, through which progress of the currently updating filter is reported. * The integer argument is a number between 0 an 100 to indicate how far completion has been achieved, the std::string argument indicates what the filter is currently doing. * @return The processed image is returned after the filter has finished. */ mitk::Image::Pointer ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle = [](int, std::string) {}); /** \brief Crops the given image * * Crops an image in 3 dimension using the given parameters. * @param inputImage The image to be processed. * @param above How many voxels will be cut from the top of the image. * @param below How many voxels will be cut from the bottom of the image. * @param right How many voxels will be cut from the right side of the image. * @param left How many voxels will be cut from the left side of the image. * @param minSlice The first slice to be present in the resulting image. * @param maxSlice The last slice to be present in the resulting image. * @return The processed image is returned after the filter has finished. For the purposes of this module, the returned image is always of type float. */ mitk::Image::Pointer ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice); /** \brief Applies a Bandpass filter to the given image * * Applies a bandpass filter to the given image using the given parameters. * @param data The image to be processed. * @param recordTime The depth of the image in seconds. * @param BPHighPass The position at which Lower frequencies are completely cut off in Hz. * @param BPLowPass The position at which Higher frequencies are completely cut off in Hz. * @param alpha The tukey window parameter to control the shape of the bandpass filter: 0 will make it a Box function, 1 a Hann function. alpha can be set between those two bounds. * @return The processed image is returned after the filter has finished. */ - mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha); + mitk::Image::Pointer BandpassFilter(mitk::Image::Pointer data, float recordTime, + float BPHighPass, float BPLowPass, + float alphaHighPass, float alphaLowPass); protected: PhotoacousticImage(); ~PhotoacousticImage() override; /** \brief For performance reasons, an instance of the Beamforming filter is initialized as soon as possible and kept for all further uses. */ mitk::BeamformingFilter::Pointer m_BeamformingFilter; /** \brief Function that creates a Tukey function for the bandpass */ - itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha); + itk::Image::Pointer BPFunction(mitk::Image::Pointer reference, + int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, + float alphaHighPass, float alphaLowPass); }; } // namespace mitk #endif /* mitkPhotoacousticImage_H_HEADER_INCLUDED */ diff --git a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp index d4961e2260..4a268f824d 100644 --- a/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp +++ b/Modules/PhotoacousticsAlgorithms/source/mitkPhotoacousticImage.cpp @@ -1,539 +1,517 @@ /*=================================================================== 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 "mitkPhotoacousticImage.h" #include "../ITKFilter/ITKUltrasound/itkBModeImageFilter.h" #include "../ITKFilter/itkPhotoacousticBModeImageFilter.h" #include "mitkImageCast.h" #include "mitkITKImageImport.h" #include "mitkPhotoacousticBeamformingFilter.h" #include #include #include "./OpenCLFilter/mitkPhotoacousticBModeFilter.h" // itk dependencies #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCropImageFilter.h" #include "itkRescaleIntensityImageFilter.h" #include "itkIntensityWindowingImageFilter.h" #include #include "itkMultiplyImageFilter.h" #include "itkBSplineInterpolateImageFunction.h" #include // needed itk image filters #include "mitkITKImageImport.h" #include "itkFFTShiftImageFilter.h" #include "itkMultiplyImageFilter.h" #include "itkComplexToModulusImageFilter.h" #include #include "../ITKFilter/ITKUltrasound/itkFFT1DComplexConjugateToRealImageFilter.h" #include "../ITKFilter/ITKUltrasound/itkFFT1DRealToComplexConjugateImageFilter.h" mitk::PhotoacousticImage::PhotoacousticImage() : m_BeamformingFilter(BeamformingFilter::New()) { MITK_INFO << "[PhotoacousticImage Debug] created that image"; } mitk::PhotoacousticImage::~PhotoacousticImage() { MITK_INFO << "[PhotoacousticImage Debug] destroyed that image"; } mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBmodeFilter(mitk::Image::Pointer inputImage, BModeMethod method, bool UseGPU, bool UseLogFilter, float resampleSpacing) { // the image needs to be of floating point type for the envelope filter to work; the casting is done automatically by the CastToItkImage typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::IdentityTransform TransformType; if (method == BModeMethod::Abs) { mitk::Image::Pointer input; mitk::Image::Pointer out; if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") input = inputImage; else input = ApplyCropping(inputImage, 0, 0, 0, 0, 0, inputImage->GetDimension(2) - 1); if (!UseGPU) { PhotoacousticBModeFilter::Pointer filter = PhotoacousticBModeFilter::New(); filter->SetParameters(UseLogFilter); filter->SetInput(input); filter->Update(); out = filter->GetOutput(); if (resampleSpacing == 0) return out; } #ifdef PHOTOACOUSTICS_USE_GPU else { PhotoacousticOCLBModeFilter::Pointer filter = PhotoacousticOCLBModeFilter::New(); filter->SetParameters(UseLogFilter); filter->SetInput(input); filter->Update(); out = filter->GetOutput(); if (resampleSpacing == 0) return out; } #endif typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(out, itkImage); itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; typedef itk::IdentityTransform TransformType; resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } else if (method == BModeMethod::EnvelopeDetection) { typedef itk::BModeImageFilter < itkFloatImageType, itkFloatImageType > BModeFilterType; BModeFilterType::Pointer bModeFilter = BModeFilterType::New(); // LogFilter typedef itk::PhotoacousticBModeImageFilter < itkFloatImageType, itkFloatImageType > PhotoacousticBModeImageFilter; PhotoacousticBModeImageFilter::Pointer photoacousticBModeFilter = PhotoacousticBModeImageFilter::New(); // No LogFilter typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::Pointer bmode; if (UseLogFilter) { bModeFilter->SetInput(itkImage); bModeFilter->SetDirection(1); bmode = bModeFilter->GetOutput(); } else { photoacousticBModeFilter->SetInput(itkImage); photoacousticBModeFilter->SetDirection(1); bmode = photoacousticBModeFilter->GetOutput(); } // resampleSpacing == 0 means: do no resampling if (resampleSpacing == 0) { return mitk::GrabItkImageMemory(bmode); } itkFloatImageType::SpacingType outputSpacing; itkFloatImageType::SizeType inputSize = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSize = inputSize; outputSpacing[0] = itkImage->GetSpacing()[0]; outputSpacing[1] = resampleSpacing; outputSpacing[2] = itkImage->GetSpacing()[2]; outputSize[1] = inputSize[1] * itkImage->GetSpacing()[1] / outputSpacing[1]; resampleImageFilter->SetInput(bmode); resampleImageFilter->SetSize(outputSize); resampleImageFilter->SetOutputSpacing(outputSpacing); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } return nullptr; } /*mitk::Image::Pointer mitk::PhotoacousticImage::ApplyScatteringCompensation(mitk::Image::Pointer inputImage, int scattering) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::MultiplyImageFilter MultiplyImageFilterType; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); MultiplyImageFilterType::Pointer multiplyFilter = MultiplyImageFilterType::New(); multiplyFilter->SetInput1(itkImage); multiplyFilter->SetInput2(m_FluenceCompResizedItk.at(m_ScatteringCoefficient)); return mitk::GrabItkImageMemory(multiplyFilter->GetOutput()); }*/ mitk::Image::Pointer mitk::PhotoacousticImage::ApplyResampling(mitk::Image::Pointer inputImage, unsigned int outputSize[2]) { typedef itk::Image< float, 3 > itkFloatImageType; typedef itk::ResampleImageFilter < itkFloatImageType, itkFloatImageType > ResampleImageFilter; ResampleImageFilter::Pointer resampleImageFilter = ResampleImageFilter::New(); typedef itk::LinearInterpolateImageFunction T_Interpolator; itkFloatImageType::Pointer itkImage; mitk::CastToItkImage(inputImage, itkImage); itkFloatImageType::SpacingType outputSpacingItk; itkFloatImageType::SizeType inputSizeItk = itkImage->GetLargestPossibleRegion().GetSize(); itkFloatImageType::SizeType outputSizeItk = inputSizeItk; outputSizeItk[0] = outputSize[0]; outputSizeItk[1] = outputSize[1]; outputSizeItk[2] = inputSizeItk[2]; outputSpacingItk[0] = itkImage->GetSpacing()[0] * (static_cast(inputSizeItk[0]) / static_cast(outputSizeItk[0])); outputSpacingItk[1] = itkImage->GetSpacing()[1] * (static_cast(inputSizeItk[1]) / static_cast(outputSizeItk[1])); outputSpacingItk[2] = itkImage->GetSpacing()[2]; typedef itk::IdentityTransform TransformType; T_Interpolator::Pointer _pInterpolator = T_Interpolator::New(); resampleImageFilter->SetInput(itkImage); resampleImageFilter->SetSize(outputSizeItk); resampleImageFilter->SetOutputSpacing(outputSpacingItk); resampleImageFilter->SetTransform(TransformType::New()); resampleImageFilter->SetInterpolator(_pInterpolator); resampleImageFilter->UpdateLargestPossibleRegion(); return mitk::GrabItkImageMemory(resampleImageFilter->GetOutput()); } mitk::Image::Pointer mitk::PhotoacousticImage::ApplyCropping(mitk::Image::Pointer inputImage, int above, int below, int right, int left, int minSlice, int maxSlice) { unsigned int inputDim[3] = { inputImage->GetDimension(0), inputImage->GetDimension(1), inputImage->GetDimension(2) }; unsigned int outputDim[3] = { inputImage->GetDimension(0) - left - right, inputImage->GetDimension(1) - (unsigned int)above - (unsigned int)below, (unsigned int)maxSlice - (unsigned int)minSlice + 1 }; void* inputData; float* outputData = new float[outputDim[0] * outputDim[1] * outputDim[2]]; ImageReadAccessor acc(inputImage); inputData = const_cast(acc.GetData()); // convert the data to float by default // as of now only float, short, double are used at all. if (inputImage->GetPixelType().GetTypeAsString() == "scalar (float)" || inputImage->GetPixelType().GetTypeAsString() == " (float)") { // copy the data into the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((float*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (short)" || inputImage->GetPixelType().GetTypeAsString() == " (short)") { // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((short*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else if (inputImage->GetPixelType().GetTypeAsString() == "scalar (double)" || inputImage->GetPixelType().GetTypeAsString() == " (double)") { // copy the data to the cropped image for (unsigned short sl = 0; sl < outputDim[2]; ++sl) { for (unsigned short l = 0; l < outputDim[0]; ++l) { for (unsigned short s = 0; s < outputDim[1]; ++s) { outputData[l + s*(unsigned short)outputDim[0] + sl*outputDim[0] * outputDim[1]] = (float)((double*)inputData)[(l + left) + (s + above)*(unsigned short)inputDim[0] + (sl + minSlice)*inputDim[0] * inputDim[1]]; } } } } else { MITK_INFO << "Could not determine pixel type"; } mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(mitk::MakeScalarPixelType(), 3, outputDim); output->SetSpacing(inputImage->GetGeometry()->GetSpacing()); - output->SetImportVolume(outputData, 0, 0, mitk::Image::ReferenceMemory); - + output->SetImportVolume(outputData, 0, 0, mitk::Image::CopyMemory); + delete[] outputData; return output; } mitk::Image::Pointer mitk::PhotoacousticImage::ApplyBeamforming(mitk::Image::Pointer inputImage, BeamformingSettings config, std::string& message, std::function progressHandle) { Image::Pointer processedImage = inputImage; if (inputImage->GetDimension() != 3) { processedImage->Initialize(mitk::MakeScalarPixelType(), 3, inputImage->GetDimensions()); processedImage->SetSpacing(inputImage->GetGeometry()->GetSpacing()); mitk::ImageReadAccessor copy(inputImage); processedImage->SetImportVolume(copy.GetData()); } config.RecordTime = config.RecordTime - (float)(config.upperCutoff) / (float)inputImage->GetDimension(1) * config.RecordTime; // adjust the recorded time lost by cropping progressHandle(0, "converting image"); if (!config.partial) { config.CropBounds[0] = 0; config.CropBounds[1] = inputImage->GetDimension(2) - 1; } processedImage = ApplyCropping(inputImage, config.upperCutoff, 0, 0, 0, config.CropBounds[0], config.CropBounds[1]); config.inputDim[0] = processedImage->GetDimension(0); config.inputDim[1] = processedImage->GetDimension(1); config.inputDim[2] = processedImage->GetDimension(2); // perform the beamforming m_BeamformingFilter->SetInput(processedImage); m_BeamformingFilter->Configure(config); m_BeamformingFilter->SetProgressHandle(progressHandle); m_BeamformingFilter->UpdateLargestPossibleRegion(); processedImage = m_BeamformingFilter->GetOutput(); message = m_BeamformingFilter->GetMessageString(); return processedImage; } -mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, float BPHighPass, float BPLowPass, float alpha) +mitk::Image::Pointer mitk::PhotoacousticImage::BandpassFilter(mitk::Image::Pointer data, float recordTime, + float BPHighPass, float BPLowPass, + float alphaHighPass, float alphaLowPass) { bool powerOfTwo = false; int finalPower = 0; for (int i = 1; pow(2, i) <= data->GetDimension(1); ++i) { finalPower = i; if (pow(2, i) == data->GetDimension(1)) { powerOfTwo = true; } } if (!powerOfTwo) { unsigned int dim[2] = { data->GetDimension(0), (unsigned int)pow(2,finalPower+1)}; data = ApplyResampling(data, dim); } MITK_INFO << data->GetDimension(0); // do a fourier transform, multiply with an appropriate window for the filter, and transform back typedef float PixelType; typedef itk::Image< PixelType, 3 > RealImageType; RealImageType::Pointer image; mitk::CastToItkImage(data, image); typedef itk::FFT1DRealToComplexConjugateImageFilter ForwardFFTFilterType; typedef ForwardFFTFilterType::OutputImageType ComplexImageType; ForwardFFTFilterType::Pointer forwardFFTFilter = ForwardFFTFilterType::New(); forwardFFTFilter->SetInput(image); forwardFFTFilter->SetDirection(1); try { forwardFFTFilter->UpdateOutputInformation(); } catch (itk::ExceptionObject & error) { std::cerr << "Error: " << error << std::endl; MITK_WARN << "Bandpass could not be applied"; return data; } float singleVoxel = 1 / (recordTime / data->GetDimension(1)) / 2 / 1000; float cutoffPixelHighPass = std::min(BPHighPass / singleVoxel, (float)data->GetDimension(1) / 2); float cutoffPixelLowPass = std::min(BPLowPass / singleVoxel, (float)data->GetDimension(1) / 2 - cutoffPixelHighPass); - RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alpha); + RealImageType::Pointer fftMultiplicator = BPFunction(data, cutoffPixelHighPass, cutoffPixelLowPass, alphaHighPass, alphaLowPass); typedef itk::MultiplyImageFilter< ComplexImageType, RealImageType, ComplexImageType > MultiplyFilterType; MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); multiplyFilter->SetInput1(forwardFFTFilter->GetOutput()); multiplyFilter->SetInput2(fftMultiplicator); /*itk::ComplexToModulusImageFilter::Pointer toReal = itk::ComplexToModulusImageFilter::New(); toReal->SetInput(forwardFFTFilter->GetOutput()); return GrabItkImageMemory(toReal->GetOutput()); return GrabItkImageMemory(fftMultiplicator); *///DEBUG typedef itk::FFT1DComplexConjugateToRealImageFilter< ComplexImageType, RealImageType > InverseFilterType; InverseFilterType::Pointer inverseFFTFilter = InverseFilterType::New(); inverseFFTFilter->SetInput(multiplyFilter->GetOutput()); inverseFFTFilter->SetDirection(1); return GrabItkImageMemory(inverseFFTFilter->GetOutput()); } -itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, int cutoffFrequencyPixelHighPass, int cutoffFrequencyPixelLowPass, float alpha) +itk::Image::Pointer mitk::PhotoacousticImage::BPFunction(mitk::Image::Pointer reference, + int cutoffFrequencyPixelHighPass, + int cutoffFrequencyPixelLowPass, + float alphaHighPass, float alphaLowPass) { float* imageData = new float[reference->GetDimension(0)*reference->GetDimension(1)]; - - // tukey window - float width = reference->GetDimension(1) / 2 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; - float center = (float)cutoffFrequencyPixelHighPass / 2 + width / 2; - - MITK_INFO << width << "width " << center << "center " << alpha; + float width = reference->GetDimension(1) / 2.0 - (float)cutoffFrequencyPixelHighPass - (float)cutoffFrequencyPixelLowPass; + float center = (float)cutoffFrequencyPixelHighPass / 2.0 + width / 2.0; for (unsigned int n = 0; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = 0; } - if (alpha < 0.00001) + for (int n = 0; n < width; ++n) { - for (int n = 0; n < width; ++n) + imageData[reference->GetDimension(0)*n] = 1; + if (n <= (alphaHighPass*(width - 1)) / 2.0) { - if (n <= (alpha*(width - 1)) / 2) + if (alphaHighPass > 0.00001) { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alpha*(width - 1)) - 1))) / 2; - } - else if (n >= (width - 1)*(1 - alpha / 2)) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = (1 + cos(itk::Math::pi*(2 * n / (alpha*(width - 1)) + 1 - 2 / alpha))) / 2; + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = + (1 + cos(itk::Math::pi*(2 * n / (alphaHighPass*(width - 1)) - 1))) / 2; } else { imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; } } - } - else - { - for (int n = 0; n < width; ++n) - { - imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; - } - } - // Butterworth-Filter - /* - // first, write the HighPass - if (cutoffFrequencyPixelHighPass != reference->GetDimension(1) / 2) - { - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) - { - imageData[reference->GetDimension(0)*n] = 1 / (1 + pow( - (float)n / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelHighPass) - , 2 * butterworthOrder)); - } - } - else - { - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) + else if (n >= (width - 1)*(1 - alphaLowPass / 2)) //??? { - imageData[reference->GetDimension(0)*n] = 1; + if (alphaLowPass > 0.00001) + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = + (1 + cos(itk::Math::pi*(2 * n / (alphaLowPass*(width - 1)) + 1 - 2 / alphaLowPass))) / 2; + } + else + { + imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))] = 1; + } } + //MITK_INFO << "n:" << n << " is " << imageData[reference->GetDimension(0)*(int)(n + center - (width / 2))]; } - - // now, the LowPass - for (int n = 0; n < reference->GetDimension(1) / 2; ++n) - { - imageData[reference->GetDimension(0)*n] *= 1 / (1 + pow( - (float)(reference->GetDimension(1) / 2 - 1 - n) / (float)(reference->GetDimension(1) / 2 - cutoffFrequencyPixelLowPass) - , 2 * butterworthOrder)); - } - */ + MITK_INFO << "width: " << width << ", center: " << center << ", alphaHighPass: " << alphaHighPass << ", alphaLowPass: " << alphaLowPass; // mirror the first half of the image for (unsigned int n = reference->GetDimension(1) / 2; n < reference->GetDimension(1); ++n) { imageData[reference->GetDimension(0)*n] = imageData[(reference->GetDimension(1) - (n + 1)) * reference->GetDimension(0)]; } // copy and paste to all lines for (unsigned int line = 1; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { imageData[reference->GetDimension(0)*sample + line] = imageData[reference->GetDimension(0)*sample]; } } typedef itk::Image< float, 3U > ImageType; ImageType::RegionType region; ImageType::IndexType start; start.Fill(0); region.SetIndex(start); ImageType::SizeType size; size[0] = reference->GetDimension(0); size[1] = reference->GetDimension(1); size[2] = reference->GetDimension(2); region.SetSize(size); ImageType::SpacingType SpacingItk; SpacingItk[0] = reference->GetGeometry()->GetSpacing()[0]; SpacingItk[1] = reference->GetGeometry()->GetSpacing()[1]; SpacingItk[2] = reference->GetGeometry()->GetSpacing()[2]; ImageType::Pointer image = ImageType::New(); image->SetRegions(region); image->Allocate(); image->FillBuffer(itk::NumericTraits::Zero); image->SetSpacing(SpacingItk); ImageType::IndexType pixelIndex; for (unsigned int slice = 0; slice < reference->GetDimension(2); ++slice) { for (unsigned int line = 0; line < reference->GetDimension(0); ++line) { for (unsigned int sample = 0; sample < reference->GetDimension(1); ++sample) { pixelIndex[0] = line; pixelIndex[1] = sample; pixelIndex[2] = slice; image->SetPixel(pixelIndex, imageData[line + sample*reference->GetDimension(0)]); } } } delete[] imageData; return image; } diff --git a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp index e630aef6cf..fd3b295c64 100644 --- a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp +++ b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.cpp @@ -1,384 +1,418 @@ /*=================================================================== 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 "mitkMorphologicalOperations.h" #include #include #include #include #include #include #include #include #include #include #include void mitk::MorphologicalOperations::Closing(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Closing..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkClosing, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkClosing, image, factor, structuralElement); } MITK_INFO << "Finished Closing"; } void mitk::MorphologicalOperations::Erode(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Erode..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkErode, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkErode, image, factor, structuralElement); } MITK_INFO << "Finished Erode"; } void mitk::MorphologicalOperations::Dilate(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Dilate..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkDilate, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkDilate, image, factor, structuralElement); } MITK_INFO << "Finished Dilate"; } void mitk::MorphologicalOperations::Opening(mitk::Image::Pointer &image, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElement) { MITK_INFO << "Start Opening..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_3(img3D, itkOpening, img3D, factor, structuralElement); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_3(image, itkOpening, image, factor, structuralElement); } MITK_INFO << "Finished Opening"; } void mitk::MorphologicalOperations::FillHoles(mitk::Image::Pointer &image) { MITK_INFO << "Start FillHole..."; auto timeSteps = static_cast(image->GetTimeSteps()); if (timeSteps > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); for (int t = 0; t < timeSteps; ++t) { MITK_INFO << " Processing time step " << t; timeSelector->SetTimeNr(t); timeSelector->Update(); mitk::Image::Pointer img3D = timeSelector->GetOutput(); img3D->DisconnectPipeline(); AccessByItk_1(img3D, itkFillHoles, img3D); mitk::ImageReadAccessor accessor(img3D); image->SetVolume(accessor.GetData(), t); } } else { AccessByItk_1(image, itkFillHoles, image); } MITK_INFO << "Finished FillHole"; } template void mitk::MorphologicalOperations::itkClosing( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryMorphologicalClosingImageFilter BallClosingFilterType; typedef typename itk::BinaryMorphologicalClosingImageFilter CrossClosingFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallClosingFilterType::Pointer closingFilter = BallClosingFilterType::New(); closingFilter->SetKernel(ball); closingFilter->SetInput(sourceImage); closingFilter->SetForegroundValue(1); closingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(closingFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossClosingFilterType::Pointer closingFilter = CrossClosingFilterType::New(); closingFilter->SetKernel(cross); closingFilter->SetInput(sourceImage); closingFilter->SetForegroundValue(1); closingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(closingFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkErode( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryErodeImageFilter BallErodeFilterType; typedef typename itk::BinaryErodeImageFilter CrossErodeFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallErodeFilterType::Pointer erodeFilter = BallErodeFilterType::New(); erodeFilter->SetKernel(ball); erodeFilter->SetInput(sourceImage); erodeFilter->SetErodeValue(1); erodeFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossErodeFilterType::Pointer erodeFilter = CrossErodeFilterType::New(); erodeFilter->SetKernel(cross); erodeFilter->SetInput(sourceImage); erodeFilter->SetErodeValue(1); erodeFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(erodeFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkDilate( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryDilateImageFilter BallDilateFilterType; typedef typename itk::BinaryDilateImageFilter CrossDilateFilterType; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallDilateFilterType::Pointer dilateFilter = BallDilateFilterType::New(); dilateFilter->SetKernel(ball); dilateFilter->SetInput(sourceImage); dilateFilter->SetDilateValue(1); dilateFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(dilateFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossDilateFilterType::Pointer dilateFilter = CrossDilateFilterType::New(); dilateFilter->SetKernel(cross); dilateFilter->SetInput(sourceImage); dilateFilter->SetDilateValue(1); dilateFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(dilateFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkOpening( itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, mitk::MorphologicalOperations::StructuralElementType structuralElementFlags) { typedef itk::Image ImageType; typedef itk::BinaryBallStructuringElement BallType; typedef itk::BinaryCrossStructuringElement CrossType; typedef typename itk::BinaryMorphologicalOpeningImageFilter BallOpeningFiltertype; typedef typename itk::BinaryMorphologicalOpeningImageFilter CrossOpeningFiltertype; if (structuralElementFlags & (Ball_Axial | Ball_Coronal | Ball_Sagital)) { BallType ball = CreateStructuringElement(structuralElementFlags, factor); typename BallOpeningFiltertype::Pointer openingFilter = BallOpeningFiltertype::New(); openingFilter->SetKernel(ball); openingFilter->SetInput(sourceImage); openingFilter->SetForegroundValue(1); openingFilter->SetBackgroundValue(0); openingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(openingFilter->GetOutput(), resultImage); } else { CrossType cross = CreateStructuringElement(structuralElementFlags, factor); typename CrossOpeningFiltertype::Pointer openingFilter = CrossOpeningFiltertype::New(); openingFilter->SetKernel(cross); openingFilter->SetInput(sourceImage); openingFilter->SetForegroundValue(1); openingFilter->SetBackgroundValue(0); openingFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(openingFilter->GetOutput(), resultImage); } } template void mitk::MorphologicalOperations::itkFillHoles(itk::Image *sourceImage, mitk::Image::Pointer &resultImage) { typedef itk::Image ImageType; typedef typename itk::BinaryFillholeImageFilter FillHoleFilterType; typename FillHoleFilterType::Pointer fillHoleFilter = FillHoleFilterType::New(); fillHoleFilter->SetInput(sourceImage); fillHoleFilter->SetForegroundValue(1); fillHoleFilter->UpdateLargestPossibleRegion(); mitk::CastToMitkImage(fillHoleFilter->GetOutput(), resultImage); } + +template +TStructuringElement mitk::MorphologicalOperations::CreateStructuringElement(StructuralElementType structuralElementFlag, int factor) +{ + TStructuringElement strElem; + typename TStructuringElement::SizeType size; + size.Fill(0); + switch (structuralElementFlag) + { + case Ball_Axial: + case Cross_Axial: + size.SetElement(0, factor); + size.SetElement(1, factor); + break; + case Ball_Coronal: + case Cross_Coronal: + size.SetElement(0, factor); + size.SetElement(2, factor); + break; + case Ball_Sagital: + case Cross_Sagital: + size.SetElement(1, factor); + size.SetElement(2, factor); + break; + case Ball: + case Cross: + size.Fill(factor); + break; + } + + strElem.SetRadius(size); + strElem.CreateStructuringElement(); + return strElem; +} \ No newline at end of file diff --git a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h index f7ce9e997d..a615a73820 100644 --- a/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h +++ b/Modules/Segmentation/SegmentationUtilities/MorphologicalOperations/mitkMorphologicalOperations.h @@ -1,124 +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 mitkMorphologicalOperations_h #define mitkMorphologicalOperations_h #include #include namespace mitk { /** \brief Encapsulates several morphological operations that can be performed on segmentations. */ class MITKSEGMENTATION_EXPORT MorphologicalOperations { public: enum StructuralElementType { Ball = 7, Ball_Axial = 1, Ball_Sagital = 2, Ball_Coronal = 4, Cross = 56, Cross_Axial = 8, Cross_Sagital = 16, Cross_Coronal = 32 }; ///@{ /** \brief Perform morphological operation on 2D, 3D or 3D+t segmentation. */ static void Closing(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); static void Erode(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); static void Dilate(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); static void Opening(mitk::Image::Pointer &image, int factor, StructuralElementType structuralElement); static void FillHoles(mitk::Image::Pointer &image); ///@} private: MorphologicalOperations(); template - static TStructuringElement CreateStructuringElement(StructuralElementType structuralElementFlag, int factor) - { - TStructuringElement strElem; - typename TStructuringElement::SizeType size; - size.Fill(0); - switch (structuralElementFlag) - { - case Ball_Axial: - case Cross_Axial: - size.SetElement(0, factor); - size.SetElement(1, factor); - break; - case Ball_Coronal: - case Cross_Coronal: - size.SetElement(0, factor); - size.SetElement(2, factor); - break; - case Ball_Sagital: - case Cross_Sagital: - size.SetElement(1, factor); - size.SetElement(2, factor); - break; - case Ball: - case Cross: - size.Fill(factor); - break; - } - - strElem.SetRadius(size); - strElem.CreateStructuringElement(); - return strElem; - } + static TStructuringElement CreateStructuringElement(StructuralElementType structuralElementFlag, int factor); ///@{ /** \brief Perform morphological operation by using corresponding ITK filter. */ template - void static itkClosing(itk::Image *sourceImage, + static void itkClosing(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template - void static itkErode(itk::Image *sourceImage, + static void itkErode(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template - void static itkDilate(itk::Image *sourceImage, + static void itkDilate(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template - void static itkOpening(itk::Image *sourceImage, + static void itkOpening(itk::Image *sourceImage, mitk::Image::Pointer &resultImage, int factor, StructuralElementType structuralElement); template - void static itkFillHoles(itk::Image *sourceImage, mitk::Image::Pointer &resultImage); + static void itkFillHoles(itk::Image *sourceImage, mitk::Image::Pointer &resultImage); ///@} }; } #endif diff --git a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox index 06afcb812e..1487cb3947 100644 --- a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox +++ b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/blueberrylogview.dox @@ -1,16 +1,16 @@ /** \page org_blueberry_ui_qt_log The Logging Plugin -\imageMacro{Logging.png,"Icon of the Logging Plugin",2.00} +\imageMacro{logging.svg,"Icon of the Logging Plugin",2.00} This plug-in records all logging output of events and progress as specified in the source code with time of occurence, level of importance (Info, Warning, Error, Fatal, Debug), the message given and where it happens. The logging starts once the plug-is started. A screenshot of the provided Logging view is shown next. \imageMacro{LogView.png,"Screenshot of the Logging Module",16.00} There are different features available in the view. The filter text field allows for searching all log events containing a certain substring. Using the button "Copy to clipboard" on the bottom right you can copy the current content of the logging view to your clipboard. This enables you to insert the logging information to any text processing application. You can also show more information on every logging message by activating the two checkboxes. In the simple view, leaving both checkboxes unchecked, you'll see logging messages and logging levels. A brief description of the logging levels can be found in the \ref LoggingPage "logging concept documentation". The checkbox "Category" adds a column for the category. The checkbox "Show Advanced Field" shows method, filename and linenumber where the logging message was emitted as well as the running time of the application. The next figure shows all information which can be shown in the Logging Module. \imageMacro{LogViewExplain.png,"Details on the Vizualized Logging Information",16.00} */ diff --git a/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg new file mode 100644 index 0000000000..ccb549f8a6 --- /dev/null +++ b/Plugins/org.blueberry.ui.qt.log/documentation/UserManual/logging.svg @@ -0,0 +1,80 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 850134fb4e..00eee0b30e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,62 +1,63 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp QmitkSingleNodeSelectionWidget.cpp QmitkNodeSelectionDialog.cpp QmitkAbstractNodeSelectionWidget.cpp QmitkMultiNodeSelectionWidget.cpp QmitkNodeSelectionPreferenceHelper.cpp QmitkNodeSelectionButton.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp QmitkNodeSelectionConstants.cpp QmitkNodeSelectionPreferencePage.cpp ) set(UI_FILES src/QmitkSingleNodeSelectionWidget.ui src/QmitkMultiNodeSelectionWidget.ui src/QmitkNodeSelectionDialog.ui src/internal/QmitkNodeSelectionPreferencePage.ui ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h src/QmitkSelectionServiceConnector.h src/QmitkSliceNavigationListener.h + src/ImporterUtil.h src/QmitkSingleNodeSelectionWidget.h src/QmitkNodeSelectionDialog.h src/QmitkAbstractNodeSelectionWidget.h src/QmitkMultiNodeSelectionWidget.h src/QmitkNodeSelectionButton.h src/internal/QmitkCommonActivator.h src/internal/QmitkNodeSelectionPreferencePage.h ) set(CACHED_RESOURCE_FILES plugin.xml resources/times.svg ) set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.common/src/ImporterUtil.h b/Plugins/org.mitk.gui.qt.common/src/ImporterUtil.h new file mode 100644 index 0000000000..bb269e9556 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/ImporterUtil.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +class ImporterUtil { +public: + /** + * @brief Convert a given QString to a utf-8 encoded string (platform-independently) + */ + static std::string getUTF8String(const QString& string) { + return string.toLocal8Bit().toStdString(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox index 09ce1a4f48..08e636a260 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox +++ b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/QmitkDatamanager.dox @@ -1,109 +1,109 @@ /** \page org_mitk_views_datamanager The DataManager -\imageMacro{QmitkDatamanager_Icon.png,"Icon of the Data Manager",2.00} +\imageMacro{data-manager.svg,"Icon of the Data Manager",2.00} \tableofcontents \section QmitkDataManagerIntroduction Introduction The Datamanager is the central componenent to manage medical data like images, surfaces, etc.. After loading one or more data into the Datamanager the data are shown in the four-view window, the so called Standard View. The user can now start working on the data by just clicking into the standard view or by using the MITK-modules such as "Segmentation" or "Basic Image Processing". \imageMacro{QmitkDatamanager_Overview.png,"How MITK looks when started",16.00} \section QmitkDataManagerLoading Loading Data There are three ways of loading data into the Datamanager as so called Data-Elements. The user can just drag and drop data into the Datamanager or directly into one of the four parts of the Standard View. He can as well use the Open-Button in the right upper corner. Or he can use the standard "File->Open"-Dialog on the top. A lot of file-formats can be loaded into MITK, for example
  • 2D-images/3D-volumes with or without several timesteps (*.dcm, *.ima, *.pic, ...)
  • Surfaces (*.stl, *.vtk, ...)
  • Pointsets (*.mps)
  • ...
The user can also load a series of 2D images (e.g. image001.png, image002.png ...) to a MITK 3D volume. To do this, just drag and drop one of those 2D data files into the Datamanager by holding the ALT key. After loading one or more data into the Datamanager they appear as Data-Elements in a sorted list inside the Datamanager. Data-Elements can also be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). The order can be changed by drag and drop. \imageMacro{QmitkDatamanager_ParentChild.png,"Screenshot1",9.61} The listed Data-Elements are shown in the standard view. Here the user can scale or rotate the medical objects or he can change the cutting planes of the object by just using the mouse inside this view. \section QmitkDataManagerSaving Saving Data There are two ways of saving data from the Datamanger. The user can either save the whole project with all Data-Elements by clicking on "File"->"Save Project" or he can save single Data-Elements by right-clicking->"Save", directly on a Data-Element. When saving the whole project, the sorting of Data-Elements is saved as well. By contrast the sorting is lost, when saving a single Data-Element. \section QmitkDataManagerProperties Working with the Datamanager \subsection QmitkDataManagerPropertiesList List of Data-Elements The Data-Elements are listed in the Datamanager. As described above the elements can be sorted hierarchically as a parent-child-relation. For example after using the Segmentation-Module on Data-Element1 the result is created as Data-Element2, which is a child of Data-Element1 (see Screenshot1). By drag and drop the sorting of Data-Elements and their hierarchical relation can be changed. \subsection QmitkDataManagerPropertiesVisibility Visibility of Data-Elements By default all loaded Data-Elements are visible in the standard view. The visibility can be changed by right-clicking on the Data-Element and then choosing "Toogle visibility". The box in front of the Data-Element in the Datamanager shows the visibility. A green-filled box means a visible Data-Element, an empty box means an invisible Data-Element (see Screenshot1). \subsection QmitkDataManagerPropertiesRepresentation Representation of Data-Elements There are different types of representations how to show the Data-Element inside the standard view. By right-clicking on the Data-Element all options are listed (see Screenshot2 and Screenshot 3).
  • An arbitrary color can be chosen
  • The opacity can be changed with a slide control
  • In case of images a texture interpolation can be switched on or off. The texture interpolation smoothes the image, so that no single pixels are visible anymore.
  • In case of surfaces the surface representation can be changed between points, wireframe or surface.
  • Global reinit updates all windows to contain all the current data: - The orientation of the worldgeometry, which basically defines the rendering space, is set to the standard coordinate system, i.e. [(0,0,1);(0,1,0);(0,0,1)] - The size of the worldgeometry is calculated, so that it includes all loaded data (depends on size and position of your data) - The spacing is set to the smallest existing spacing regarding your data Reinit updates a single data item and fits the windows to contain only this data item: - The orientation of the worldgeometry, is aligned according to the orientation of the currently selected datanode - The size of the worldgeometry is set to the size of the currently selected datanode - The spacing is set to the spacing of the currently selected datanode
\imageMacro{QmitkDatamanager_ImageProperties.png,"Screenshot2: Properties for images",10.56} \imageMacro{QmitkDatamanager_SurfaceProperties.png,"Screenshot3: Properties for surfaces",11.01} \subsection QmitkDataManagerPropertiesPreferences Preferences For the datamanager there are already some default hotkeys like the del-key for deleting a Data-Element. The whole list is seen in Screenshot4. From here the Hotkeys can also be changed. The preference page is found in "Window"->"Preferences". \imageMacro{QmitkDatamanager_Preferences.png,"Screenshot4",16.00} \section QmitkDataManagerPropertyList Property List The Property List displays all the properties the currently selected Data-Element has. Which properties these are depends on the Data-Element. Examples are opacity, shader, visibility. These properties can be changed by clicking on the appropriate field in the "value" column. \imageMacro{QmitkDatamanager_PropertyList.png,"Screenshot5: Property List",7.85} */ diff --git a/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg new file mode 100644 index 0000000000..7dd5c797d5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datamanager/documentation/UserManual/data-manager.svg @@ -0,0 +1,60 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox index fb81cee2d4..136c56e93d 100644 --- a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox +++ b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/QmitkDicom.dox @@ -1,118 +1,118 @@ /** \page org_mitk_gui_qt_dicom The Dicom Plugin -\imageMacro{QmitkDicom_Icon.png,"Icon of the DICOM Plugin",2.00} +\imageMacro{dicom.svg,"Icon of the DICOM Plugin",2.00} \note This article requires a basic knowledge of the DICOM Standard. \tableofcontents \section org_mitk_gui_qt_dicomOverview Overview The DICOM editor is an experimental editor which allows for loading of DICOM images as well as server communication. It features a highly experimental query/retrieve (you need to configure your PACS correspondingly) as well as a DICOM browser. The DICOM browser allows you to navigate the DICOM folder/cd depending on its metadata (patient/study/series) and import selected series for viewing in your MITK based application. It also allows you to store your dicom data in an internal database so you can easily access often used dicom images. It is based on the commonTK (CTK) DICOM funcionality. \section org_mitk_gui_qt_dicomDataHandling Data handling \imageMacro{QmitkDicom_PluginControls.png,"The dicom Plugin controls",7.37} In the image above you see the start page of the dicom plugin. On top of the start page you see four buttons. The Local Storage, the Import CD, the Import Folder and the Query Retrieve button. If you press one of these buttons, the dicom plugin will switch to your local dicom image storage or will start importing dicom images from CD or a folder on your hard drive or it will open the query retrieve screen.
  • Click the 'Local Storage' button to open the local storage screen.
  • Click the 'Import CD' button to import DICOM data from a CD.
  • Click the 'Import Folder' button to import DICOM date from a directory.
  • Click the 'Query Retrieve' button to open the query retrieve screen.
\subsection org_mitk_gui_qt_dicomStorage Data storage \imageMacro{QmitkDicom_PluginExtended.png,"The DICOM data storage",16.00} If you open the dicom plugin the dicom data storage will be displayed. You are able to see all your stored dicom image data. You can browse your data by clicking on the left arrow beside the name of your data. There are three levels available. The first level is the patient level where you can see the patient data. On the second level you can see the dicom studies for the patient. on the third level you can see all available series refering to it's study. You can delete the data by selecting it and pressing the delete button. Be careful if you have selected a patient or a study all refering data be deleted. So if you delete a patient the patient and all studies and series refered to the patient will be deleted. If you delete a study all series of the study will be deleted. If you want to view the dicom data you have to select a series and click on the View button. The data will appear in the DataManager and will be dispayed. \imageMacro{QmitkDicom_DisplayDataManager.png,"Viewed image",16.00}
  • Click on the arrow on the left of your data to expand or hide dicom data levels.
  • Click the 'Delete' button to delete selected DICOM data.
  • Click the 'View' button to view DICOM data.
\subsection org_mitk_gui_qt_dicomImport Data import \imageMacro{QmitkDicom_ImportDialog.png,"The import dialog checked",9.53} There are two diffrent ways to import DICOM data. The First one is to directly imort it into your DICOM data storage. To achieve this you should toggle the checkbox 'Copy on import'. The second approach is, to have a look at the data first before importing it. To do that you simply don't check 'Copy on import'. This will leed you to the leed you to the 'External Dicom Data' screen which provides you a preview of the data containing in youre choosen folder. You can import the data here by selecting it and pressing the 'Download' button. It is also possible to view DICOM series directly in Mitk by selecting it here and pressing the 'View' button.
  • Click 'Import Folder' or 'Import CD' button to open the import dialog.
    • Enable the 'Copy on import' checkbox and choose a folder to import into data storage directly.
    • Disable the 'Copy on import' checkbox to get to the 'External Dicom Data' screen.
      • Click on the arrow on the left of your data to expand or hide dicom data levels.
      • Click the 'Download' button to download selected DICOM data to your DICOM data storage.
      • Click the 'View' button to view DICOM data.
\section org_mitk_gui_qt_dicomQueryRetrieve Query/Retrieve \warning This plugin is experimental and not all of the described features behave as expected. \note The query retrieve plugin only works if the PACS you are calling knows your machine settings. There are also issues when you are running a firewall. The query retrieve workflow allows you to get DICOM data from a server. \imageMacro{QmitkDicom_QueryRetrieve.png,"The query retrieve screen",16.00} \subsection org_mitk_gui_qt_dicomQuery Query \imageMacro{QmitkDicom_Nodes.png,"The DICOM network configuration",11.26} By performing a DICOM query you will ask a server for it's DICOM data. This requires to setup the DICOM network configuration of your system and the server. By clicking on 'Add Server' a new plain server field will appear. Now you can give it a name of your choice. Fill the servers "DICOM name" the AETitle. Type in it's url, it's port and the specific DICOM protocoll you want to use for image transfer. \note I recommend not to use CGET because most of the PACS systems (Image Servers) don't support that protocoll. You can configure the DICOM network configuration of your machine by editing the 'Calling AETiltle', the 'Storage AETitle' and The 'Storage Port' text fields. But normaly you don't have to change your configuration. \imageMacro{QmitkDicom_FilterWidget.png,"The DICOM search options",3.66} After you have finished your network configuration and before you start the query you should use the 'Search Options' to specify your query. Otherwise all data on the server will be queried and you will have to wait for a long time. You can specify your query by searching for a specific patient name or a study or a serie or a specific DICOM object by it's id. You are allowed to include or exclude DICOM modalities from your query and you can specify a specific time in which the DICOM images you are searching fo might been captured. When you finished that you can click the query button and the queried DICOM data will appear.
  • Click on the 'Add Server' button.
    • Edit 'Name' field.
    • Edit 'AETitle' field.
    • Edit 'Adress' field.
    • Edit 'Port' field.
  • Set search options.
  • Click on 'Query' button.
\subsection org_mitk_gui_qt_dicomRetrieve Retrieve \imageMacro{QmitkDicom_Retrieve.png,"The queried DICOM data.",15.22} After the query you are able to select the queried data and click the 'Retrieve' button. This will store the queried DICOM data into your DICOM storage. Click on the 'Local Storage' button and work with your new data.
  • Click on the 'Retrieve' button to retrieve the data to your DICOM storage.
  • Click on the 'Local Storage' button.
*/ diff --git a/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg new file mode 100644 index 0000000000..3d10f794ae --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dicom/documentation/UserManual/dicom.svg @@ -0,0 +1,85 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp index 1ed2168d9f..1689bf0c70 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp @@ -1,261 +1,263 @@ /*=================================================================== 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 "mitkPluginActivator.h" #include "DicomEventHandler.h" #include #include #include #include #include #include #include #include #include #include "mitkImage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include + DicomEventHandler::DicomEventHandler() { } DicomEventHandler::~DicomEventHandler() { } void DicomEventHandler::OnSignalAddSeriesToDataManager(const ctkEvent& ctkEvent) { QStringList listOfFilesForSeries; listOfFilesForSeries = ctkEvent.getProperty("FilesForSeries").toStringList(); if (!listOfFilesForSeries.isEmpty()) { //for rt data, if the modality tag isn't defined or is "CT" the image is handled like before if(ctkEvent.containsProperty("Modality") && (ctkEvent.getProperty("Modality").toString().compare("RTDOSE",Qt::CaseInsensitive) == 0 || ctkEvent.getProperty("Modality").toString().compare("RTSTRUCT",Qt::CaseInsensitive) == 0 || ctkEvent.getProperty("Modality").toString().compare("RTPLAN", Qt::CaseInsensitive) == 0)) { QString modality = ctkEvent.getProperty("Modality").toString(); if(modality.compare("RTDOSE",Qt::CaseInsensitive) == 0) { auto doseReader = mitk::RTDoseReaderService(); - doseReader.SetInput(listOfFilesForSeries.front().toStdString()); + doseReader.SetInput(ImporterUtil::getUTF8String(listOfFilesForSeries.front())); std::vector > readerOutput = doseReader.Read(); if (!readerOutput.empty()){ mitk::Image::Pointer doseImage = dynamic_cast(readerOutput.at(0).GetPointer()); mitk::DataNode::Pointer doseImageNode = mitk::DataNode::New(); doseImageNode->SetData(doseImage); doseImageNode->SetName("RTDose"); if (doseImage != nullptr) { std::string sopUID; if (mitk::GetBackwardsCompatibleDICOMProperty(0x0008, 0x0016, "dicomseriesreader.SOPClassUID", doseImage->GetPropertyList(), sopUID)) { doseImageNode->SetName(sopUID); }; berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); if (prefNode.IsNull()) { mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " << prefNode->ToString().toStdString(); } //set some specific colorwash and isoline properties bool showColorWashGlobal = prefNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(), true); bool showIsolinesGlobal = prefNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(), true); //Set reference dose property double referenceDose = prefNode->GetDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE); mitk::ConfigureNodeAsDoseNode(doseImageNode, mitk::GeneratIsoLevels_Virtuos(), referenceDose, showColorWashGlobal); ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference(); mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); dataStorage->Add(doseImageNode); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } }//END DOSE } else if(modality.compare("RTSTRUCT",Qt::CaseInsensitive) == 0) { auto structReader = mitk::RTStructureSetReaderService(); - structReader.SetInput(listOfFilesForSeries.front().toStdString()); + structReader.SetInput(ImporterUtil::getUTF8String(listOfFilesForSeries.front())); std::vector > readerOutput = structReader.Read(); if (readerOutput.empty()){ MITK_ERROR << "No structure sets were created" << endl; } else { std::vector modelVector; ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference(); mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); for (const auto& aStruct : readerOutput){ mitk::ContourModelSet::Pointer countourModelSet = dynamic_cast(aStruct.GetPointer()); mitk::DataNode::Pointer structNode = mitk::DataNode::New(); structNode->SetData(countourModelSet); structNode->SetProperty("name", aStruct->GetProperty("name")); structNode->SetProperty("color", aStruct->GetProperty("contour.color")); structNode->SetProperty("contour.color", aStruct->GetProperty("contour.color")); structNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); structNode->SetVisibility(true, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); structNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); structNode->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); structNode->SetVisibility(true, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); dataStorage->Add(structNode); } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } } else if (modality.compare("RTPLAN", Qt::CaseInsensitive) == 0) { auto planReader = mitk::RTPlanReaderService(); - planReader.SetInput(listOfFilesForSeries.front().toStdString()); + planReader.SetInput(ImporterUtil::getUTF8String(listOfFilesForSeries.front())); std::vector > readerOutput = planReader.Read(); if (!readerOutput.empty()){ //there is no image, only the properties are interesting mitk::Image::Pointer planDummyImage = dynamic_cast(readerOutput.at(0).GetPointer()); mitk::DataNode::Pointer planImageNode = mitk::DataNode::New(); planImageNode->SetData(planDummyImage); planImageNode->SetName("RTPlan"); ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference(); mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); dataStorage->Add(planImageNode); } } } else { mitk::StringList seriesToLoad; QStringListIterator it(listOfFilesForSeries); while (it.hasNext()) { - seriesToLoad.push_back(it.next().toStdString()); + seriesToLoad.push_back(ImporterUtil::getUTF8String(it.next())); } //Get Reference for default data storage. ctkServiceReference serviceReference = mitk::PluginActivator::getContext()->getServiceReference(); mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); std::vector baseDatas = mitk::IOUtil::Load(seriesToLoad.front()); for (const auto &data : baseDatas) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(data); std::string nodeName = "Unnamed Dicom"; std::string studyUID = ""; std::string seriesUID = ""; data->GetPropertyList()->GetStringProperty("DICOM.0020.000D", studyUID); data->GetPropertyList()->GetStringProperty("DICOM.0020.000E", seriesUID); if (!studyUID.empty()) { nodeName = studyUID; } if (!seriesUID.empty()) { if (!studyUID.empty()) { nodeName += "/"; } nodeName += seriesUID; } dataStorage->Add(node); } } } else { MITK_INFO << "There are no files for the current series"; } } void DicomEventHandler::OnSignalRemoveSeriesFromStorage(const ctkEvent& /*ctkEvent*/) { } void DicomEventHandler::SubscribeSlots() { ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); if (ref) { ctkEventAdmin* eventAdmin = mitk::PluginActivator::getContext()->getService(ref); ctkDictionary properties; properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/ADD"; eventAdmin->subscribeSlot(this, SLOT(OnSignalAddSeriesToDataManager(ctkEvent)), properties); properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/DELETED"; eventAdmin->subscribeSlot(this, SLOT(OnSignalRemoveSeriesFromStorage(ctkEvent)), properties); } } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox index 70208b09c3..62658b5368 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox +++ b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/QmitkImageCropper.dox @@ -1,37 +1,37 @@ /** \page org_mitk_gui_qt_imagecropper Image Cropper Plugin -\imageMacro{QmitkImageCropper_Icon.png,"Icon of the Image Cropper Plugin.",20} +\imageMacro{crop.svg,"Icon of the Image Cropper Plugin.",20} \tableofcontents \section org_mitk_gui_qt_imagecropperUsage Usage The Image Cropper Plugin allows to crop subvolumes out of your original image volume by defining a cubic bounding box. This box can be placed at an arbitrary position in the volume and can be easily adjusted by using the handles on each of the faces. Touching the handles changes the size of the box whereas touching the box itself changes its position. As soon as the bounding box is placed at the desired position, pressing the button 'Crop' creates a new image assigned to the original image as child node containing only the selected subvolume. The size of the subvolume equals the size of the bounding box. Pressing the "Mask" button keeps the original image size but masks out the area not contained within the bounding box bounds. In case of 3D+t images the whole time series is cropped by default. \imageMacro{BoundingBox_ImageCropperView.png,"Bounding Box.",12.00} \imageMacro{Basic_ImageCropperView.png,"Basic Settings.",7.09} \section org_mitk_gui_qt_imagecropperAdvanced Advanced settings In the advanced settings view you find additional features to manipulate the bounding box. \imageMacro{Advanced_ImageCropperView.png,"Advanced Settings.",7.09} \subsection org_mitk_gui_qt_imagecropperAdvancedOverwrite Overwrite original image By enabling this checkbox the image is replaced by the cropped subvolume. Be careful to use this option since there is no undo action available. \subsection org_mitk_gui_qt_imagecropperAdvancedTimestep Crop current time step only If this checkbox is enabled the xD + t image is reduced to a xD image (e.g., 3D+t --> 3D) with the time step visible in the widget. This is useful if you want to extract a single image or its corresponding subvolume of the time series. The whole time series is cropped by default using the timeGeometry of the time step visible in the widget. \section org_mitk_gui_qt_imagecropperIssues Current issues Cropping 2D images is not supported unless the are 3D images containing only a single slice. The user will be notified by a warning and the input is handled as a single label image. Right now changing the shape or rotation of the bounding box is not supported but might be integrated in the future. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg new file mode 100644 index 0000000000..7abad89683 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/crop.svg @@ -0,0 +1,60 @@ + + + + + + + image/svg+xml + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox index 2267b623d2..e158d98694 100644 --- a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox +++ b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/QmtikImageNavigator.dox @@ -1,15 +1,15 @@ /** \page org_mitk_views_imagenavigator The Image Navigator -\imageMacro{QmtikImageNavigator_Slider.png,"Icon of the Image Navigator",2.00} +\imageMacro{image_navigator.svg,"Icon of the Image Navigator",2.00} \imageMacro{QmtikImageNavigator_ImageNavigator.png,"Image Navigator",7.47} Fast movement through the available data can be achieved by using the Image Navigator. By moving the sliders around you can scroll quickly through the slides and timesteps. By entering numbers in the relevant fields you can jump directly to your point of interest. The "Show detail" checkbox enables you to see the world coordinates in millimetres and the index/voxel coordinates. These may be edited to jump to a specific location. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg new file mode 100644 index 0000000000..6bde98e8bc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagenavigator/documentation/UserManual/image_navigator.svg @@ -0,0 +1,90 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox index f9c2915943..0de797abdb 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkImageStatistics.dox @@ -1,54 +1,54 @@ /** \page org_mitk_views_imagestatistics The Image Statistics View -\imageMacro{QmitkMeasurementToolbox_ImageStatisticsIcon.png,"Icon of the Image Statistics View",2.00} +\imageMacro{bar-chart.svg,"Icon of the Image Statistics View",2.00} \section QmitkImageStatisticsUserManualSummary Summary This view provides an easy interface to quickly compute some features of a whole image or a region of interest. This document will tell you how to use this view, but it is assumed that you already know how to use MITK in general. Please see \ref QmitkImageStatisticsUserManualDetails for more detailed information on usage and supported filters. If you encounter problems using the view, please have a look at the \ref QmitkImageStatisticsUserManualTrouble page. \section QmitkImageStatisticsUserManualDetails Details Manual sections: - \ref QmitkImageStatisticsUserManualOverview - \ref QmitkImageStatisticsUserManualUsage - \ref QmitkImageStatisticsUserManualTrouble \section QmitkImageStatisticsUserManualOverview Overview This view provides an easy interface to quickly compute some features of a whole image or a region of interest. \imageMacro{QmitkMeasurementToolbox_Interface.png,"The interface",9.10} \section QmitkImageStatisticsUserManualUsage Usage After selection of an image or a binary mask of an image in the datamanager, the Image Statistics view shows some statistical information. If a mask is selected, the name of the mask and the name of the image, to which the mask is applied, are shown at the top. For time data the current time step is used for the selected mask and the selected image. If the total number of time steps on the selected mask is less than the current time step, the last time step of the mask is used. If a mask is selected, its used time step will be displayed next to its name like this: (t=0). Check "Ignore zero-valued voxels" to hide voxels with grayvalue zero. Below it is the statistics window which displays the calculated statistical features (such as mean, standard deviation...). Beneath the statistics window is the histogram window, which shows the histogram of the current selection. At top of the histogram window are two radiobuttons. Toggle one of them to either show the histogram as a barchart or as a lineplot. Use mousewheel to zoom in and out the histogram. With the left mouse button the histogram is pannable in zoomed state. If the histogram is displayed as a barchart a tooltip is available by hovering over one of the bins. A tooltip is also available, if an intesity profile is created for a path element as mask. At the bottom of each view is one button. They copy their respective data in csv format to the clipboard. \section QmitkImageStatisticsUserManualTrouble Troubleshooting No known problems. All other problems.
Please report to the MITK mailing list. See http://www.mitk.org/wiki/Mailinglist on how to do this. */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox index 613a057372..e7ea6bd729 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/QmitkMeasurement.dox @@ -1,126 +1,126 @@ /** \page org_mitk_views_measurement The Measurement View -\imageMacro{QmitkMeasurementToolbox_MeasurementIcon.png,"Icon of the Measurement View",2.00} +\imageMacro{measurement.svg,"Icon of the Measurement View",2.00} \section QmitkMeasurementUserManualOverview Overview The Measurement view enables the user to interact with 2D images or single slices of 3D image stacks and planar figure data types. It allows to measure distances, angels, pathes and several geometric figures on a dataset. \tableofcontents The workflow to use this view is: \imageMacro{QmitkMeasurementToolbox_Workflow.png,"",16.00} The workflow is repeatedly useable with the same or different measurement figures, which are correlated to the choosen image and can be saved together with it for future use. On pressing the Measurement icon (see picture below the page title) in the view button line the basic appearance of the view is as follws. \imageMacro{QmitkMeasurementToolbox_BasicScreenEdited.jpg,"",16.00} The standard working plane is "Axial" but the other standard viewplanes ("Saggital" and "Coronal") are also valid for measurements. To swap between the view planes refer to the application user manual. \section QmitkMeasurementUserManualFeatures Features The view as it is depicted below offers the following features in the order of apperance on the image from top to bottom: \imageMacro{QmitkMeasurementToolbox_MeasurementView.jpg,"",7.60} The first information is the selected image's name (here: DICOM-MRI-Image) followed by the measurement figures button line with the seven measurement figures. From left to right the buttons are connected with the following functions: \subsection SubOne Draw Line Draws a line between two set points and returns the distance between these points. \subsection SubTwo Draw Path Draws a path between several set points (two and more) and calculates the circumference, that is all line's length summed up. Add the final point by double left click. \subsection SubThree Draw Angle Draws two lines from three set points connected in the second set point and returns the inner angle at the second point. \subsection SubFour Draw Four Point Angle Draws two lines that may but must not intersect from four set points. The returned angle is the one depicted in the icon. \subsection SubFive Draw Circle Draws a circle by setting two points, whereas the first set point is the center and the second the radius of the circle. The measured values are the radius and the included area. \subsection SubSix Draw Rectangle Draws a rectangle by setting two points at the opposing edges of the rectangle starting with the upper left edge. The measured values are the circumference and the included area. \subsection SubSeven Draw Polygon Draws a polygon by setting three or more points. The measured values are the circumference and the included area. Add the final point by double left click. Below the buttonline the statistics window is situated, it displays the results of the actual measurements from the selected measurement figures. The content of the statistics window can be copied to the clipboard with the correspondig button for further use in a table calculation programm (e.g. Open Office Calc etc.). \imageMacro{QmitkMeasurementToolbox_ImageProcessed.jpg,"",7.56} The last row contains again a button line to swap from the measurement perspective (activated in the image) to other supported MITK perspectives. \section QmitkMeasurementUserManualUsage Usage This Section is subdivided into four subsections:
  1. Add an image
  2. Work with measurement figures
  3. Save the image with measurement information
  4. Remove measurement figures or image
Let's start with subsection 1 \subsection One Add an image There are two possible ways to add an image to the programm. One is to grap the image with left mouse click from your prefered file browser and simply drag&drop it to the View Plane field. The other way is to use the \imageMacro{QmitkMeasurementToolbox_OpenButton.png,"",2.01} button in the upper left corner of the application. A dialog window appears showing the file tree of the computer. Navigate to the wanted file and select it with the left mouse click. Afterwards just use the dialog's open button. The wanted image appears in the View Plane and in the Data Manager the images name appears as a new tree node. Now the image is loaded it can be adjusted in the usual way ( zoom in/out: right mouse button + moving the mouse up and down, moving the image: press mouse wheel and move the mouse to the wished direction, scroll through the slices( only on 3D images): scroll mouse wheel up and down). \imageMacro{QmitkMeasurementToolbox_ImageLoadedScreen.jpg,"",16.00} After the image is loaded the image's name appears in the Data Manager. By left-clicking on the image name the buttonline becomes activated. \subsection Two Work with measurement figures The measurement view comes with seven measurement figures(see picture below), that can be applied to the images. \imageMacro{QmitkMeasurementToolbox_MeasurementFigureButtonLine.jpg,"",7.22} The results of the measurement with each of these figures is shown in the statistics window and in the lower right corner of the view plane. \imageMacro{QmitkMeasurementToolbox_ImageProcessedScreen.jpg,"",6.96} When applying more then one measurement figure to the image the actual measurement figure is depicted in red and the displayed values belong to this measurement figure. All measurement figures become part of the Data Manager as a node of the image tree. \subsection Three Save the image with measurement information After applying the wanted measurement figures the entire scene consisting of the image and the measurement figures can be saved for future use. Therefore just click the right mouse button when over the image item in the Data Manager and choose the item "Save" in the opening item list. Following to that a save dialog appears where the path to the save folder can be set. Afterwards just accept your choice with the save button. \subsection Four Remove measurement figures or image If the single measurement figures or the image is not needed any longer, it can be removed solely or as an entire group. The image can't be removed without simultaneously removing all the dependent measurement figures that belong to the image tree in the Data Manager. To remove just select the wanted items in the data manager list by left-click on it or if several items wanted to be removed left click on all wanted by simultaneously holding the ctrl-button pressed. For more detailed usage of the save/remove functionality refer to the Data Manager User Manual. ",16.00} */ diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg new file mode 100644 index 0000000000..a756ada699 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/bar-chart.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg new file mode 100644 index 0000000000..d5e6defc77 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/documentation/UserManual/measurement.svg @@ -0,0 +1,196 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox index 2cfc3a9318..cc8f00e9a7 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker.dox @@ -1,64 +1,64 @@ /** \page org_mitk_gui_qt_moviemaker The Movie Maker Plugin -\imageMacro{QmitkMovieMaker_Icon.png,"Icon of the Movie Maker Plugin.",2.00} +\imageMacro{video-camera.svg,"Icon of the Movie Maker Plugin.",2.00} \tableofcontents \section org_mitk_gui_qt_moviemakerOverview Overview The Movie Maker View allows you to create basic animations of your scene and to record them to video files. Individual animations are arranged in a timeline and can be played back sequential or in parallel. The Movie Maker View uses external FFmpeg/Libav command line utilities to write compressed video files. You have to manually install either FFmpeg or Libav and set the corresponding path in "External Programs" in the MITK Workbench Preferences (Ctrl+P) in order to record your movies to video files. \imageMacro{QmitkMovieMaker_Preferences.png,"The External Programs preferences page.",12.00} \section org_mitk_gui_qt_moviemakerUsage Usage \imageMacro{QmitkMovieMaker_MovieMakerView.png,"The Movie Maker View.",16.00} To create a movie you have to add an animation to the timeline by clicking the "Add animation" button. You can choose between the available types of animations, e.g., Orbit or Slice. The timeline surrounding bottons allow you to arrange, remove, or add further animations to your movie. Each animation can be set to either begin with the previous animation, i.e., run in parallel, or to start after the previous animation, i.e., run sequential. In combination with delays, rather complex animation arrangements are possible. To set animation specific parameters, select the corresponding animation in the timeline first. You can play back, pause and stop your movie with the according controls at the bottom of the Movie Maker View. Click the "Record" button to finally record your movie to a video file with the specified number of frames per second. You have to choose the render window which you want to record. \subsection org_mitk_gui_qt_moviemakerOrbitUsage Orbit Animation The Orbit animation rotates the camera in the 3D window around the scene. Align the camera directly in the 3D window and enter the number of degrees for the orbitting. If you are planning to have a specific view in the middle of your movie you can play the movie and pause it at the specific frame of interest. Adjust the camera in the 3D window and restart the animation. \imageMacro{QmitkMovieMaker_Orbit.png,"The Orbit animation.",12.00} \subsection org_mitk_gui_qt_moviemakerSliceUsage Slice Animation The Slice animation slices through an image. You can choose the image plane (axial, sagittal, or coronal), as well as the start and end points of the slicing. Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. Check "Reverse" in order to slice from the higher slice number to the lower slice number. \imageMacro{QmitkMovieMaker_Slice.png,"The Slice animation.",12.00} \subsection org_mitk_gui_qt_moviemakerTimeUsage Time Animation The Time animation steps through the individual time steps of the current scene. You can specify the range of the animated time steps. Use the image navigator in the bottom left of the Workbench to get an idea of the desired values. Check "Reverse" in order to step from later time steps to previous time steps. \imageMacro{QmitkMovieMaker_Time.gif,"The Time animation.",12.00} */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg new file mode 100644 index 0000000000..ebf0fd1bfd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/video-camera.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg new file mode 100644 index 0000000000..9b24feb3b2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/multilabelsegmentation.svg @@ -0,0 +1,10683 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox index 77069cfa4b..a88b5f28fe 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/documentation/UserManual/org_mitk_gui_qt_multilabelsegmentation.dox @@ -1,114 +1,114 @@ /** \page org_mitk_views_multilabelsegmentation The Multilabel Segmentation View -\imageMacro{"multilabelsegmentation.png", "html", 12} +\imageMacro{"multilabelsegmentation.svg", "Icon of the MultiLabelSegmentation Plugin", 12} Please reference \ref org_mitk_views_segmentation for the description of the general segmentation tools. \tableofcontents \section org_mitk_views_multilabelsegmentationUserManualCreateOpenSaveImportAdd Start Segmenting To start using the Segmentation Perspective you will have to either create a new segmentation session or load an existing one from disk. The Segmentation toolbar collects buttons for the these actions: \imageMacro{"org_mitk_views_multilabelsegmentationIMGtoolbar.png", "Segmentation toolbar", 12}
  • Create segmentation session
  • a new segmentation session is created.
  • Load segmentation session
  • a segmentation session can be loaded from disk (.lset file extensions).
  • Save segmentation session
  • the current segmentation session can be saved to disk.
  • Import segmentation session
  • a segmentation session can be incorporated into the current one. All new labels will be appended at the end of the table.
  • Add label
  • a new label is appended to the current segmentation session, at the end of the table.
\section org_mitk_views_multilabelsegmentationUserManualLabelTable The Label Table The following label properties are readily available to modify:
  • Name
  • the name of the label. Can be a predefined one or any other.
  • Color
  • the color of the label.
  • Visible
  • whether the label is currently visible or hiden.
  • Locked
  • whether the label is locked or editable. A locked label cannot be overwritten by another.
The Label Table is shown below: \imageMacro{"org_mitk_views_multilabelsegmentationIMGlabeltable.png", "The Label Table showing all the labels in the current segmentation session", 12} \section org_mitk_views_multilabelsegmentationUserManualLabelCreation Creating a New Label Click the "New Label" button to add a new label. A dialog will show-up to enter the name and color. Preset organ names and corresponding colors are offered while you type in, but you can set any name. The new name if not known will be automatically remembered and made available the next time you create a new label. In the current implementation of the plugin, the maximum number of labels is restricted to 255. If you need more, you will have to create a new segmentation session. \section org_mitk_views_multilabelsegmentationUserManualLayerCreation Creating a New Layer A layer is a set of labels that occupy a non-overlapping anatomical space. The best way to describe them is by a real use case. Imagine you are working on a radiotherpay planning application. In the first layer of your segmentation session you would like to trace the contours of the liver and neighboring organs. You can accomodate all these segmentations in separate labels because they all occupy different anamical regions and do not overlap. Now say you would like to segment the arteries and veins inside the liver. If you don´t trace them in a different layer, you will overwrite the previous ones. You may also need a third layer for segmenting the different irrigation territories in the liver and a fourth layer to contain the lession you would like to treat. The next figure illustrates the Layer Manager . The buttons in it contained serve for adding a new layer, selecting the previous and the next one. The active layer is shown together with the buttons. \imageMacro{"org_mitk_views_multilabelsegmentationIMGlayerManager.png", "Correction Tool",12} \section org_mitk_views_multilabelsegmentationUserManualLabelSearch Searching a Label It may happen that many labels (e.g. > 200) are present in a segmentation session and therefore manual searching is time consuming. The Label Search edit box allows for quickly finding the label you want. Just start writing its name and and you will get assitance for completing its name. If the label you were searching is found, press enter and it will became the active one. \imageMacro{"org_mitk_views_multilabelsegmentationIMGsearchlabel.png", "Label search", 12} \section org_mitk_views_multilabelsegmentationUserManualLabelEditing Label Editing First of all, you have to select the active label by clicking on the corresponding row in the Label Table. Only one label can be active at the time. Then you can select an editing tool in the toolbox. \section org_mitk_views_multilabelsegmentationUserManualOperationsOnLabels Operations on Labels Depending on your selection in the Label Table , several actions are offered: \subsection org_mitk_views_multilabelsegmentationUserManualOperationsOnSingleSelection Single Label Selection If you right click on any label in the table, a menu will pop-up offering the following actions to be performed on the selected label:
  • Rename...
  • : change the name and/or color of the selected label.
  • Remove label
  • : delete the selected label.
  • Erase label
  • : only clear the contents of the selected label.
  • Random color
  • : generate a surface mesh out of the selected label.
  • View only
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • View/Hide all
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • Lock/Unlock all
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
  • Create surface
  • : generate a surface out of the selected label.
  • Create mask
  • : generate a mask out of the selected label. A mask is a binary image with "1" inside and "0" outside.
\imageMacro{"org_mitk_views_multilabelsegmentationIMGLabelTableSingleSelectionContextMenu.png", "Context menu for single label selection", 12} \subsection org_mitk_views_multilabelsegmentationUserManualOperationsOnMultipleSelection Multiple Label Selection If more than one label is selected, a different menu will show up: \imageMacro{"org_mitk_views_multilabelsegmentationIMGLabelTableMultipleSelectionContextMenu.png", "Context menu for multiple label selection", 12}
  • Merge selection on current label
  • : transfer the contents of the selected labels in the Label Table into the current one.
  • Remove selected labels
  • : delete the selected labels.
  • Erase selected labels
  • : only clear the contents of the selected labels.
  • Create a surface for each selected label
  • : generate a surface mesh out of each selected label.
  • Combine and create a surface
  • : generate a surface out of the combination of the selected labels.
  • Create a mask for each selected label
  • : generate a mask out of each selected label. A mask is a binary image with "1" inside and "0" outside.
  • Combine and create a mask
  • : generate a mask out of the combination of the selected labels.
*/ diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp index 2960377da6..36f37eadde 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp @@ -1,1161 +1,1166 @@ /*=================================================================== 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 // Qmitk #include "PAImageProcessing.h" // Qt #include #include #include #include //mitk image #include #include "mitkPhotoacousticImage.h" #include "mitkPhotoacousticBeamformingFilter.h" //other #include #include #include const std::string PAImageProcessing::VIEW_ID = "org.mitk.views.paimageprocessing"; PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false), m_FilterBank(mitk::PhotoacousticImage::New()) { qRegisterMetaType(); qRegisterMetaType(); } void PAImageProcessing::SetFocus() { m_Controls.buttonApplyBModeFilter->setFocus(); } void PAImageProcessing::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.buttonApplyBModeFilter, SIGNAL(clicked()), this, SLOT(StartBmodeThread())); connect(m_Controls.DoResampling, SIGNAL(clicked()), this, SLOT(UseResampling())); connect(m_Controls.Logfilter, SIGNAL(clicked()), this, SLOT(UseLogfilter())); connect(m_Controls.ResamplingValue, SIGNAL(valueChanged(double)), this, SLOT(SetResampling())); connect(m_Controls.buttonApplyBeamforming, SIGNAL(clicked()), this, SLOT(StartBeamformingThread())); connect(m_Controls.buttonApplyCropFilter, SIGNAL(clicked()), this, SLOT(StartCropThread())); connect(m_Controls.buttonApplyBandpass, SIGNAL(clicked()), this, SLOT(StartBandpassThread())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UseImageSpacing())); connect(m_Controls.ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBeamforming())); connect(m_Controls.BPSpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBandpass())); connect(m_Controls.Samples, SIGNAL(valueChanged(int)), this, SLOT(UpdateImageInfo())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UpdateImageInfo())); connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(LowerSliceBoundChanged())); connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpperSliceBoundChanged())); connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(SliceBoundsEnabled())); connect(m_Controls.BatchProcessing, SIGNAL(clicked()), this, SLOT(BatchProcessing())); connect(m_Controls.StepBeamforming, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepCropping, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBandpass, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBMode, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); UpdateSaveBoxes(); m_Controls.DoResampling->setChecked(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(100); m_Controls.progressBar->setVisible(false); m_Controls.UseImageSpacing->setToolTip("Image spacing of y-Axis must be in us, x-Axis in mm."); m_Controls.UseImageSpacing->setToolTipDuration(5000); m_Controls.ProgressInfo->setVisible(false); m_Controls.UseBP->hide(); m_Controls.UseGPUBmode->hide(); #ifndef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(false); m_Controls.UseGPUBf->setChecked(false); m_Controls.UseGPUBmode->setEnabled(false); m_Controls.UseGPUBmode->setChecked(false); #endif UseImageSpacing(); } void PAImageProcessing::ChangedSOSBandpass() { m_Controls.SpeedOfSound->setValue(m_Controls.BPSpeedOfSound->value()); } void PAImageProcessing::ChangedSOSBeamforming() { m_Controls.BPSpeedOfSound->setValue(m_Controls.SpeedOfSound->value()); } std::vector splitpath( const std::string& str , const std::set delimiters) { std::vector result; char const* pch = str.c_str(); char const* start = pch; for (; *pch; ++pch) { if (delimiters.find(*pch) != delimiters.end()) { if (start != pch) { std::string str(start, pch); result.push_back(str); } else { result.push_back(""); } start = pch + 1; } } result.push_back(start); return result; } void PAImageProcessing::UpdateSaveBoxes() { if (m_Controls.StepBeamforming->isChecked()) m_Controls.SaveBeamforming->setEnabled(true); else m_Controls.SaveBeamforming->setEnabled(false); if (m_Controls.StepCropping->isChecked()) m_Controls.SaveCropping->setEnabled(true); else m_Controls.SaveCropping->setEnabled(false); if (m_Controls.StepBandpass->isChecked()) m_Controls.SaveBandpass->setEnabled(true); else m_Controls.SaveBandpass->setEnabled(false); if (m_Controls.StepBMode->isChecked()) m_Controls.SaveBMode->setEnabled(true); else m_Controls.SaveBMode->setEnabled(false); } void PAImageProcessing::BatchProcessing() { QFileDialog LoadDialog(nullptr, "Select Files to be processed"); LoadDialog.setFileMode(QFileDialog::FileMode::ExistingFiles); LoadDialog.setNameFilter(tr("Images (*.nrrd)")); LoadDialog.setViewMode(QFileDialog::Detail); QStringList fileNames; if (LoadDialog.exec()) fileNames = LoadDialog.selectedFiles(); QString saveDir = QFileDialog::getExistingDirectory(nullptr, tr("Select Directory To Save To"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); DisableControls(); std::set delims{'/'}; bool doSteps[] = { m_Controls.StepBeamforming->isChecked(), m_Controls.StepCropping->isChecked() , m_Controls.StepBandpass->isChecked(), m_Controls.StepBMode->isChecked() }; bool saveSteps[] = { m_Controls.SaveBeamforming->isChecked(), m_Controls.SaveCropping->isChecked() , m_Controls.SaveBandpass->isChecked(), m_Controls.SaveBMode->isChecked() }; for (int fileNumber = 0; fileNumber < fileNames.size(); ++fileNumber) { m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("loading file"); QString filename = fileNames.at(fileNumber); auto split = splitpath(filename.toStdString(), delims); std::string imageName = split.at(split.size()-1); // remove ".nrrd" imageName = imageName.substr(0, imageName.size()-5); mitk::Image::Pointer image = mitk::IOUtil::Load(filename.toStdString().c_str()); UpdateBFSettings(image); // Beamforming if (doSteps[0]) { std::function progressHandle = [this](int progress, std::string progressInfo) { this->UpdateProgress(progress, progressInfo); }; m_Controls.progressBar->setValue(100); std::string errorMessage = ""; image = m_FilterBank->ApplyBeamforming(image, BFconfig, errorMessage, progressHandle); if (saveSteps[0]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " beamformed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Cropping if (doSteps[1]) { m_Controls.ProgressInfo->setText("cropping image"); image = m_FilterBank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, image->GetDimension(2) - 1); if (saveSteps[1]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " cropped" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bandpass if (doSteps[2]) { m_Controls.ProgressInfo->setText("applying bandpass"); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } if (BPHighPass > maxFrequency - BFconfig.BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } - image = m_FilterBank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, m_Controls.BPFalloff->value()); + image = m_FilterBank->BandpassFilter(image, recordTime, BPHighPass, BPLowPass, + m_Controls.BPFalloffHigh->value(), + m_Controls.BPFalloffLow->value()); if (saveSteps[2]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bandpassed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bmode if (doSteps[3]) { m_Controls.ProgressInfo->setText("applying bmode filter"); bool useGPU = m_Controls.UseGPUBmode->isChecked(); if (m_Controls.BModeMethod->currentText() == "Absolute Filter") image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU, m_UseLogfilter, m_ResampleSpacing); else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU, m_UseLogfilter, m_ResampleSpacing); if (saveSteps[3]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bmode" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } m_Controls.progressBar->setVisible(false); } EnableControls(); } void PAImageProcessing::StartBeamformingThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing beamforming for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("started"); m_Controls.buttonApplyBeamforming->setText("working..."); DisableControls(); BeamformingThread *thread = new BeamformingThread(); connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleBeamformingResults); connect(thread, &BeamformingThread::updateProgress, this, &PAImageProcessing::UpdateProgress); connect(thread, &BeamformingThread::message, this, &PAImageProcessing::PAMessageBox); connect(thread, &BeamformingThread::finished, thread, &QObject::deleteLater); thread->setConfig(BFconfig); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Beamforming"; thread->start(); } } } void PAImageProcessing::HandleBeamformingResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DAS) newNodeName << "DAS bf, "; else if (BFconfig.Algorithm == mitk::BeamformingSettings::BeamformingAlgorithm::DMAS) newNodeName << "DMAS bf, "; if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::QuadApprox) newNodeName << "q. delay"; if (BFconfig.DelayCalculationMethod == mitk::BeamformingSettings::DelayCalc::Spherical) newNodeName << "s. delay"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); levelWindow.SetAuto(image, true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.ProgressInfo->setVisible(false); m_Controls.buttonApplyBeamforming->setText("Apply Beamforming"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews(image->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartBmodeThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image processing."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyBModeFilter->setText("working..."); DisableControls(); BmodeThread *thread = new BmodeThread(); connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleBmodeResults); connect(thread, &BmodeThread::finished, thread, &QObject::deleteLater); bool useGPU = m_Controls.UseGPUBmode->isChecked(); if(m_Controls.BModeMethod->currentText() == "Absolute Filter") thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::Abs, useGPU); else if(m_Controls.BModeMethod->currentText() == "Envelope Detection") thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticImage::BModeMethod::EnvelopeDetection, useGPU); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Processing"; thread->start(); } } } void PAImageProcessing::HandleBmodeResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "B-Mode"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.buttonApplyBModeFilter->setText("Apply B-mode Filter"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartCropThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing image cropping for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyCropFilter->setText("working..."); DisableControls(); CropThread *thread = new CropThread(); connect(thread, &CropThread::result, this, &PAImageProcessing::HandleCropResults); connect(thread, &CropThread::finished, thread, &QObject::deleteLater); thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, image->GetDimension(2) - 1); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Cropping"; thread->start(); } } } void PAImageProcessing::HandleCropResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "Cropped"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); m_Controls.buttonApplyCropFilter->setText("Apply Crop Filter"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::StartBandpassThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before starting image cropping."); return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { UpdateBFSettings(image); std::stringstream message; std::string name; message << "Performing Bandpass filter on image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.buttonApplyBandpass->setText("working..."); DisableControls(); BandpassThread *thread = new BandpassThread(); connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleBandpassResults); connect(thread, &BandpassThread::finished, thread, &QObject::deleteLater); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } if (BPHighPass > maxFrequency - BFconfig.BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } - thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloff->value(), recordTime); + thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloffLow->value(), m_Controls.BPFalloffHigh->value(), recordTime); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Bandpass filter"; thread->start(); } } } void PAImageProcessing::HandleBandpassResults(mitk::Image::Pointer image) { auto newNode = mitk::DataNode::New(); newNode->SetData(image); // name the new Data node std::stringstream newNodeName; newNodeName << m_OldNodeName << " "; newNodeName << "Bandpassed"; newNode->SetName(newNodeName.str()); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); auto data = newNode->GetData(); levelWindow.SetAuto(dynamic_cast(data), true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); m_Controls.buttonApplyBandpass->setText("Apply Bandpass"); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews( dynamic_cast(data)->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void PAImageProcessing::SliceBoundsEnabled() { if (!m_Controls.Partial->isChecked()) { m_Controls.boundLow->setEnabled(false); m_Controls.boundHigh->setEnabled(false); return; } else { m_Controls.boundLow->setEnabled(true); m_Controls.boundHigh->setEnabled(true); } } void PAImageProcessing::UpperSliceBoundChanged() { if(m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundLow->setValue(m_Controls.boundHigh->value()); } } void PAImageProcessing::LowerSliceBoundChanged() { if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundHigh->setValue(m_Controls.boundLow->value()); } } void PAImageProcessing::UpdateProgress(int progress, std::string progressInfo) { if (progress < 100) m_Controls.progressBar->setValue(progress); else m_Controls.progressBar->setValue(100); m_Controls.ProgressInfo->setText(progressInfo.c_str()); qApp->processEvents(); } void PAImageProcessing::PAMessageBox(std::string message) { if (0 != message.compare("noMessage")) { QMessageBox msgBox; msgBox.setText(message.c_str()); msgBox.exec(); } } void PAImageProcessing::UpdateImageInfo() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected return; } mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast(data); if (image) { // beamforming configs if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ElementCount->setValue(image->GetDimension(0)); m_Controls.Pitch->setValue(image->GetGeometry()->GetSpacing()[0]); } m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); m_Controls.boundHigh->setMaximum(image->GetDimension(2) - 1); UpdateBFSettings(image); m_Controls.CutoffBeforeBF->setValue(0.000001 / BFconfig.TimeSpacing); // 1us standard offset for our transducer std::stringstream frequency; float maxFrequency = (1 / BFconfig.TimeSpacing) * image->GetDimension(1) / 2 / 2 / 1000; frequency << maxFrequency / 1000000; //[MHz] frequency << "MHz"; m_Controls.BPhigh->setMaximum(maxFrequency / 1000000); m_Controls.BPlow->setMaximum(maxFrequency / 1000000); frequency << " is the maximal allowed frequency for the selected image."; m_Controls.BPhigh->setToolTip(frequency.str().c_str()); m_Controls.BPlow->setToolTip(frequency.str().c_str()); m_Controls.BPhigh->setToolTipDuration(5000); m_Controls.BPlow->setToolTipDuration(5000); } } } void PAImageProcessing::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_Controls.labelWarning->setVisible( false ); m_Controls.buttonApplyBModeFilter->setEnabled( true ); m_Controls.labelWarning2->setVisible(false); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.labelWarning3->setVisible(false); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.labelWarning4->setVisible(false); m_Controls.buttonApplyBeamforming->setEnabled(true); UpdateImageInfo(); return; } } m_Controls.labelWarning->setVisible( true ); m_Controls.buttonApplyBModeFilter->setEnabled( false ); m_Controls.labelWarning2->setVisible(true); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.labelWarning3->setVisible(true); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.labelWarning4->setVisible(true); m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseResampling() { if (m_Controls.DoResampling->isChecked()) { m_Controls.ResamplingValue->setEnabled(true); m_ResampleSpacing = m_Controls.ResamplingValue->value(); } else { m_Controls.ResamplingValue->setEnabled(false); m_ResampleSpacing = 0; } } void PAImageProcessing::UseLogfilter() { m_UseLogfilter = m_Controls.Logfilter->isChecked(); } void PAImageProcessing::SetResampling() { m_ResampleSpacing = m_Controls.ResamplingValue->value(); } void PAImageProcessing::UpdateBFSettings(mitk::Image::Pointer image) { if ("DAS" == m_Controls.BFAlgorithm->currentText()) BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; else if ("DMAS" == m_Controls.BFAlgorithm->currentText()) BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; else if ("sDMAS" == m_Controls.BFAlgorithm->currentText()) BFconfig.Algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; if ("Quad. Approx." == m_Controls.DelayCalculation->currentText()) { BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::QuadApprox; } else if ("Spherical Wave" == m_Controls.DelayCalculation->currentText()) { BFconfig.DelayCalculationMethod = mitk::BeamformingSettings::DelayCalc::Spherical; } if ("Von Hann" == m_Controls.Apodization->currentText()) { BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hann; } else if ("Hamming" == m_Controls.Apodization->currentText()) { BFconfig.Apod = mitk::BeamformingSettings::Apodization::Hamm; } else if ("Box" == m_Controls.Apodization->currentText()) { BFconfig.Apod = mitk::BeamformingSettings::Apodization::Box; } BFconfig.Pitch = m_Controls.Pitch->value() / 1000; // [m] BFconfig.SpeedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] BFconfig.SamplesPerLine = m_Controls.Samples->value(); BFconfig.ReconstructionLines = m_Controls.Lines->value(); BFconfig.TransducerElements = m_Controls.ElementCount->value(); BFconfig.apodizationArraySize = m_Controls.Lines->value(); BFconfig.Angle = m_Controls.Angle->value(); // [deg] BFconfig.UseBP = m_Controls.UseBP->isChecked(); BFconfig.UseGPU = m_Controls.UseGPUBf->isChecked(); BFconfig.upperCutoff = m_Controls.CutoffBeforeBF->value(); if (m_Controls.UseImageSpacing->isChecked()) { BFconfig.RecordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000; // [s] BFconfig.TimeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000; MITK_INFO << "Calculated Scan Depth of " << BFconfig.RecordTime * BFconfig.SpeedOfSound * 100 / 2 << "cm"; } else { BFconfig.RecordTime = 2 * m_Controls.ScanDepth->value() / 1000 / BFconfig.SpeedOfSound; // [s] BFconfig.TimeSpacing = BFconfig.RecordTime / image->GetDimension(1); } if ("US Image" == m_Controls.ImageType->currentText()) { BFconfig.isPhotoacousticImage = false; } else if ("PA Image" == m_Controls.ImageType->currentText()) { BFconfig.isPhotoacousticImage = true; } BFconfig.partial = m_Controls.Partial->isChecked(); BFconfig.CropBounds[0] = m_Controls.boundLow->value(); BFconfig.CropBounds[1] = m_Controls.boundHigh->value(); } void PAImageProcessing::EnableControls() { m_Controls.BatchProcessing->setEnabled(true); m_Controls.StepBeamforming->setEnabled(true); m_Controls.StepBandpass->setEnabled(true); m_Controls.StepCropping->setEnabled(true); m_Controls.StepBMode->setEnabled(true); UpdateSaveBoxes(); m_Controls.DoResampling->setEnabled(true); UseResampling(); m_Controls.Logfilter->setEnabled(true); m_Controls.BModeMethod->setEnabled(true); m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.CutoffAbove->setEnabled(true); m_Controls.CutoffBelow->setEnabled(true); m_Controls.CutoffBeforeBF->setEnabled(true); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.BPSpeedOfSound->setEnabled(true); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.Partial->setEnabled(true); m_Controls.boundHigh->setEnabled(true); m_Controls.boundLow->setEnabled(true); m_Controls.BFAlgorithm->setEnabled(true); m_Controls.DelayCalculation->setEnabled(true); m_Controls.ImageType->setEnabled(true); m_Controls.Apodization->setEnabled(true); m_Controls.UseBP->setEnabled(true); #ifdef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(true); m_Controls.UseGPUBmode->setEnabled(true); #endif m_Controls.BPhigh->setEnabled(true); m_Controls.BPlow->setEnabled(true); - m_Controls.BPFalloff->setEnabled(true); + m_Controls.BPFalloffLow->setEnabled(true); + m_Controls.BPFalloffHigh->setEnabled(true); m_Controls.UseImageSpacing->setEnabled(true); UseImageSpacing(); m_Controls.Pitch->setEnabled(true); m_Controls.ElementCount->setEnabled(true); m_Controls.SpeedOfSound->setEnabled(true); m_Controls.Samples->setEnabled(true); m_Controls.Lines->setEnabled(true); m_Controls.Angle->setEnabled(true); m_Controls.buttonApplyBeamforming->setEnabled(true); } void PAImageProcessing::DisableControls() { m_Controls.BatchProcessing->setEnabled(false); m_Controls.StepBeamforming->setEnabled(false); m_Controls.StepBandpass->setEnabled(false); m_Controls.StepCropping->setEnabled(false); m_Controls.StepBMode->setEnabled(false); m_Controls.SaveBeamforming->setEnabled(false); m_Controls.SaveBandpass->setEnabled(false); m_Controls.SaveCropping->setEnabled(false); m_Controls.SaveBMode->setEnabled(false); m_Controls.DoResampling->setEnabled(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.Logfilter->setEnabled(false); m_Controls.BModeMethod->setEnabled(false); m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.CutoffAbove->setEnabled(false); m_Controls.CutoffBelow->setEnabled(false); m_Controls.CutoffBeforeBF->setEnabled(false); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.BPSpeedOfSound->setEnabled(false); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.Partial->setEnabled(false); m_Controls.boundHigh->setEnabled(false); m_Controls.boundLow->setEnabled(false); m_Controls.BFAlgorithm->setEnabled(false); m_Controls.DelayCalculation->setEnabled(false); m_Controls.ImageType->setEnabled(false); m_Controls.Apodization->setEnabled(false); m_Controls.UseBP->setEnabled(false); #ifdef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(false); m_Controls.UseGPUBmode->setEnabled(false); #endif m_Controls.BPhigh->setEnabled(false); m_Controls.BPlow->setEnabled(false); - m_Controls.BPFalloff->setEnabled(false); + m_Controls.BPFalloffLow->setEnabled(false); + m_Controls.BPFalloffHigh->setEnabled(false); m_Controls.UseImageSpacing->setEnabled(false); m_Controls.ScanDepth->setEnabled(false); m_Controls.Pitch->setEnabled(false); m_Controls.ElementCount->setEnabled(false); m_Controls.SpeedOfSound->setEnabled(false); m_Controls.Samples->setEnabled(false); m_Controls.Lines->setEnabled(false); m_Controls.Angle->setEnabled(false); m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseImageSpacing() { if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ScanDepth->setDisabled(true); } else { m_Controls.ScanDepth->setEnabled(true); } } #include void BeamformingThread::run() { mitk::Image::Pointer resultImage = mitk::Image::New(); mitk::Image::Pointer resultImageBuffer; std::string errorMessage = ""; std::function progressHandle = [this](int progress, std::string progressInfo) { emit updateProgress(progress, progressInfo); }; resultImageBuffer = m_FilterBank->ApplyBeamforming(m_InputImage, m_BFconfig, errorMessage, progressHandle); mitk::ImageReadAccessor copy(resultImageBuffer); resultImage->Initialize(resultImageBuffer); resultImage->SetSpacing(resultImageBuffer->GetGeometry()->GetSpacing()); resultImage->SetImportVolume(const_cast(copy.GetData()), 0, 0, mitk::Image::CopyMemory); emit result(resultImage); emit message(errorMessage); } void BeamformingThread::setConfig(mitk::BeamformingSettings BFconfig) { m_BFconfig = BFconfig; } void BeamformingThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BmodeThread::run() { mitk::Image::Pointer resultImage; resultImage = m_FilterBank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseGPU, m_UseLogfilter, m_ResampleSpacing); emit result(resultImage); } void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU) { m_UseLogfilter = useLogfilter; m_ResampleSpacing = resampleSpacing; m_Method = method; m_UseGPU = useGPU; } void BmodeThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void CropThread::run() { mitk::Image::Pointer resultImage; resultImage = m_FilterBank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, m_CutSliceFirst, m_CutSliceLast); emit result(resultImage); } void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast) { m_CutAbove = CutAbove; m_CutBelow = CutBelow; m_CutSliceLast = CutSliceLast; m_CutSliceFirst = CutSliceFirst; } void CropThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BandpassThread::run() { mitk::Image::Pointer resultImage; - resultImage = m_FilterBank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlpha); + resultImage = m_FilterBank->BandpassFilter(m_InputImage, m_RecordTime, m_BPHighPass, m_BPLowPass, m_TukeyAlphaHighPass, m_TukeyAlphaLowPass); emit result(resultImage); } -void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime) +void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime) { m_BPHighPass = BPHighPass; m_BPLowPass = BPLowPass; - m_TukeyAlpha = TukeyAlpha; + m_TukeyAlphaHighPass = TukeyAlphaHighPass; + m_TukeyAlphaLowPass = TukeyAlphaLowPass; m_RecordTime = recordTime; } void BandpassThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h index d20b78b3ae..8bb5eb860e 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h @@ -1,254 +1,255 @@ /*=================================================================== 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 PAImageProcessing_h #define PAImageProcessing_h #include #include #include #include #include "ui_PAImageProcessingControls.h" #include "mitkPhotoacousticBeamformingFilter.h" #include "mitkPhotoacousticBeamformingSettings.h" Q_DECLARE_METATYPE(mitk::Image::Pointer) Q_DECLARE_METATYPE(std::string) /*! * \brief Plugin implementing an interface for the Photoacoustic Algorithms Module * * Beamforming, Image processing as B-Mode filtering, cropping, resampling, as well as batch processing can be performed using this plugin. */ class PAImageProcessing : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; PAImageProcessing(); protected slots: void UpperSliceBoundChanged(); void LowerSliceBoundChanged(); void SliceBoundsEnabled(); void UseResampling(); void UseLogfilter(); void SetResampling(); void UseImageSpacing(); void UpdateImageInfo(); /** \brief Method called when the beamforming thread finishes; * it adds the image to a new data node and registers it to the worbench's data storage */ void HandleBeamformingResults(mitk::Image::Pointer image); /** \brief Beamforming is being performed in a separate thread to keep the workbench from freezing. */ void StartBeamformingThread(); /** \brief Method called when the B-mode filter thread finishes; * it adds the image to a new data node and registers it to the worbench's data storage */ void HandleBmodeResults(mitk::Image::Pointer image); /** \brief B-mode filtering is being performed in a separate thread to keep the workbench from freezing. */ void StartBmodeThread(); /** \brief Method called when the Cropping thread finishes; * it adds the image to a new data node and registers it to the worbench's data storage */ void HandleCropResults(mitk::Image::Pointer image); /** \brief Cropping is being performed in a separate thread to keep the workbench from freezing. */ void StartCropThread(); /** \brief Method called when the bandpass thread finishes; * it adds the image to a new data node and registers it to the worbench's data storage */ void HandleBandpassResults(mitk::Image::Pointer image); /** \brief Bandpassing is being performed in a separate thread to keep the workbench from freezing. */ void StartBandpassThread(); void UpdateProgress(int progress, std::string progressInfo); void PAMessageBox(std::string message); void BatchProcessing(); void UpdateSaveBoxes(); void ChangedSOSBandpass(); void ChangedSOSBeamforming(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; /** \brief called by QmitkFunctionality when DataManager's selection has changed. * On a change some parameters are internally updated to calculate bounds for GUI elements as the slice selector for beamforming or * the bandpass filter settings. */ virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, const QList& nodes ) override; /** \brief Instance of the GUI controls */ Ui::PAImageProcessingControls m_Controls; float m_ResampleSpacing; bool m_UseLogfilter; std::string m_OldNodeName; /** \brief The settings set which is used for beamforming, updated through this class. */ mitk::BeamformingSettings BFconfig; /** \brief Method for updating the BFconfig by using a selected image and the GUI configuration. */ void UpdateBFSettings(mitk::Image::Pointer image); void EnableControls(); void DisableControls(); /** \brief Class through which the filters are called. */ mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BeamformingThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); void updateProgress(int, std::string); void message(std::string); public: void setConfig(mitk::BeamformingSettings BFconfig); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::BeamformingSettings m_BFconfig; mitk::Image::Pointer m_InputImage; int m_Cutoff; mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BmodeThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: enum BModeMethod { ShapeDetection, Abs }; void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticImage::BModeMethod method, bool useGPU); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; mitk::PhotoacousticImage::BModeMethod m_Method; bool m_UseLogfilter; double m_ResampleSpacing; bool m_UseGPU; mitk::PhotoacousticImage::Pointer m_FilterBank; }; class CropThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: void setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; unsigned int m_CutAbove; unsigned int m_CutBelow; unsigned int m_CutSliceLast; unsigned int m_CutSliceFirst; mitk::PhotoacousticImage::Pointer m_FilterBank; }; class BandpassThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer); public: - void setConfig(float BPHighPass, float BPLowPass, float TukeyAlpha, float recordTime); + void setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticImage::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; float m_BPHighPass; float m_BPLowPass; - float m_TukeyAlpha; + float m_TukeyAlphaHighPass; + float m_TukeyAlphaLowPass; float m_RecordTime; mitk::PhotoacousticImage::Pointer m_FilterBank; }; #endif // PAImageProcessing_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui index fcd6e415c8..2cf6316fd3 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui @@ -1,991 +1,1027 @@ PAImageProcessingControls 0 0 - 382 + 385 1278 0 0 QmitkTemplate <html><head/><body><p><span style=" font-weight:600;">Batch Processing</span></p></body></html> Start Batch Processing Bandpass true Crop true Save - true + false Save - true + false Save + + true + Beamform true BMode true Save true <html><head/><body><p><span style=" font-weight:600;">B-mode Filter Settings</span></p></body></html> - Absolute Filter + Envelope Detection Absolute Filter Envelope Detection Do Resampling true 0 0 13 0 11 3 0.010000000000000 1.000000000000000 0.010000000000000 - 0.075000000000000 + 0.150000000000000 [mm] Resampled Depth Spacing - Add Logfilter + Logarithmic Compression Use GPU QLabel { color: rgb(255, 0, 0) } <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Please select an image!</span></p></body></html> 0 0 Do image processing Apply B-mode Filter Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Bandpass Filter Settings</span></p></body></html> QLayout::SetDefaultConstraint 0 0 0 3 0.010000000000000 200.000000000000000 - 15.000000000000000 + 1.000000000000000 [MHz] f High Pass [MHz] f Low Pass 0 0 3 200.000000000000000 - - - - Tukey window alpha - - - - + 1 200.000000000000000 3000.000000000000000 5.000000000000000 1540.000000000000000 - + [m/s] Speed of Sound - - + + + + 1.000000000000000 + + + 0.100000000000000 + + + 0.500000000000000 + + + + + + + Tukey Window α High Pass + + + + + 2 1.000000000000000 0.100000000000000 - 0.500000000000000 + 0.000000000000000 + + + + + + + Tukey Window α Low Pass <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Bandpass Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Crop Filter Settings</span></p></body></html> 99999 - 10 + 300 Cut Top Cut Bottom 99999 5 - 165 + 800 <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Crop Filer Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Beamforming Filter Settings</span></p></body></html> 5 2 Delay Calculation Auto Get Depth true Apply Beamforming Beamforming Method [mm] Scan Depth 0 0 3 0.010000000000000 9.000000000000000 0.050000000000000 0.300000000000000 Transducer Elements 0 0 4 300.000000000000000 0.100000000000000 50.000000000000000 [mm] Transducer Pitch 0 0 64 1024 128 128 0 0 256 16384 256 2048 0 0 64 2048 128 256 Samples Reconstruction Lines true 0 0 100 0 0 0 900 10 0 0 0 DAS DMAS sDMAS 0 0 - Quad. Approx. + Spherical Wave Quad. Approx. Spherical Wave 0 0 PA Image US Image Image Type 0 0 Von Hann Hamming Box Apodization 0 0 1 200.000000000000000 3000.000000000000000 5.000000000000000 1540.000000000000000 [m/s] Speed of Sound false 99999 minimal beamformed slice min false 99999 10 Maximal beamformed slice max select slices Compute On GPU true true Auto Use Bandpass 0 0 1 1.000000000000000 180.000000000000000 27.000000000000000 [°] Element Angle Cutoff Upper Voxels <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox index 012e67114d..a65d740abe 100644 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/QmitkPointSetInteraction.dox @@ -1,47 +1,47 @@ /** \page org_mitk_views_pointsetinteraction The Point Set Interaction View -\imageMacro{QmitkPointSetInteraction_Icon.png,"Icon of the Point Set Interaction View",2.00} +\imageMacro{pointset_interaction.svg,"Icon of the Point Set Interaction View",2.00} Available sections: - \ref QmitkPointSetInteractionUserManualOverview - \ref QmitkPointSetInteractionUserManualDetails \section QmitkPointSetInteractionUserManualOverview Overview This view allows you to define multiple sets of points, to fill them with points and to save them in so called PointSets. \imageMacro{QmitkPointSetInteraction_Screenshot.png,"MITK with the QmitkPointSetInteraction view",16.00} This document will tell you how to use this view, but it is assumed that you already know how to navigate through the slices of an image using the four window view. Please read the application manual for more information. \section QmitkPointSetInteractionUserManualDetails Details First of all you have to select a PointSet to use this view. Therefore, you have to select the point set in the data manager. If there are currently no point sets in the data tree, you have to first add a new point set to the data tree. This is done by clicking the "Add pointset..." button. \imageMacro{QmitkPointSetInteraction_AddPointSet.png,"The Add pointset... dialog",8.64} In the pop-up dialog, you have to specify a name for the new point set. This is also the node for the new data tree item. \imageMacro{QmitkPointSetInteraction_CurrentPointSetArea.png,"The Current pointset area",6.52} The "Current pointset" area contains a list of points. Within this area, all points for the current point set node are listed. To set points you have to toggle the "Set Points" button, the leftmost of the four buttons on the bottom of the view. Points can be defined by performing a left mouse button click while holding the "Shift"-key pressed in the four window view. To erase all points from the list press the next button. The user is prompted to confirm the decision. If you want to delete only a single point, left click on it in the list and then press delete on your keyboard. With the third button, a previously saved point set can be loaded and all of its points are shown in the list and the four window view. The user is prompted to select the file to be loaded. The file extension is ".mps". On the right of this button is the save button. With this function the entire point set can be saved to the harddrive. The user is prompted to select a filename. Pointsets are saved in XML fileformat but have to have a ".mps" file extension. You can select points in the render window, if the "Set Points" button is toggled, with a left mouse button click on them. If you keep the mouse button pressed, you can move the points by moving the mouse and then releasing the mouse button. With the delete key you can remove the selected points. */ \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg new file mode 100644 index 0000000000..969c6568aa --- /dev/null +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/documentation/UserManual/pointset_interaction.svg @@ -0,0 +1,77 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox index b769e64cd1..82afd40d2f 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation.dox @@ -1,317 +1,317 @@ /** \page org_mitk_views_segmentation The Segmentation Plugin -\imageMacro{QmitkSegmentation_Icon.png,"Icon of the Segmentation Plugin",2.00} +\imageMacro{segmentation.svg,"Icon of the Segmentation Plugin",2.00} Some of the features described below are closed source additions to the open source toolkit MITK and are not available in every application. \tableofcontents \section org_mitk_gui_qt_segmentationUserManualOverview Overview The Segmentation plugin allows you to create segmentations of anatomical and pathological structures in medical images of the human body. The plugin consists of a number of view which can be used for:
  • manual and (semi-)automatic segmentation of organs on CT or MR image volumes via the Segmentation View
  • segmentation postprocessing via the \subpage org_mitk_views_segmentationutilities
  • clipping of existing segmentations using a resection plane via the \subpage org_mitk_views_deformableclippingplane
\imageMacro{QmitkSegmentation_IMGApplication.png,"Segmentation Plugin consisting of the Segmentation View the Segmentation Utilities View and the Clipping Plane View", 16.00} The segmentation plugin offers a number of preferences which can be set via the MITK Workbench application preference dialog: \imageMacro{QmitkSegmentation_IMGPreferences.png,"Segmentation Plugin consisting of the Segmentation View the Segmentation Utilities View and the Clipping Plane View", 10.00} The following preferences can be set:
  • Slim view: Allows you to show or hide the tool button description of the Segmentation View
  • 2D display: Specify whether the segmentation is drawn as outline or as a transparent overlay
  • 3D display: Activate 3D volume rendering for your segmentation
  • Data node selection mode: If activated the segmentation image combo box is always sychronized with the data manager selection.
  • Smoothed surface creation: Set certain smoothing parameters for surface creation
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. \imageMacro{QmitkSegmentation_IMGSelection.png,"Data Manager is used for selecting the current segmentation. The reference image is selected in the drop down box of the control area.",5.50} To select the reference image (e.g. the original CT/MR image) use the patient image drop down box in the control area of the Segmentation view. The segmentation image selected in the Data Manager is displayed below in the segmentation drop down box. By default the auto selection mode is enabled, which always keeps the selection of the segmentation drop down box in synch with the selection in the data manager. If you disable the auto selection mode the selection of the right segmentation image has to be done via the drop down box. If no segmentation image exists or none is selected create a new segmentation image by using the "New segmentation" button on the right of the Segmentation drop down box. Some items of the graphical user interface might be disabled when no image is selected or the selected image does not fit to the patient image's geoemtry. In any case, the application will give you hints if a selection is needed. \section org_mitk_gui_qt_segmentationUserManualToolOverview Tool overview MITK comes with a comprehensive set of segmentation tools. These tools can be differenciated between manual slice-based 2D segmentation tools and (semi-)automated 3D tools. The manual 2D tools require a big amount of user interaction and can only be applied to a single image slice whereas the 3D tools operate on the hole image. The 3D tools usually require a small amount of interaction like placin seedpoints of setting some parameters. You can switch between the different toolsets by switching the 2D/3D tab in the segmentation view. \imageMacro{QmitkSegmentation_ToolOverview.png,"An overview of the existing tools in MITK. There are interactive 2D tools as well as (semi-)automated 3D tools",5.50} \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. \imageMacro{QmitkSegmentation_IMGIconAddSubtract.png,"Add and Subtract Tools",7.70} 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). \imageMacro{QmitkSegmentation_IMGIconPaintWipe.png,"Paint and Wipe Tools",7.68} 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. \imageMacro{QmitkSegmentation_IMGIconRegionGrowing.png,"Region Growing Tool",3.81} 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. Moving the mouse left and right will shift the range. 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. \if THISISNOTIMPLEMENTEDATTHEMOMENT 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). \imageMacro{QmitkSegmentation_IMGLeakage.png,"Leakage correction feature of the Region Growing tool",11.28} \endif
\imageMacro{QmitkSegmentation_IMGIconCorrection.png,"Correction Tool",3.77} 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)
\imageMacro{QmitkSegmentation_IMGCorrectionActions.png,"%Actions of the Correction tool illustrated.",13.50}
\imageMacro{QmitkSegmentation_IMGIconFill.png,"Fill Tool",3.81} Left-click inside a segmentation with holes to completely fill all holes (left-click outside a segmentation). \imageMacro{QmitkSegmentation_IMGIconErase.png,"Erase Tool",3.79} 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 (left-click outside a segmentation). \imageMacro{QmitkSegmentation_IMGIconLiveWire.png,"LiveWire Tool",3.01} The LiveWire Tool acts as a magnetic lasso with a contour snapping to edges of objects. \imageMacro{QmitkSegmentation_IMGLiveWireUsage.png,"Steps for using LiveWire Tool",16.00}
  • (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. \imageMacro{QmitkSegmentation_IMG2DFastMarchingUsage.png,"2D Fast Marching Tool",3.01} Provides a fast marching based 2D interaction segmentation tool. You start with setting seedpoints in an image slice. Via several sliders you can adapt parameters and see the fast marching result instantly. \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. \imageMacro{QmitkSegmentation_3DInterpolationWrongRight.png,"3D Interpolation HowTo",16.00} 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 current state of the 3D interpolation can be saved accross application restart. Therefor just click on save project during the interpolation is active. After restarting the application and load your project you can click on "Reinit Interpolation" within the 3D interpolation GUI area.
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_segmentationUserManual3DSegmentationTools 3D Segmenation tools The 3D tools operate on the hole image and require usually a small amount of interaction like placing seed-points or specifying certain parameters. All 3D tools provide an immediate segmentation feedback, which is displayed as a transparent green overlay. For accepting a preview you have to press the "Comfirm" button of the selected tool. The following 3D tools are at your disposal: \subsection org_mitk_gui_qt_segmentationUserManual3DThresholdTool 3D Threshold tool The Thresholding tool simply applies a 3D threshold to the patient image. All pixels with values equal or above the selected threshold are labeled. You can change the threshold by either moving the slider of setting a certain value in the spinbox. \imageMacro{QmitkSegmentation_3DThresholdTool.png,"3D Threshold tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DULTool 3D Upper/Lower Threshold tool The Upper/Lower Thresholding tool works similar to the simple 3D threshold tool but allows you to define an upper and lower threshold. All pixels with values within this threshold intervall will be labeled \imageMacro{QmitkSegmentation_3DULThresholdTool.png,"3D Upper/Lower Threshold tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DOtsuTool 3D Otsu tool The 3D Otsu tool provides a more sophisticated thresholding algorithm. It allows you to define a number of regions. Based on the image histogram the pixels will then divided into different regions. There more regions you define the longer will the calculation take. \imageMacro{QmitkSegmentation_3DOtsuTool.png,"3D Otsu tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DFMTool 3D Fast Marching tool The 3D Fast Marching tools works similar to the 2D pendant but on the hole image. Depending on you image's size the calculation will take some time. You can interactive set the parameters of the algorithm via the tool GUI. \imageMacro{QmitkSegmentation_3DFMTool.png,"3D Fast Marching tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManual3DRGTool 3D Region Growing tool The 3D Region Growing tool works similar to the 2D pendant. At the beginning you have to place a seedpoint and define a threshold intervall. If you press "Run segmentation" a preview is calculated, if the "3D preview" box is checked you will also see the result in 3D. By moving the "Adapt region growing slider" you can interactively adapt the result to you image. \imageMacro{QmitkSegmentation_3DRGTool.png,"3D Region Growing tool",10.00} +\subsection org_mitk_gui_qt_segmentationUserManual3DWatershedTool 3D Watershed tool This tool provides a watershed based segmentation algorithm. \imageMacro{QmitkSegmentation_3DWatershedTool.png,"3D Watershed tool",10.00} \subsection org_mitk_gui_qt_segmentationUserManualPickingTool Picking tool The Picking tool allows you to select islands within your segmentation. This is especially usefull if e.g. a thresholding delivered your several areas within your image but you are just interested in one special region. \imageMacro{QmitkSegmentation_PickingTool.png,"Picking tool",10.00} \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 \imageMacro{QmitkSegmentation_IMGDataManagerContextMenu.png,"Context menu items for segmentations.",10.58}
  • 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.
  • 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 QmitkSegmentation_UserManualSurfaceMasking 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: \imageMacro{QmitkSegmentation_FromSurfaceBefore.png,"Load an image and a surface.",16.00} 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) \imageMacro{QmitkSegmentation_FromSurfaceAfter.png,"Create segmentation from surface",16.00} 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/QmitkSegmentationUtilities.dox b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox index b60a39db80..65cf6d1b77 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentationUtilities.dox @@ -1,62 +1,62 @@ /** \page org_mitk_views_segmentationutilities The Segmentation Utilities View -\imageMacro{SegmentationUtilities.png,"Icon of the Segmentation Utilities View",5.00} +\imageMacro{segmentation_utilities.svg,"Icon of the Segmentation Utilities View",5.00} \imageMacro{QmitkSegmentationUtilities_Overview.png,"The Segmentation Utilities view",16.00} \tableofcontents \section org_mitk_views_segmentationUtilitiesManualOverview Overview The Segmentation Utilities View allows you to postprocess existing segmentations \section org_mitk_views_segmentationUtilitiesImageSelection Image Selection Usually the data selection in the Segmentation Utilities View is done via drop down box which let you just select the appropriate data. \section org_mitk_views_segmentationUtilitiesBooleanOperations Boolean Operations Boolean operations allow you to create the
  • Union: Combines two existing segmentations
  • Intersection: Keeps just the overlapping areas of two existing segmentations
  • Difference: Subtracts one segmentation from the other
of two segmentations. The selected segmentations must have the same geometry (size, spacing, ...) \imageMacro{QmitkSegmentationUtilities_IMGBooleanOperations.png,"Boolean operations of the SegmentationUtlitiesView",6.00} \section org_mitk_views_segmentationUtilitiesImageMasking Image masking You can mask your grey value image with either an existing segmentation or a surface. The result will be an image containing only the pixels that are cover by the respective mask. \imageMacro{QmitkSegmentationUtilities_IMGImageMasking.png,"Image masking widget of the Segmentation Utilities View",6.00} \section org_mitk_views_segmentationUtilitiesMorphologicalOperators Morphological Operators The morphological operators are applied to a single segmentation image. Based on a given structuring element the underlying segmentation will be modfied. MITK provides a ball and a cross as structuring elements. The follow operators are at your disposal:
  • Dilation: Each labeled pixel within the segmentation will be dilated based on the selected structuring element
  • Erosion: Each labeled pixel within the segmentation will be eroded based on the selected structuring element
  • Opening: A dilation followed by an erosion, used for smoothing edges or eliminating small objects
  • Closing An erosion followed by an dilation, used for filling small holes
  • Fill Holes Fills bigger holes within a segmentation
\imageMacro{QmitkSegmentationUtilities_IMGMorphologicalOperators.png,"Morphological operators widget of the Segmentation Utilities View",6.00} \section org_mitk_views_segmentationUtilitiesSurfaceToImage Surface to binary image This widget lets you fill you meshes into an empty binary image. It is required that a reference grey value image is present. The created binary image will have the same geometrical properties like the reference image \imageMacro{QmitkSegmentationUtilities_IMGSurfaceToImage.png,"Surface to image widget of the Segmentation Utilities View",6.00} **/ diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg new file mode 100644 index 0000000000..54fb2e3178 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation.svg @@ -0,0 +1,2051 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg new file mode 100644 index 0000000000..5689bc3f3c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/segmentation_utilities.svg @@ -0,0 +1,3481 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox index 45c93fb7c7..49360ff183 100644 --- a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox +++ b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/QmitkVolumeVisualization.dox @@ -1,154 +1,154 @@ /** \page org_mitk_views_volumevisualization The Volume Visualization Plugin -\imageMacro{QmitkVolumeVisualization_Icon.png,"Icon of the Volume Visualization Plugin",2.00} +\imageMacro{volume_visualization.svg,"Icon of the Volume Visualization Plugin",2.00} \tableofcontents \section QVV_Overview Overview The Volume Visualization Plugin is a basic tool for visualizing three dimensional medical images. MITK provides generic transfer function presets for medical CT data. These functions, that map the gray-value to color and opacity, can be interactively edited. Additionally, there are controls to quickly generate common used transfer function shapes like the threshold and bell curve to help identify a range of grey-values. \imageMacro{QmitkVolumeVisualization_Overview.png,"",16.00} \section QVV_EnableVRPage Enable Volume Rendering \subsection QVV_LoadingImage Loading an image into the application Load an image into the application by
  • dragging a file into the application window.
  • selecting file / load from the menu.
Volume Visualization imposes following restrictions on images:
  • It has to be a 3D-Image Scalar image, that means a normal CT or MRT.
  • 3D+T are supported for rendering, but the histograms are not computed.
  • Also be aware that volume visualization requires a huge amount of memory. Very large images may not work, unless you use the 64bit version.
\subsection QVV_EnableVR Enable Volumerendering \imageMacro{QmitkVolumeVisualization_Checkboxen.png,"",8.21} Select an image in datamanager and click on the checkbox left of "Volumerendering". Please be patient, while the image is prepared for rendering, which can take up to a half minute. \subsection QVV_LODGPU Dropdown menus for the rendering and blend modes Two dropdown menus allow selection of rendering mode (Default, RayCast, GPU) and the blend mode (Composite, Max, Min, Avg, Add). Any Volume Rendering mode requires a lot of computing resources including processor, memory and often also graphics card. The Default selection usually finds the best rendering mode for the available hardware. Alternatively, it is possible to manually specify the selections RayCast and GPU. The RayCast selection is based on CPU computation and therefore typically slow, but allows to render without hardware acceleration. The GPU selection uses computing resources on the graphics card to accelerate volume rendering. It requires a powerful graphics card and OpenGL hardware support for shaders, but achieves much higher frame rates than software-rendering. Blend modes define how the volume voxels intersected by the rendering rays are pooled. The composite mode specifies standard volume rendering, for which each voxel contributes equally with opacity and color. Other blend modes simply visualize the voxel of maximum / minimum intensity and average / add the intentities along the rendering ray. \section QVV_PresetPage Applying premade presets \subsection QVV_Preset Internal presets There are some internal presets given, that can be used with normal CT data (given in Houndsfield units). A large set of medical data has been tested with that presets, but it may not suit on some special cases. Click on the "Preset" tab for using internal or custom presets. \imageMacro{QmitkVolumeVisualization_InternalPresets.png,"",8.30}
  • "CT Generic" is the default transferfunction that is first applied.
  • "CT Black&White" does not use any colors, as it may be distracting on some data.
  • "CT Cardiac" tries to increase detail on CTs from the heart.
  • "CT Bone" emphasizes bones and shows other areas more transparent.
  • "CT Bone (Gradient)" is like "CT Bone", but shows from other organs only the surface by using the gradient.
  • "MR Generic" is the default transferfunction that we use on MRT data (which is not normalized like CT data).
  • "CT Thorax small" tries to increase detail.
  • "CT Thorax large" tries to increase detail.
\subsection QVV_CustomPreset Saving and loading custom presets After creating or editing a transferfunction (see \ref QVV_Editing or \ref QVV_ThresholdBell), the custom transferfunction can be stored and later retrieved on the filesystem. Click "Save" (respectively "Load") button to save (load) the threshold-, color- and gradient function combined in a single .xml file. \section QVV_ThresholdBell Interactively create transferfunctions Beside the possibility to directly edit the transferfunctions (\ref QVV_Editing), a one-click generation of two commonly known shapes is given. Both generators have two parameters, that can be modified by first clicking on the cross and then moving the mouse up/down and left/right. The first parameter "center" (controlled by horizontal movement of the mouse) specifies the gravalue where the center of the shape will be located. The second parameter "width" (controlled by vertical movement of the mouse) specifies the width (or steepness) of the shape. \subsection Threshold Click on the "Threshold" tab to active the threshold function generator. \imageMacro{QmitkVolumeVisualization_Threshold.png,"",8.21} A threshold shape begins with zero and raises to one across the "center" parameter. Lower widths results in steeper threshold functions. \subsection Bell Click on the "Bell" tab to active the threshold function generator. \imageMacro{QmitkVolumeVisualization_Bell.png,"",8.23} A threshold shape begins with zero and raises to one at the "center" parameter and the lowers agains to zero. The "width" parameter correspondens to the width of the bell. \section QVV_Editing Customize transferfunctions in detail \subsection QVV_Navigate Choosing grayvalue interval to edit \imageMacro{QmitkVolumeVisualization_Slider.png,"",8.23} To navigate across the grayvalue range or to zoom in some ranges use the "range"-slider. All three function editors have in common following:
  • By left-clicking a new point is added.
  • By right-clicking a point is deleted.
  • By left-clicking and holding, an exisiting point can be dragged.
  • By pressing arrow keys, the currently selected point is moved.
  • By pressing the "DELETE" key, the currently selected point is deleted.
  • Between points the transferfunctions are linear interpolated.
There are three transferfunctions to customize: \subsection QVV_GO Grayvalue -> Opacity \imageMacro{QmitkVolumeVisualization_Opacity.png,"grayvalues will be mapped to opacity.",8.04} An opacity of 0 means total transparent, an opacity of 1 means total opaque. \subsection QVV_GC Grayvalue -> Color \imageMacro{QmitkVolumeVisualization_Color.png,"grayvalues will be mapped to color.",8.81} The color transferfunction editor also allows by double-clicking a point to change its color. \subsection QVV_GGO Grayvalue and Gradient -> Opacity \imageMacro{QmitkVolumeVisualization_Gradient.png,"",8.85} Here the influence of the gradient is controllable at specific grayvalues. */ diff --git a/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg new file mode 100644 index 0000000000..26682d271e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.volumevisualization/documentation/UserManual/volume_visualization.svg @@ -0,0 +1,65 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Wrapping/Common/mitk_swig_classes.i b/Wrapping/Common/mitk_swig_classes.i index 8a5e384924..52a12a12f9 100644 --- a/Wrapping/Common/mitk_swig_classes.i +++ b/Wrapping/Common/mitk_swig_classes.i @@ -1,81 +1,144 @@ // // Defining some Macros that make problems with SWIG as the // corresponding definitions are not included by default. // Luckely, these includes are not necessary for SWIG. // #define ITK_NOEXCEPT #define ITKCommon_EXPORT #define ITK_OVERRIDE #define MITKCORE_EXPORT #define MITKCLCORE_EXPORT #define MITKCLUTILITIES_EXPORT #define ITKCommon_EXPORT +#define MITKMATCHPOINTREGISTRATION_EXPORT +#define MAPDeployment_EXPORT +#define MAPAlgorithms_EXPORT +#define MITKSEGMENTATION_EXPORT +#define MITKMULTILABEL_EXPORT #define ITKCommon_EXPORT #define ITK_FORWARD_EXPORT #define ITK_OVERRIDE #define ITK_NOEXCEPT %include %include %include %include %include %include #define DEPRECATED(func) func #undef ITK_DISALLOW_COPY_AND_ASSIGN #define ITK_DISALLOW_COPY_AND_ASSIGN(TypeName) %pythoncode %{ convertion_list = {} %} SWIG_ADD_MITK_CLASS(Object, itkObject.h, itk) SWIG_ADD_MITK_CLASS(DataObject, itkDataObject.h, itk) SWIG_ADD_MITK_CLASS(TimeGeometry, mitkTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ArbitraryTimeGeometry, mitkArbitraryTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(ProportionalTimeGeometry, mitkProportionalTimeGeometry.h, mitk) SWIG_ADD_MITK_CLASS(BaseGeometry, mitkBaseGeometry.h, mitk) SWIG_ADD_MITK_CLASS(Geometry3D, mitkGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(SlicedGeometry3D, mitkSlicedGeometry3D.h, mitk) SWIG_ADD_MITK_CLASS(PlaneGeometry , mitkPlaneGeometry.h, mitk) SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BoundingBox, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(TimeBounds, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(FixedArrayType, mitkBaseGeometry.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4D, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point2I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point3I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Point4I, mitkPoint.h, mitk) SWIG_ADD_NONOBJECT_CLASS(VnlVector, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector2D, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector3D, mitkVector.h, mitk) SWIG_ADD_NONOBJECT_CLASS(Vector4D, mitkVector.h, mitk) SWIG_ADD_MITK_CLASS(BaseData, mitkBaseData.h, mitk) SWIG_ADD_MITK_CLASS(SlicedData, mitkSlicedData.h, mitk) SWIG_ADD_MITK_CLASS(Image, mitkImage.h, mitk) +SWIG_ADD_MITK_CLASS(LabelSetImage, mitkLabelSetImage.h, mitk) SWIG_ADD_MITK_CLASS(PointSet, mitkPointSet.h, mitk) +%{ +using mitk::Message; +%} +// +// Phenotyping Related Classes +// SWIG_ADD_MITK_CLASS(AbstractGlobalImageFeature, mitkAbstractGlobalImageFeature.h, mitk) SWIG_ADD_MITK_CLASS(GIFImageDescriptionFeatures, mitkGIFImageDescriptionFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderStatistics, mitkGIFFirstOrderStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFFirstOrderHistogramStatistics, mitkGIFFirstOrderHistogramStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricStatistics, mitkGIFVolumetricStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFVolumetricDensityStatistics, mitkGIFVolumetricDensityStatistics.h, mitk) SWIG_ADD_MITK_CLASS(GIFCooccurenceMatrix2, mitkGIFCooccurenceMatrix2.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbouringGreyLevelDependenceFeature, mitkGIFNeighbouringGreyLevelDependenceFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelRunLength, mitkGIFGreyLevelRunLength.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelSizeZone, mitkGIFGreyLevelSizeZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFGreyLevelDistanceZone, mitkGIFGreyLevelDistanceZone.h, mitk) SWIG_ADD_MITK_CLASS(GIFLocalIntensity, mitkGIFLocalIntensity.h, mitk) SWIG_ADD_MITK_CLASS(GIFIntensityVolumeHistogramFeatures, mitkGIFIntensityVolumeHistogramFeatures.h, mitk) SWIG_ADD_MITK_CLASS(GIFNeighbourhoodGreyToneDifferenceFeatures, mitkGIFNeighbourhoodGreyToneDifferenceFeatures.h, mitk) -SWIG_ADD_MITK_CLASS(GIFCurvatureStatistic, mitkGIFCurvatureStatistic.h, mitk) \ No newline at end of file +SWIG_ADD_MITK_CLASS(GIFCurvatureStatistic, mitkGIFCurvatureStatistic.h, mitk) + +// +// Conversion and Segmentation based Classes +// +SWIG_ADD_MITK_CLASS(ContourModelSetToImageFilter, mitkContourModelSetToImageFilter.h, mitk) +SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(BooleanOperation, mitkBooleanOperation.h, mitk) +SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(MorphologicalOperations, mitkMorphologicalOperations.h, mitk) +%{ + #include + typedef itk::DataObject::DataObjectIdentifierType DataObjectIdentifierType; + typedef itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; +%} + +// +// MatchPoint Related Classes +// +MITKSWIG_ADD_CLASS(MITKAlgorithmHelper, mitkAlgorithmHelper.h, mitk) +MITKSWIG_ADD_CLASS(RegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) +MITKSWIG_ADD_CLASS(MITKRegistrationType, mitkImageMappingHelper.h, mitk::ImageMappingHelper) + + +%ignore map::deployment::DLLHandle::New(const LibraryHandleType& libraryHandle, const map::algorithm::UID* pUID, const core::String& libraryFile, const core::String& profileStr); +%ignore map::deployment::DLLHandle::New(const map::algorithm::UID* pUID,const core::String& libraryFilePath,const core::String& profileStr); +%ignore map::deployment::DLLInfo::New(const map::algorithm::UID* pUID,const core::String& libraryFilePath,const core::String& profileStr); +%ignore map::deployment::DLLHandle::New; + +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLDirectoryBrowser, mapDeploymentDLLDirectoryBrowser.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLInfo, mapDeploymentDLLInfo.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, ::map::deployment) +SWIG_ADD_MITK_CLASS_VECTORFREE(UID, mapUID.h, ::map::algorithm) +%{ + namespace algorithm + { + typedef map::algorithm::UID UID; + } + namespace core + { + typedef map::core::String String; + } +%} + +MITKSWIG_ADD_HEADERFILE(mapDeploymentDLLAccess.h) +SWIG_ADD_MITK_CLASS_VECTORFREE(DLLHandle, mapDeploymentDLLHandle.h, ::map::deployment) + +// SWIG_ADD_MITK_CLASS(FastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm, mitkFastSymmetricForcesDemonsMultiResDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(LevelSetMotionMultiResDefaultRegistrationAlgorithm, mitkLevelSetMotionMultiResDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalAffineDefaultRegistrationAlgorithm, mitkMultiModalAffineDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalRigidDefaultRegistrationAlgorithm, mitkMultiModalRigidDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(MultiModalTransDefaultRegistrationAlgorithm, mitkMultiModalTransDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(RigidClosedFormPointsDefaultRegistrationAlgorithm, mitkRigidClosedFormPointsDefaultRegistrationAlgorithm.h, mitk) +// SWIG_ADD_MITK_CLASS(RigidICPDefaultRegistrationAlgorithm, mitkRigidICPDefaultRegistrationAlgorithm.h, mitk) \ No newline at end of file diff --git a/Wrapping/Common/mitk_swig_macros.i b/Wrapping/Common/mitk_swig_macros.i index 5f7c949163..51288dd2cb 100644 --- a/Wrapping/Common/mitk_swig_macros.i +++ b/Wrapping/Common/mitk_swig_macros.i @@ -1,196 +1,228 @@ // // This file contains macros for swig. // + + // -// SWIG_ADD_MITK_CLASS is a helper macro in order to do -// all important stuff before an mitk::Class is included. -// Requires the name of the class as it is in c++ as classname -// and the include file, in which the class is defined. -// It is assumed that the class is somehow inherited from -// mitk::BaseData, and supports smartpointers. +// MITKSWIG_ADD_HEADERFILE includes a header-file into SWIG // -%define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) +%define MITKSWIG_ADD_HEADERFILE( classinclude ) // Include the include file in the generated cpp file %{ #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; %} // Include the given header, where the class definition is found %include < ## classinclude ## > - using nspace ##:: ## classname ; - - - // Declaring that this class is a smart-pointer class, in order to handle - // online upcasting where necessary (for example python) - %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } +%enddef +// +// MITKSWIG_ADD_CLASS is a helper macro in order to do +// all important stuff in order to wrap an existing +// class +// +%define MITKSWIG_ADD_CLASS(classname, classinclude, nspace) + MITKSWIG_ADD_HEADERFILE( classinclude ) + // Using class name in order to remove ambigiouties + %{ + typedef nspace ## :: ## classname classname ## ; + using nspace ## :: ## classname ; + %} + using nspace ##:: ## classname ; // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; +%enddef - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; - // Defining the Smartpointer, allows easy access in target language - %template(classname ## Pointer) itk::SmartPointer; +// +// MITKSWIG_AUTOMATED_CASTING is a helper macro in order to +// provide a convinience interface for up/downcasting of +// classes +// +%define MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) // Define a conversion method to convert from and to types %template(ConvertTo ## classname) ConvertTo< nspace ##:: ## classname ## >; - // This extend is necessary to have the automatic cast methods available %extend itk::SmartPointer< nspace ## :: ## classname ## ::Self> { %pythoncode %{ def _GetListOfValidItems(self): - return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] + return [str(k).replace("class itk::","") for k in self.GetClassHierarchy() if str(k).replace("class itk::","") in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %extend std::vector< nspace ## :: ## classname *>::value_type { %pythoncode %{ def _GetListOfValidItems(self): - return [str(k) for k in self.GetClassHierarchy() if k in convertion_list.keys() ] + return [str(k).replace("class itk::","") for k in self.GetClassHierarchy() if str(k).replace("class itk::","") in convertion_list.keys() ] %} %pythoncode %{ def __getattr__(self, item): if type(item)==str: if (len(item) > 9) and ('ConvertTo' in item): searchString=item[9:] if searchString in self._GetListOfValidItems(): def func_t(): return convertion_list[searchString](self) return func_t %} %pythoncode %{ def __dir__(self): return super().__dir__() + ['ConvertTo'+k for k in self._GetListOfValidItems()] %} } %pythoncode %{ convertion_list['classname'] = ConvertTo ## classname %} %enddef +// +// MITKSWIG_SMARTPOINTERVECTOR : Wrapper for Vectors of Smartpointer-Classes +// +%define MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) + // Initianziation of std. vectors containing pointers to these classes. This allows to use + // vectors of these types as target language arrays. + %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname ## ::Pointer >; + %template(Vector ## classname) std::vector< nspace ## :: ## classname ## ::Self *>; +%enddef // -// SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do +// MITKSWIG_POINTERVECTOR : Wrapper for Vectors of Classes +// +%define MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) + // Initianziation of std. vectors containing pointers to these classes. This allows to use + // vectors of these types as target language arrays. + %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; + %template(Vector ## classname) std::vector< nspace ## :: ## classname >; +%enddef + +// +// MITKSWIG_MITKSMARTPOINTER_INITIALIZATION : Wrapper for Vectors of Smartpointer-Classes +// +%define MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) + + // Declaring that this class is a smart-pointer class, in order to handle + // online upcasting where necessary (for example python) + %feature("smartptr", noblock=1) nspace ##:: ## classname { itk::SmartPointer } +%enddef + +// +// MITKSWIG_MITKSMARTPOINTER_TEMPLATE : Wrapper for Vectors of Smartpointer-Classes +// +%define MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) + // Defining the Smartpointer, allows easy access in target language + %template(classname ## Pointer) itk::SmartPointer; + +%enddef + + +// +// SWIG_ADD_MITK_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // -%define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} +%define SWIG_ADD_MITK_CLASS_VECTORFREE(classname, classinclude, nspace) + MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; - - // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG - // ignores namespaces. This can lead to some problems with templates. - typedef nspace ## :: ## classname classname ## ; + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) class nspace ## :: ## classname ## ; + class nspace ## :: ## classname ## ::Pointer; - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname >; + MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) + MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) %enddef +// +// SWIG_ADD_MITK_CLASS is a helper macro in order to do +// all important stuff before an mitk::Class is included. +// Requires the name of the class as it is in c++ as classname +// and the include file, in which the class is defined. +// It is assumed that the class is somehow inherited from +// mitk::BaseData, and supports smartpointers. +// +%define SWIG_ADD_MITK_CLASS(classname, classinclude, nspace) + MITKSWIG_MITKSMARTPOINTER_INITIALIZATION(classname, classinclude, nspace) + + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) + + + class nspace ## :: ## classname ## ; + //class nspace ## :: ## classname ## ::Pointer; + + // It is important to first define the Vectors and + // then define the Smartpointer. Otherwise a SWIG-bug ... + MITKSWIG_SMARTPOINTERVECTOR(classname, classinclude, nspace) + + MITKSWIG_MITKSMARTPOINTER_TEMPLATE(classname, classinclude, nspace) + + MITKSWIG_AUTOMATED_CASTING(classname, classinclude, nspace) +%enddef // -// SWIG_ADD_NONOBJECT_TEMPLATECLASS is a helper macro in order to do +// SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // -%define SWIG_ADD_NONOBJECT_TEMPLATECLASS(classname, classinclude, nspace, tmplstring) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} - - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; +%define SWIG_ADD_NONOBJECT_CLASS(classname, classinclude, nspace) + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; - %template( classname ) nspace ## :: ## tmplstring ## ; - - // Initianziation of std. vectors containing pointers to these classes. This allows to use - // vectors of these types as target language arrays. - %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; - %template(Vector ## classname) std::vector< nspace ## :: ## classname >; + class nspace ## :: ## classname ## ; + MITKSWIG_POINTERVECTOR(classname, classinclude, nspace) %enddef - - // // SWIG_ADD_NONOBJECT_CLASS is a helper macro in order to do // all important stuff before an mitk::Class is included. // Requires the name of the class as it is in c++ as classname // and the include file, in which the class is defined. // It is assumed that the class is somehow inherited from // mitk::BaseData, and supports smartpointers. // %define SWIG_ADD_NONOBJECT_NOVECTOR_CLASS(classname, classinclude, nspace) - // Include the include file in the generated cpp file - %{ - #include < ## classinclude ## > - typedef nspace ## :: ## classname classname ## ; - using nspace ## :: ## classname ; - %} - // Include the given header, where the class definition is found - %include < ## classinclude ## > - using nspace ##:: ## classname ; + MITKSWIG_ADD_CLASS( classname, classinclude, nspace ) // Typedef is necessary to overcome ambigiouties resulting in the fact that SWIG // ignores namespaces. This can lead to some problems with templates. typedef nspace ## :: ## classname classname ## ; // Initianziation of std. vectors containing pointers to these classes. This allows to use // vectors of these types as target language arrays. %template(Vector ## classname ## Pointer) std::vector< nspace ## :: ## classname * >; %enddef diff --git a/Wrapping/Python/CMakeLists.txt b/Wrapping/Python/CMakeLists.txt index ac708a0b76..cb9327dc76 100644 --- a/Wrapping/Python/CMakeLists.txt +++ b/Wrapping/Python/CMakeLists.txt @@ -1,77 +1,77 @@ # Version 2.8.1 is the minium requirement for this script. # this is lower than the general minimum requirement. #cmake_minimum_required ( VERSION 2.8.1 FATAL_ERROR ) include(mitkTargetLinkLibrariesWithDynamicLookup) project( MITK_Python ) set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERNAL "" FORCE) mitk_check_dynamic_lookup(MODULE SHARED MITK_UNDEFINED_SYMBOLS_ALLOWED ) # # Find the necessary libraries etc.. # if ( MITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY "REQUIRED" ) endif() find_package ( PythonInterp REQUIRED ) find_package ( PythonLibs ${_QUIET_LIBRARY} ) include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} ) # # Options # option ( MITK_PYTHON_THREADS "Enable threaded python usage by unlocking the GIL." ON ) mark_as_advanced( MITK_PYTHON_THREADS ) option ( MITK_PYTHON_EGG "Add building of python eggs to the dist target." OFF ) mark_as_advanced( MITK_PYTHON_EGG ) option ( MITK_PYTHON_WHEEL "Add building of python wheels to the dist target." ON ) mark_as_advanced( MITK_PYTHON_WHEEL ) # Prepare the SWIG-File, i.e. especially add necessary include folders -mitkSwigPrepareFiles(pyMITK MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") +mitkSwigPrepareFiles(pyMITK MITK.i "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration;MitkSegmentation;MitkMultilabel;MitkDICOMReader;MitkDICOMReaderServices;MitkDicomRT") # Add additional SWIG Parameters # These parameters depend on the target language set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_GLOBAL_FLAGS} -features autodoc=1 -keyword ) if( MITK_PYTHON_THREADS ) set(CMAKE_SWIG_FLAGS ${CMAKE_SWIG_FLAGS} -threads) endif() set(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}) # Create the actual SWIG project swig_add_module(pyMITK python MITK.i ) -mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon") +mitkSwigAddLibraryDependencies(pyMITK "MitkCore;MitkCLCore;MitkCLUtilities;ITKCommon;MitkMatchPointRegistration;MitkSegmentation;MitkMultilabel;MitkDICOMReader;MitkDICOMReaderServices;MitkDicomRT") mitk_target_link_libraries_with_dynamic_lookup(${SWIG_MODULE_pyMITK_REAL_NAME} ${PYTHON_LIBRARIES}) if(DEFINED SKBUILD) message(WARNING "SKBuild exists") # Currently this installation install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pyMITK.py ${CMAKE_CURRENT_SOURCE_DIR}/Packaging/__init__.py # ${MITK_DOC_FILES} DESTINATION pyMITK COMPONENT Runtime ) install(TARGETS ${SWIG_MODULE_pyMITK_REAL_NAME} RUNTIME DESTINATION pyMITK LIBRARY DESTINATION pyMITK COMPONENT Runtime ) else() message(WARNING "SKBuild missing") include(LegacyPackaging.cmake) endif() diff --git a/Wrapping/Python/MITK.i b/Wrapping/Python/MITK.i index cbdd3c857c..f7a188f7ed 100644 --- a/Wrapping/Python/MITK.i +++ b/Wrapping/Python/MITK.i @@ -1,171 +1,167 @@ %module pyMITK %include %{ #include "mitkNumpyArrayConversion.cxx" %} // Numpy array conversion support %native(_GetMemoryViewFromImage) PyObject *mitk_GetMemoryViewFromImage( PyObject *self, PyObject *args ); %native(_SetImageFromArray) PyObject *mitk_SetImageFromArray( PyObject *(self), PyObject *args ); %pythoncode %{ HAVE_NUMPY = True try: import numpy except ImportError: HAVE_NUMPY = False def _get_numpy_dtype( mitkImage ): """Given a MITK image, returns the numpy.dtype which describes the data""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # this is a mapping from MITK's pixel id to numpy's dtype _mitk_np = {ComponentTypeUInt8:numpy.uint8, ComponentTypeUInt16:numpy.uint16, ComponentTypeUInt32:numpy.uint32, ComponentTypeInt8:numpy.int8, ComponentTypeInt16:numpy.int16, ComponentTypeInt32:numpy.int32, ComponentTypeFloat:numpy.float32, ComponentTypeDouble:numpy.float64, } return _mitk_np[ mitkImage.GetPixelType().GetComponentType() ] def _get_mitk_pixelid(numpy_array_type): """Returns a MITK PixelID given a numpy array.""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # This is a Mapping from numpy array types to sitks pixel types. _np_mitk = {numpy.character:ComponentTypeUInt8, numpy.uint8:ComponentTypeUInt8, numpy.uint16:ComponentTypeUInt16, numpy.uint32:ComponentTypeUInt32, numpy.int8:ComponentTypeInt8, numpy.int16:ComponentTypeInt16, numpy.int32:ComponentTypeInt32, numpy.float32:ComponentTypeFloat, numpy.float64:ComponentTypeDouble, } try: return _np_mitk[numpy_array_type.dtype] except KeyError: for key in _np_mitk: if numpy.issubdtype(numpy_array_type.dtype, key): return _np_mitk[key] raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) def _get_sitk_vector_pixelid(numpy_array_type): """Returns a MITK vecotr PixelID given a numpy array.""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') # This is a Mapping from numpy array types to sitks pixel types. _np_sitk = {numpy.character:sitkVectorUInt8, numpy.uint8:sitkVectorUInt8, numpy.uint16:sitkVectorUInt16, numpy.uint32:sitkVectorUInt32, numpy.uint64:sitkVectorUInt64, numpy.int8:sitkVectorInt8, numpy.int16:sitkVectorInt16, numpy.int32:sitkVectorInt32, numpy.int64:sitkVectorInt64, numpy.float32:sitkVectorFloat32, numpy.float64:sitkVectorFloat64, } try: return _np_sitk[numpy_array_type.dtype] except KeyError: for key in _np_sitk: if numpy.issubdtype(numpy_array_type.dtype, key): return _np_sitk[key] raise TypeError('dtype: {0} is not supported.'.format(numpy_array_type.dtype)) # MITK <-> Numpy Array conversion support. #http://www.nickdarnell.com/swig-casting-revisited/ def GetArrayViewFromImage(image): """Get a NumPy ndarray view of a MITK Image. Returns a Numpy ndarray object as a "view" of the MITK's Image buffer. This reduces pixel buffer copies, but requires that the MITK image object is kept around while the buffer is being used. """ if not HAVE_NUMPY: raise ImportError('NumPy not available.') dtype = _get_numpy_dtype( image ) shape = GetImageSize(image); if image.GetPixelType().GetNumberOfComponents() > 1: shape = ( image.GetPixelType().GetNumberOfComponents(), ) + shape imageMemoryView = _pyMITK._GetMemoryViewFromImage(image) arrayView = numpy.asarray(imageMemoryView).view(dtype = dtype) arrayView.shape = shape[::-1] return arrayView def GetArrayFromImage(image): """Get a NumPy ndarray from a MITK Image. This is a deep copy of the image buffer and is completely safe and without potential side effects. """ # TODO: If the image is already not unique then a second copy may be made before the numpy copy is done. arrayView = GetArrayViewFromImage(image) # perform deep copy of the image buffer return numpy.array(arrayView, copy=True) def GetImageFromArray( arr, isVector=False): """Get a MITK Image from a numpy array. If isVector is True, then a 3D array will be treated as a 2D vector image, otherwise it will be treated as a 3D image""" if not HAVE_NUMPY: raise ImportError('Numpy not available.') z = numpy.asarray( arr ) assert z.ndim in ( 2, 3, 4 ), \ "Only arrays of 2, 3 or 4 dimensions are supported." id = _get_mitk_pixelid( z ) #img = Image_New() if ( z.ndim == 3 and isVector ) or (z.ndim == 4): pixelType=MakePixelTypeFromTypeID(id, z.shape[-1]) newShape=VectorUInt32(z.shape[-2::-1]) img = MakeImage(pixelType, newShape) #img.Initialize(pixelType, z.ndim - 1, z.shape[-2::-1]) elif z.ndim in ( 2, 3 ): pixelType=MakePixelTypeFromTypeID(id, 1) newShape=VectorUInt32(z.shape[::-1]) img = MakeImage(pixelType, newShape) #img.Initialize(pixelType, z.ndim, z.shape[::-1]) _pyMITK._SetImageFromArray( z.tostring(), img ) return img -#convertion_list = {'Image':ConvertToImage, -# 'SlicedData':ConvertToSlicedData, -# 'BaseData':ConvertToBaseData} - %}