diff --git a/CMake/BuildConfigurations/mitkNavigationModules.cmake b/CMake/BuildConfigurations/mitkNavigationModules.cmake index 456c1c877c..c315c718e0 100644 --- a/CMake/BuildConfigurations/mitkNavigationModules.cmake +++ b/CMake/BuildConfigurations/mitkNavigationModules.cmake @@ -1,38 +1,35 @@ message(STATUS "Configuring MITK Navigation Modules Build") set(MITK_CONFIG_PACKAGES ACVD Qt5 BLUEBERRY ) # Enable open cv and open igt link, which is a necessary configuration set(MITK_USE_OpenCV ON CACHE BOOL "MITK Use OpenCV Library" FORCE) set(MITK_USE_OpenIGTLink ON CACHE BOOL "MITK Use OpenIGTLink Library" FORCE) # Enable default plugins and the navigation modules set(MITK_CONFIG_PLUGINS org.mitk.gui.qt.datamanager org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.dicom org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.properties org.mitk.gui.qt.segmentation org.mitk.gui.qt.volumevisualization org.mitk.planarfigure org.mitk.gui.qt.moviemaker org.mitk.gui.qt.pointsetinteraction org.mitk.gui.qt.registration org.mitk.gui.qt.remeshing org.mitk.gui.qt.viewnavigator org.mitk.gui.qt.imagecropper - org.mitk.gui.qt.igtexamples org.mitk.gui.qt.igttracking - org.mitk.gui.qt.igtlplugin org.mitk.gui.qt.openigtlink org.mitk.gui.qt.ultrasound - org.mitk.gui.qt.toftutorial org.mitk.gui.qt.tofutil ) diff --git a/CMake/MITKDashboardSetup.cmake b/CMake/MITKDashboardSetup.cmake index 4bf2d289cf..652289861b 100644 --- a/CMake/MITKDashboardSetup.cmake +++ b/CMake/MITKDashboardSetup.cmake @@ -1,160 +1,161 @@ # This file is intended to be included at the end of a custom MITKDashboardScript.TEMPLATE.cmake file list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") # # Automatically determined properties # set(MY_OPERATING_SYSTEM ) if(UNIX) # Download a utility script - if(IS_PHABRICATOR_URL) - set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw") - else() + # See T24757. + # if(IS_PHABRICATOR_URL) + # set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw") + # else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/mitkDetectOS.sh") - endif() + # endif() set(dest "${CTEST_SCRIPT_DIRECTORY}/mitkDetectOS.sh") downloadFile("${url}" "${dest}") execute_process(COMMAND sh "${dest}" RESULT_VARIABLE _result OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT _result) set(MY_OPERATING_SYSTEM "${_out}") endif() endif() if(NOT MY_OPERATING_SYSTEM) set(MY_OPERATING_SYSTEM "${CMAKE_HOST_SYSTEM}") # Windows 7, Linux-2.6.32, Darwin... endif() site_name(CTEST_SITE) if(NOT DEFINED MITK_USE_Qt5) set(MITK_USE_Qt5 1) endif() if(MITK_USE_Qt5) if(NOT QT_QMAKE_EXECUTABLE) find_program(QT_QMAKE_EXECUTABLE NAMES qmake qmake-qt5 HINTS ${QT_BINARY_DIR}) endif() execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} --version OUTPUT_VARIABLE MY_QT_VERSION RESULT_VARIABLE qmake_error) if(qmake_error) message(FATAL_ERROR "Error when executing ${QT_QMAKE_EXECUTABLE} --version\n${qmake_error}") endif() string(REGEX REPLACE ".*Qt version ([0-9.]+) .*" "\\1" MY_QT_VERSION ${MY_QT_VERSION}) endif() # # Project specific properties # if(NOT CTEST_BUILD_NAME) if(MITK_USE_Qt5) set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} Qt${MY_QT_VERSION} ${CTEST_BUILD_CONFIGURATION}") else() set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}") endif() set(CTEST_BUILD_NAME "${CTEST_BUILD_NAME}${CTEST_BUILD_NAME_SUFFIX}") endif() set(PROJECT_BUILD_DIR "MITK-build") set(CTEST_PATH "$ENV{PATH}") if(WIN32) if("${CTEST_CMAKE_GENERATOR}" MATCHES ".*Win64") set(CMAKE_LIBRARY_ARCHITECTURE x64) else() set(CMAKE_LIBRARY_ARCHITECTURE x86) endif() string(SUBSTRING "${MY_COMPILER}" 2 2 vc_version) set(OPENCV_BIN_DIR "${CTEST_BINARY_DIRECTORY}/ep/${CMAKE_LIBRARY_ARCHITECTURE}/vc${vc_version}/bin") set(BLUEBERRY_RUNTIME_DIR "${CTEST_BINARY_DIRECTORY}/MITK-build/bin/plugins/${CTEST_BUILD_CONFIGURATION}") set(PYTHON_BINARY_DIRS "${CTEST_BINARY_DIRECTORY}/ep/src/CTK-build/CMakeExternals/Install/bin") get_filename_component(_python_dir ${PYTHON_EXECUTABLE} DIRECTORY) list(APPEND PYTHON_BINARY_DIRS "${_python_dir}") set(CTEST_PATH "${CTEST_PATH};${CTEST_BINARY_DIRECTORY}/ep/bin;${QT_BINARY_DIR};${BLUEBERRY_RUNTIME_DIR};${OPENCV_BIN_DIR};${PYTHON_BINARY_DIRS}") endif() set(ENV{PATH} "${CTEST_PATH}") # If the dashscript doesn't define a GIT_REPOSITORY variable, let's define it here. if(NOT DEFINED GIT_REPOSITORY OR GIT_REPOSITORY STREQUAL "") set(GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git") endif() # # Display build info # message("Site name: ${CTEST_SITE}") message("Build name: ${CTEST_BUILD_NAME}") message("Script Mode: ${SCRIPT_MODE}") message("Coverage: ${WITH_COVERAGE}, MemCheck: ${WITH_MEMCHECK}") # # Set initial cache options # if(CTEST_CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(CTEST_USE_LAUNCHERS 1) else() set(CTEST_USE_LAUNCHERS 0) endif() set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} ${CTEST_USE_LAUNCHERS}) # Remove this if block after all dartclients work if(DEFINED ADDITIONNAL_CMAKECACHE_OPTION) message(WARNING "Rename ADDITIONNAL to ADDITIONAL in your dartlclient script: ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") set(ADDITIONAL_CMAKECACHE_OPTION ${ADDITIONNAL_CMAKECACHE_OPTION}) endif() if(NOT DEFINED MITK_BUILD_CONFIGURATION) set(MITK_BUILD_CONFIGURATION "All") endif() if(NOT DEFINED MITK_VTK_DEBUG_LEAKS) set(MITK_VTK_DEBUG_LEAKS 1) endif() set(INITIAL_CMAKECACHE_OPTIONS " SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} MITK_VTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} ${ADDITIONAL_CMAKECACHE_OPTION} ") if(MITK_USE_Qt5) set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} QT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}") endif() # Write a cache file for populating the MITK initial cache (not the superbuild cache). # This can be used to provide variables which are not passed through the # superbuild process to the MITK configure step) if(MITK_INITIAL_CACHE) set(mitk_cache_file "${CTEST_SCRIPT_DIRECTORY}/mitk_initial_cache.txt") file(WRITE "${mitk_cache_file}" "${MITK_INITIAL_CACHE}") set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} MITK_INITIAL_CACHE_FILE:INTERNAL=${mitk_cache_file} ") endif() # # Download and include dashboard driver script # if(IS_PHABRICATOR_URL) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardDriverScript.cmake?view=raw") else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardDriverScript.cmake") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.driver) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/Modules/BasicImageProcessing/CMakeLists.txt b/Modules/BasicImageProcessing/CMakeLists.txt new file mode 100644 index 0000000000..2f337313f9 --- /dev/null +++ b/Modules/BasicImageProcessing/CMakeLists.txt @@ -0,0 +1,8 @@ +MITK_CREATE_MODULE( + DEPENDS MitkCore + PACKAGE_DEPENDS + PUBLIC + PRIVATE ITK|ITKIOImageBase+ITKIOGDCM +) + +add_subdirectory(MiniApps) diff --git a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt new file mode 100644 index 0000000000..e107b85391 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt @@ -0,0 +1,88 @@ +option(BUILD_BasicImageProcessingMiniApps "Build commandline tools for Basic Image Processing" OFF) + +if(BUILD_BasicImageProcessingMiniApps OR MITK_BUILD_ALL_APPS) + + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + # list of miniapps + # if an app requires additional dependencies + # they are added after a "^^" and separated by "_" + set( basicImageProcessingMiniApps + FileConverter^^MitkCore + ImageTypeConverter^^MitkCore + ) + + foreach(basicImageProcessingMiniApp ${basicImageProcessingMiniApps}) + # extract mini app name and dependencies + string(REPLACE "^^" "\\;" miniapp_info ${basicImageProcessingMiniApp}) + set(miniapp_info_list ${miniapp_info}) + list(GET miniapp_info_list 0 appname) + list(GET miniapp_info_list 1 raw_dependencies) + string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") + set(dependencies_list ${dependencies}) + + mitk_create_executable(${appname} + DEPENDS MitkCore MitkCommandLine ${dependencies_list} + PACKAGE_DEPENDS ITK + CPP_FILES ${appname}.cpp + ) + # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp + + if(EXECUTABLE_IS_ENABLED) + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) + + if(APPLE) + if(_is_bundle) + set(_target_locations ${EXECUTABLE_TARGET}.app) + set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) + install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) + else() + if(NOT MACOSX_BUNDLE_NAMES) + set(_qt_conf_install_dirs bin) + set(_target_locations bin/${EXECUTABLE_TARGET}) + set(${_target_locations}_qt_plugins_install_dir bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + else() + foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) + list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) + set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) + list(APPEND _target_locations ${_current_target_location}) + set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) + message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) + endforeach() + endif() + endif() + else() + set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) + set(${_target_locations}_qt_plugins_install_dir bin) + set(_qt_conf_install_dirs bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + endif() + endif() + endforeach() + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + if(EXECUTABLE_IS_ENABLED) + MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) + endif() + +endif() diff --git a/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp new file mode 100644 index 0000000000..c349243f93 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp @@ -0,0 +1,116 @@ +/*=================================================================== + +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 + +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("File Converter"); + parser.setCategory("Basic Image Processing"); + 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::InputFile, "Input file:", "Input File",us::Any(),false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); + parser.addArgument("reader", "r", mitkCommandLineParser::String, "Reader Name", "Reader Name", us::Any()); + parser.addArgument("list-readers", "lr", mitkCommandLineParser::Bool, "Reader Name", "Reader Name", 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 inputFilename = us::any_cast(parsedArgs["input"]); + std::string outputFilename = us::any_cast(parsedArgs["output"]); + + mitk::PreferenceListReaderOptionsFunctor::ListType preference = {}; + if (parsedArgs.count("reader")) + { + preference.push_back(us::any_cast(parsedArgs["reader"])); + } + + if (parsedArgs.count("list-readers")) + { + mitk::IOUtil::LoadInfo loadInfo(inputFilename); + auto readers = loadInfo.m_ReaderSelector.Get(); + + std::string errMsg; + if (readers.empty()) + { + if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str())) + { + errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; + } + else + { + errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; + } + MITK_ERROR << errMsg; + return 0; + } + + std::cout << "Available Readers: "< 0) + { + writeName = path + "/" + filename + "_" + std::to_string(count) + extension; + } + mitk::IOUtil::Save(node, writeName); + ++count; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp new file mode 100644 index 0000000000..080f88e955 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp @@ -0,0 +1,127 @@ +/*=================================================================== + +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 "mitkCommandLineParser.h" +#include "mitkIOUtil.h" +#include +#include + +#define CONVERT_IMAGE(TYPE, DIM) \ + { \ + MITK_INFO << "Data Type for Conversion: " << typeid(TYPE).name(); \ + itk::Image::Pointer itkImage = itk::Image::New(); \ + mitk::CastToItkImage(image, itkImage); \ + mitk::CastToMitkImage(itkImage, outputImage); \ + } + +#define CONVERT_IMAGE_TYPE(TYPE) \ + { \ + unsigned int dimension = image->GetDimension(); \ + MITK_INFO << "Image Dimension is: " << dimension; \ + switch (dimension) { \ + case 2 : CONVERT_IMAGE( TYPE , 2); \ + break; \ + case 3 : CONVERT_IMAGE( TYPE , 3); \ + break; \ + default: MITK_INFO << "This tool doesn't support a dimension of "< 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 inputName = us::any_cast(parsedArgs["input"]); + std::string outputName = us::any_cast(parsedArgs["output"]); + std::string type = us::any_cast(parsedArgs["type"]); + + mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); + mitk::Image::Pointer outputImage = mitk::Image::New(); + + if (type.compare("int") == 0) { + CONVERT_IMAGE_TYPE(int); + } + else if (type.compare("uint") == 0) + { + CONVERT_IMAGE_TYPE(unsigned int); + } + else if (type.compare("char") == 0) + { + CONVERT_IMAGE_TYPE(char); + } + else if (type.compare("uchar") == 0) + { + CONVERT_IMAGE_TYPE(unsigned char); + } + else if (type.compare("short") == 0) + { + CONVERT_IMAGE_TYPE(short); + } + else if (type.compare("ushort") == 0) + { + CONVERT_IMAGE_TYPE(unsigned short); + } + else if (type.compare("float") == 0) + { + CONVERT_IMAGE_TYPE(float); + } + else if (type.compare("double") == 0) + { + CONVERT_IMAGE_TYPE(double); + } + else if (type.compare("none") == 0) + { + MITK_INFO << " No conversion performed"; + outputImage = NULL; + } + else + { + CONVERT_IMAGE_TYPE(double); + } + + if (outputImage.IsNotNull()) + { + mitk::IOUtil::Save(outputImage, outputName); + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Modules/BasicImageProcessing/files.cmake b/Modules/BasicImageProcessing/files.cmake new file mode 100644 index 0000000000..562652a41d --- /dev/null +++ b/Modules/BasicImageProcessing/files.cmake @@ -0,0 +1,9 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + +set(CPP_FILES + mitkArithmeticOperation.cpp +) + +set(RESOURCE_FILES + +) diff --git a/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h new file mode 100644 index 0000000000..7b75ebbd8a --- /dev/null +++ b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h @@ -0,0 +1,104 @@ +/*=================================================================== + +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 mitkArithmeticOperation_h +#define mitkArithmeticOperation_h + +#include +#include + +namespace mitk +{ + /** \brief Executes a arithmetic operations on one or two images + * + * All parameters of the arithmetic operations must be specified during construction. + * The actual operation is executed when calling GetResult(). + */ + class MITKBASICIMAGEPROCESSING_EXPORT ArithmeticOperation { + public: + static Image::Pointer Add(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Add(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, double value, bool outputAsDouble = true); + + static Image::Pointer Add(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(double value, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Tan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Atan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Cos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Acos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Asin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Square(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sqrt(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Abs(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Exp(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer ExpNeg(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Log10(Image::Pointer & imageA, bool outputAsDouble = true); + }; + + class MITKBASICIMAGEPROCESSING_EXPORT NonStaticArithmeticOperation { + public: + enum OperationsEnum + { + Add2, + Sub2, + Mult, + Div, + AddValue, + SubValue, + MultValue, + DivValue, + PowValue, + Tan, + ATan, + Cos, + ACos, + Sin, + ASin, + Square, + Sqrt, + Abs, + Exp, + ExpNeg, + Log10 + }; + + + void CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB); + + template + void ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB); + + template + void ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB); + + mitk::Image::Pointer m_ResultImage; + OperationsEnum m_Algorithm; + bool m_GenerateDoubleOutput = false; + }; + + +} +#endif // mitkArithmeticOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp new file mode 100644 index 0000000000..aa4852cd6f --- /dev/null +++ b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp @@ -0,0 +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 std::pow(value, A); + else + return 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/CameraCalibration/mitkCameraIntrinsics.h b/Modules/CameraCalibration/mitkCameraIntrinsics.h index 24466803e6..45b96bfaa1 100644 --- a/Modules/CameraCalibration/mitkCameraIntrinsics.h +++ b/Modules/CameraCalibration/mitkCameraIntrinsics.h @@ -1,144 +1,145 @@ /*=================================================================== 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 mitkCameraIntrinsics_h #define mitkCameraIntrinsics_h #include #include #include #include -#include #include #include "mitkXMLSerializable.h" #include +#include "opencv2/core.hpp" + int mitkCameraIntrinsicsTest(int, char* []); namespace mitk { /// /// \brief class representing camera intrinsics and related functions /// class MITKCAMERACALIBRATION_EXPORT CameraIntrinsics: virtual public itk::Object, virtual public mitk::XMLSerializable { public: /// /// for testing purposes /// friend int mitkCameraIntrinsicsTest(int argc, char* argv[]); /// /// smartpointer typedefs /// mitkClassMacroItkParent(CameraIntrinsics, itk::Object); /// /// the static new function /// itkFactorylessNewMacro(Self); /// /// make a clone of this intrinsics /// itkCloneMacro(Self) /// /// copy information from other to this /// void Copy(const CameraIntrinsics* other); /// /// checks two intrinsics for equality /// bool Equals( const CameraIntrinsics* other ) const; /// /// \return the intrinsic parameter matrix as a 3x3 vnl matrix /// vnl_matrix_fixed GetVnlCameraMatrix() const; /// /// \return the intrinsic parameter matrix as a 3x4 vnl matrix /// (the last column only containing zeros) /// vnl_matrix_fixed GetVnlCameraMatrix3x4() const; /// /// \return true if the intrinsics are set (some plausibility checks /// may be done here) /// bool IsValid() const; void SetValid(bool valid); cv::Mat GetCameraMatrix() const; cv::Mat GetDistorsionCoeffs(); cv::Mat GetDistorsionCoeffs() const; void ToXML(TiXmlElement* elem) const override; std::string ToString() const; std::string GetString(); double GetFocalLengthX() const; double GetFocalLengthY() const; double GetPrincipalPointX() const; double GetPrincipalPointY() const; mitk::Point4D GetDistorsionCoeffsAsPoint4D() const; mitk::Point3D GetFocalPoint() const; mitk::Point3D GetPrincipalPoint() const; vnl_vector_fixed GetFocalPointAsVnlVector() const; vnl_vector_fixed GetPrincipalPointAsVnlVector() const; /// /// set a new camera matrix utilizing a vnl matrix /// void SetCameraMatrix( const vnl_matrix_fixed& _CameraMatrix ); void SetIntrinsics( const cv::Mat& _CameraMatrix , const cv::Mat& _DistorsionCoeffs); void SetFocalLength( double x, double y ); void SetPrincipalPoint( double x, double y ); void SetDistorsionCoeffs( double k1, double k2, double p1, double p2 ); void SetIntrinsics( const mitk::Point3D& focalPoint, const mitk::Point3D& principalPoint, const mitk::Point4D& distortionCoefficients); void FromXML(TiXmlElement* elem) override; void FromGMLCalibrationXML(TiXmlElement* elem); std::string ToOctaveString(const std::string& varName="CameraIntrinsics"); ~CameraIntrinsics() override; protected: CameraIntrinsics(); CameraIntrinsics(const CameraIntrinsics& other); cv::Mat m_CameraMatrix; cv::Mat m_DistorsionCoeffs; bool m_Valid; itk::FastMutexLock::Pointer m_Mutex; private: itk::LightObject::Pointer InternalClone() const override; }; } // namespace mitk MITKCAMERACALIBRATION_EXPORT std::ostream& operator<< (std::ostream& os, mitk::CameraIntrinsics::Pointer p); #endif // mitkCameraIntrinsics_h diff --git a/Modules/CameraCalibration/mitkCvMatFromVnlMatrix.h b/Modules/CameraCalibration/mitkCvMatFromVnlMatrix.h index 21b724321c..758587915d 100644 --- a/Modules/CameraCalibration/mitkCvMatFromVnlMatrix.h +++ b/Modules/CameraCalibration/mitkCvMatFromVnlMatrix.h @@ -1,88 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkCvMatFromVnlMatrix_h #define mitkCvMatFromVnlMatrix_h #include #include -#include #include #include +#include "opencv2/core.hpp" + namespace mitk { /// /// casts a random cv::Mat to a vnl Matrix /// if the columns of the first row are > 1 /// then the Matrix is filled with the values from this row /// otherwise the first elements of each row are used /// to fill the Matrix /// template class CvMatFromVnlMatrix: virtual public Algorithm { public: /// /// init default values and save references /// CvMatFromVnlMatrix( const vnl_matrix* _VnlMatrix, cv::Mat* _CvMat): m_VnlMatrix(_VnlMatrix), m_CvMat(_CvMat) { } /// /// templated function for multiplexed cv::Mat /// template static void Cast( const vnl_matrix& vnlMat, cv::Mat& cvMat ) { endodebugvar( vnlMat ) cvMat = cv::Mat(vnlMat.rows(), vnlMat.cols(), cv::DataType::type); for(unsigned int i=0; i(i,j) = static_cast( vnlMat(i,j) ); // endodebugvar( vnlMat(i,j) ) // endodebugvar( cvMat.at(i,j) ) } } } /// /// executes the Algorithm /// void Update() override { Cast( *m_VnlMatrix, *m_CvMat ); } private: /// /// CvMatFromVnlMatrix input member variable /// const vnl_matrix* m_VnlMatrix; /// /// CvMatFromVnlMatrix output member variable /// cv::Mat* m_CvMat; }; } // namespace mitk #endif // mitkCvMatFromVnlMatrix_h diff --git a/Modules/CameraCalibration/mitkStringFromCvMat.h b/Modules/CameraCalibration/mitkStringFromCvMat.h index d522d0390e..f0e0f13296 100644 --- a/Modules/CameraCalibration/mitkStringFromCvMat.h +++ b/Modules/CameraCalibration/mitkStringFromCvMat.h @@ -1,92 +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 mitkStringFromCvMat_h #define mitkStringFromCvMat_h -#include #include #include #include #include #include +#include "opencv2/core.hpp" + namespace mitk { /// /// create a vnl_matrix from a cv mat /// class StringFromCvMat: virtual public Algorithm { public: /// /// init default values and save references /// StringFromCvMat( const cv::Mat* _CvMat, std::string* _String): m_CvMat(_CvMat), m_String(_String) { } /// /// cv mat to vnl matrix with known cv type /// template void ToString( std::string& string, const cv::Mat& mat ) { std::ostringstream s; for(int i=0; i(i,j) << " "; } s << T_Delim; } string = s.str(); } void SetMatrix( const cv::Mat* _CvMat ) { m_CvMat = _CvMat; } /// /// executes the Algorithm /// void Update() override { endoAccessCvMat( ToString, '\n', (*m_String), (*m_CvMat) ); } private: /// /// StringFromCvMat input member variable /// const cv::Mat* m_CvMat; /// /// StringFromCvMat output member variable /// std::string* m_String; }; } // namespace mitk #endif // mitkStringFromCvMat_h diff --git a/Modules/Classification/CLMiniApps/CLImageConverter.cpp b/Modules/Classification/CLMiniApps/CLImageConverter.cpp deleted file mode 100644 index de2ab03538..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageConverter.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkCommandLineParser.h" -#include "mitkIOUtil.h" - -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 file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file",us::Any(),false); - - 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 inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::IOUtil::Save(image, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp b/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp deleted file mode 100644 index aeeaf8325a..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include "mitkCommandLineParser.h" -#include "mitkIOUtil.h" -#include -#include - -#define CONVERT_IMAGE(TYPE, DIM) itk::Image::Pointer itkImage = itk::Image::New(); \ - MITK_INFO << "Data Type for Conversion: "<< typeid(TYPE).name(); \ - mitk::CastToItkImage(image, itkImage); \ - mitk::CastToMitkImage(itkImage, outputImage) - -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Image Type Converter"); - 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 file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); - parser.addArgument("type", "t", mitkCommandLineParser::OutputFile, "Type definition:", "Define Scalar data type: int, uint, short, ushort, char, uchar, float, double", us::Any(), false); - - 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 inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - std::string type = us::any_cast(parsedArgs["type"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::Image::Pointer outputImage = mitk::Image::New(); - - if (type.compare("int") == 0) - { - CONVERT_IMAGE(int, 3); - } - else if (type.compare("uint") == 0) - { - CONVERT_IMAGE(unsigned int, 3); - } - else if (type.compare("char") == 0) - { - CONVERT_IMAGE(char, 3); - } - else if (type.compare("uchar") == 0) - { - CONVERT_IMAGE(unsigned char, 3); - } - else if (type.compare("short") == 0) - { - CONVERT_IMAGE(short, 3); - } - else if (type.compare("ushort") == 0) - { - CONVERT_IMAGE(unsigned short, 3); - } - else if (type.compare("float") == 0) - { - CONVERT_IMAGE(float, 3); - } - else if (type.compare("double") == 0) - { - CONVERT_IMAGE(double, 3); - } - else if (type.compare("none") == 0) - { - MITK_INFO << " No conversion performed"; - outputImage = image; - } - else - { - CONVERT_IMAGE(double, 3); - } - - - mitk::IOUtil::Save(outputImage, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index ab24948280..0bb6f5e560 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,143 +1,122 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore - CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) - #mitk_create_executable(CLGlobalImageFeatures - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLBrainMask - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageConverter - # DEPENDS MitkCore - # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLSurWeighting - # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting - # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageCropper - # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt - # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp - #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 17b04b392f..64e037b845 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,38 +1,39 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCLResultWritter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp + GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp GlobalImageFeatures/mitkGIFLocalIntensity.cpp GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h new file mode 100644 index 0000000000..9f28cde2d6 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h @@ -0,0 +1,156 @@ +/*=================================================================== + +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 mitkGIFFirstOrderStatistics_h +#define mitkGIFFirstOrderStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFFirstOrderNumericStatistics : public AbstractGlobalImageFeature + { + public: + /** + * \brief Calculates first order statistics of the given image. + * + * The first order statistics for the intensity distribution within a given Region of Interest (ROI) + * is caluclated. The ROI is defined using a mask. + * + * The features are calculated on a quantified image. If the bin-size is too big, the obtained values + * can be errornous and missleading. It is therefore important to use enough bins. The binned approach is + * used in order to avoid floating-point related errors. + * + * This feature calculator is activated by the option -first-order or -fo. + * + * The connected areas are based on the binned image, the binning parameters can be set via the default + * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the + * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. + * No other options are possible beside these two options. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image. All voxels with the value 1 are treated as masked. + * + * The following features are then defined using the (binned) voxel intensity \f$ x_i \f$ of each voxel, the probability + * an intensity \f$ p_x \f$, and the overall number of voxels within the mask \f$ N_v \f$: + * - First Order::Mean: The mean intensity within the ROI + * \f[ \textup{Mean}= \mu = \frac{1}{N_v} \sum x_i \f] + * - First Order::Unbiased Variance: An unbiased estimation of the variance: + * \f[ \textup{Unbiased Variance} = \frac{1}{N_v - 1} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Biased Variance: An biased estimation of the variance. If not specified otherwise, this is + * used as the variance: + * \f[ \textup{Biased Variance} = \sigma^2 = \frac{1}{N_v} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Unbiased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Unbiased Standard Deviation} = \sqrt{\frac{1}{N_v-1} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Biased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Biased Standard Deviation} = \sigma = \sqrt{\frac{1}{N_v} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Skewness: + * \f[ \textup{Skewness} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^3}{\sigma^3} \f] + * - First Order::Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution: + * \f[ \textup{Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} \f] + * - First Order::Excess Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution. The excess kurtosis is similar to the kurtosis, but is corrected by a fisher correction, + * ensuring that a gaussian distribution has an excess kurtosis of 0. + * \f[ \textup{Excess Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} - 3 \f] + * - First Order::Median: The median is defined as the median of the all intensities in the ROI. + * - First Order::Minimum: The minimum is defined as the minimum of the all intensities in the ROI. + * - First Order::05th Percentile: \f$ P_{5\%} \f$ The 5% percentile. 5% of all voxel do have this or a lower intensity. + * - First Order::10th Percentile: \f$ P_{10\%} \f$ The 10% percentile. 10% of all voxel do have this or a lower intensity. + * - First Order::15th Percentile: \f$ P_{15\%} \f$ The 15% percentile. 15% of all voxel do have this or a lower intensity. + * - First Order::20th Percentile: \f$ P_{20\%} \f$ The 20% percentile. 20% of all voxel do have this or a lower intensity. + * - First Order::25th Percentile: \f$ P_{25\%} \f$ The 25% percentile. 25% of all voxel do have this or a lower intensity. + * - First Order::30th Percentile: \f$ P_{30\%} \f$ The 30% percentile. 30% of all voxel do have this or a lower intensity. + * - First Order::35th Percentile: \f$ P_{35\%} \f$ The 35% percentile. 35% of all voxel do have this or a lower intensity. + * - First Order::40th Percentile: \f$ P_{40\%} \f$ The 40% percentile. 40% of all voxel do have this or a lower intensity. + * - First Order::45th Percentile: \f$ P_{45\%} \f$ The 45% percentile. 45% of all voxel do have this or a lower intensity. + * - First Order::50th Percentile: \f$ P_{50\%} \f$ The 50% percentile. 50% of all voxel do have this or a lower intensity. + * - First Order::55th Percentile: \f$ P_{55\%} \f$ The 55% percentile. 55% of all voxel do have this or a lower intensity. + * - First Order::60th Percentile: \f$ P_{60\%} \f$ The 60% percentile. 60% of all voxel do have this or a lower intensity. + * - First Order::65th Percentile: \f$ P_{65\%} \f$ The 65% percentile. 65% of all voxel do have this or a lower intensity. + * - First Order::70th Percentile: \f$ P_{70\%} \f$ The 70% percentile. 70% of all voxel do have this or a lower intensity. + * - First Order::75th Percentile: \f$ P_{75\%} \f$ The 75% percentile. 75% of all voxel do have this or a lower intensity. + * - First Order::80th Percentile: \f$ P_{80\%} \f$ The 80% percentile. 80% of all voxel do have this or a lower intensity. + * - First Order::85th Percentile: \f$ P_{85\%} \f$ The 85% percentile. 85% of all voxel do have this or a lower intensity. + * - First Order::90th Percentile: \f$ P_{90\%} \f$ The 90% percentile. 90% of all voxel do have this or a lower intensity. + * - First Order::95th Percentile: \f$ P_{95\%} \f$ The 95% percentile. 95% of all voxel do have this or a lower intensity. + * - First Order::Maximum: The maximum is defined as the minimum of the all intensities in the ROI. + * - First Order::Range: The range of intensity values is defined as the difference between the maximum + * and minimum intensity in the ROI. + * - First Order::Interquartile Range: The difference between the 75% and 25% quantile. + * - First Order::Mean Absolute Deviation: The mean absolute deviation gives the mean distance of each + * voxel intensity to the overal mean intensity and is a measure of the dispersion of the intensity form the + * mean value: + * \f[ \textup{Mean Absolute Deviation} = \frac{1}{N_v} \sum \left \| x_i - \mu \right \| \f] + * - First Order::Robust Mean: The mean intensity within the ROI for all voxels between the 10% and 90% quantile: + * \f[ \textup{Robust Mean}= \mu_R = \frac{1}{N_{vr}} \sum x_i \f] + * - First Order::Robust Mean Absolute Deviation: The absolute deviation of all intensities within the ROI for + * all voxels between the 10% and 90% quantilefrom the robust mean intensity: + * \f[ \textup{Robust Mean Absolute Deviation}= \mu_R = \frac{1}{N_{vr}} \sum \left \| x_i - \mu_R \right \| \f] + * - First Order::Median Absolute Deviation: Similar to the mean absolute deviation, but uses the median + * instead of the mean to measure the center of the distribution. + * - First Order::Coefficient Of Variation: Measures the dispersion of the intensity distribution: + * \f[ \textup{Coefficient Of Variation} = \frac{sigma}{\mu} \f] + * - First Order::Quantile Coefficient Of Dispersion: A robust alternative to teh coefficient of variance: + * \f[ \textup{Quantile Coefficient Of Dispersion} = \frac{P_{75\%} - P_{25\%} }{P_{75\%} + P_{25\%}} \f] + * - First Order::Energy: The intensity energy: + * \f[ \textup{Energy} = \sum x_i ^2 \f] + * - First Order::Root Mean Square: Root mean square is an important measure for the error. + * \f[ \textup{Root Mean Square} = \sqrt{\frac{\sum x_i ^2}{N_v}} \f] + * - First Order::Uniformity: + * \f[ \textup{Uniformity} = \sum p_x^2 \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Covered Image Intensity Range: Percentage of the image intensity range (maximum - minimum in whole + * image) that is covered by the ROI. + * - First Order::Sum: The sum of all intensities. It is correlated to the mean intensity. + * \f[ \textup{Sum} = \sum x_i \f] + * - First Order::Mode: The most common intensity. + * - First Order::Mode Probability: The likelihood of the most common intensity. + * - First Order::Number Of Voxels: \f$ N_v \f$ the number of voxels covered by the ROI. + * - First Order::Image Dimension: The dimensionality of the image (e.g. 2D, 3D, etc.). + * - First Order::Number Of Voxels: The product of all spacing along all dimensions. In 3D, this is equal to the + * volume. + * - First Order::Number Of Voxels: The volume of a single voxel. If the dimensionality is only 2D, this is the + * surface of an voxel. + */ + mitkClassMacro(GIFFirstOrderNumericStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFFirstOrderNumericStatistics(); + + /** + * \brief Calculates the First Order Features based on a binned version of the image. + */ + FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + FeatureNameListType GetFeatureNames() override; + virtual std::string GetCurrentFeatureEncoding() override; + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + }; +} +#endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index a50b98f65a..3bb2973578 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,693 +1,693 @@ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(itk::Image* itkImage, itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, config.prefix + " Overall", featureList); - MatrixFeaturesTo(featureMean, config.prefix + " Mean", featureList); - MatrixFeaturesTo(featureStd, config.prefix + " Std.Dev.", featureList); + MatrixFeaturesTo(overallFeature, config.prefix + "Overall ", featureList); + MatrixFeaturesTo(featureMean, config.prefix + "Mean ", featureList); + MatrixFeaturesTo(featureStd, config.prefix + "Std.Dev. ", featureList); } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + "Joint Maximum", features.JointMaximum)); featureList.push_back(std::make_pair(prefix + "Joint Average", features.JointAverage)); featureList.push_back(std::make_pair(prefix + "Joint Variance", features.JointVariance)); featureList.push_back(std::make_pair(prefix + "Joint Entropy", features.JointEntropy)); - featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); - featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); - featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); - featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); - featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); - featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + "Difference Average", features.DifferenceAverage)); featureList.push_back(std::make_pair(prefix + "Difference Variance", features.DifferenceVariance)); featureList.push_back(std::make_pair(prefix + "Difference Entropy", features.DifferenceEntropy)); featureList.push_back(std::make_pair(prefix + "Sum Average", features.SumAverage)); featureList.push_back(std::make_pair(prefix + "Sum Variance", features.SumVariance)); featureList.push_back(std::make_pair(prefix + "Sum Entropy", features.SumEntropy)); featureList.push_back(std::make_pair(prefix + "Angular Second Moment", features.AngularSecondMoment)); featureList.push_back(std::make_pair(prefix + "Contrast", features.Contrast)); featureList.push_back(std::make_pair(prefix + "Dissimilarity", features.Dissimilarity)); featureList.push_back(std::make_pair(prefix + "Inverse Difference", features.InverseDifference)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Normalized", features.InverseDifferenceNormalised)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment", features.InverseDifferenceMoment)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); - featureList.push_back(std::make_pair(prefix + " Inverse Variance", features.InverseVariance)); + featureList.push_back(std::make_pair(prefix + "Inverse Variance", features.InverseVariance)); featureList.push_back(std::make_pair(prefix + "Correlation", features.Correlation)); - featureList.push_back(std::make_pair(prefix + "Autocorrleation", features.Autocorrelation)); + featureList.push_back(std::make_pair(prefix + "Autocorrelation", features.Autocorrelation)); featureList.push_back(std::make_pair(prefix + "Cluster Tendency", features.ClusterTendency)); featureList.push_back(std::make_pair(prefix + "Cluster Shade", features.ClusterShade)); featureList.push_back(std::make_pair(prefix + "Cluster Prominence", features.ClusterProminence)); featureList.push_back(std::make_pair(prefix + "First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + "Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); + featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); + featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); + featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); + featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); + featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): m_Range(1.0) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } std::string mitk::GIFCooccurenceMatrix2::GetCurrentFeatureEncoding() { std::ostringstream ss; ss << m_Range; std::string strRange = ss.str(); return QuantifierParameterString() + "_Range-" + ss.str(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp new file mode 100644 index 0000000000..38f3a7ad77 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -0,0 +1,357 @@ +/*=================================================================== + +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 + +// ITK +#include +#include +#include + +// STL +#include + +struct FirstOrderNumericParameterStruct { + mitk::IntensityQuantifier::Pointer quantifier; + double MinimumIntensity; + double MaximumIntensity; + int Bins; + std::string prefix; +}; + +template +void +CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + // + // Calculate the Volume of Voxel (Maximum to the 3th order) + // + double voxelVolume = 1; + for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) + voxelVolume *= itkImage->GetSpacing()[i]; + + // + // Calculate the Hypervolume of Voxel + // + double voxelSpace = 1; + for (unsigned int i = 0; i < VImageDimension; ++i) + voxelSpace *= itkImage->GetSpacing()[i]; + + unsigned int numberOfBins = params.quantifier->GetBins(); + std::vector histogram; + histogram.resize(numberOfBins, 0); + + + double minimum = std::numeric_limits::max(); + double maximum = std::numeric_limits::lowest(); + double absoluteMinimum = std::numeric_limits::max(); + double absoluteMaximum = std::numeric_limits::lowest(); + double sum = 0; + double sumTwo= 0; + double sumThree = 0; + unsigned int numberOfVoxels = 0; + + itk::ImageRegionIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); + + while (!imageIter.IsAtEnd()) + { + double value = imageIter.Get(); + + absoluteMinimum = std::min(minimum, value); + absoluteMaximum = std::max(maximum, value); + if (maskIter.Get() > 0) + { + minimum = std::min(minimum, value); + maximum = std::max(maximum, value); + + sum += value; + sumTwo += value * value; + sumThree += value * value*value; + + histogram[params.quantifier->IntensityToIndex(value)] += 1; + + ++numberOfVoxels; + } + ++maskIter; + ++imageIter; + } + + // + // Histogram based calculations + // + unsigned int passedValues = 0; + double doubleNoOfVoxes = numberOfVoxels; + double median = 0; + double lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(0); + std::size_t modeIdx = 0; + + double entropy = 0; + double uniformity = 0; + + std::vector percentiles; + percentiles.resize(20, 0); + + for (std::size_t idx = 0; idx < histogram.size(); ++idx) + { + unsigned int actualValues = histogram[idx]; + + for (std::size_t percentileIdx = 0; percentileIdx < percentiles.size(); ++percentileIdx) + { + double threshold = doubleNoOfVoxes * (percentileIdx + 1) *1.0 / (percentiles.size()); + if ((passedValues < threshold) & ((passedValues + actualValues) >= threshold)) + { + // Lower Bound + if (passedValues == std::floor(threshold)) + { + percentiles[percentileIdx] = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + percentiles[percentileIdx] = params.quantifier->IndexToMeanIntensity(idx); + } + } + } + + if ((passedValues < doubleNoOfVoxes * 0.5) & ((passedValues + actualValues) >= doubleNoOfVoxes * 0.5)) + { + // Lower Bound + if (passedValues == std::floor(doubleNoOfVoxes * 0.5)) + { + median = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + median = params.quantifier->IndexToMeanIntensity(idx); + } + } + + if (actualValues > histogram[modeIdx]) + { + modeIdx = idx; + } + + if (actualValues > 0) + { + lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(idx); + + double currentProbability = actualValues / (1.0 *numberOfVoxels); + uniformity += currentProbability * currentProbability; + entropy += currentProbability * std::log(currentProbability) / std::log(2); + } + passedValues += actualValues; + } + double p10 = percentiles[1]; + double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); + double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); + double p90 = percentiles[17]; + + double mean = sum / (numberOfVoxels); + double variance = sumTwo / (numberOfVoxels) - (mean*mean); + double energy = sumTwo; + double rootMeanSquare = std::sqrt(sumTwo / numberOfVoxels); + + double sumAbsoluteDistanceToMean = 0; + double sumAbsoluteDistanceToMedian = 0; + double sumRobust = 0; + double sumRobustSquare = 0; + double sumRobustAbsolulteDistanceToMean = 0; + double sumValueMinusMean = 0; + double sumValueMinusMeanThree = 0; + double sumValueMinusMeanFour = 0; + unsigned int numberOfRobustVoxel = 0; + + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + double valueMinusMean = value - mean; + + sumAbsoluteDistanceToMean += std::abs(valueMinusMean); + sumAbsoluteDistanceToMedian += std::abs(value - median); + sumValueMinusMean += valueMinusMean; + sumValueMinusMeanThree += valueMinusMean * valueMinusMean * valueMinusMean; + sumValueMinusMeanFour += valueMinusMean * valueMinusMean * valueMinusMean * valueMinusMean; + + if ((p10 <= value) & (value <= p90)) + { + sumRobust += value; + sumRobustSquare += value * value; + ++numberOfRobustVoxel; + } + } + ++maskIter; + ++imageIter; + } + double robustMean = sumRobust / numberOfRobustVoxel; + double robustVariance = sumRobustSquare / numberOfRobustVoxel - (robustMean * robustMean); + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + + if ((p10 <= value) & (value <= p90)) + { + sumRobustAbsolulteDistanceToMean += std::abs(value - robustMean); + } + } + ++maskIter; + ++imageIter; + } + + + + double meanAbsoluteDeviation = sumAbsoluteDistanceToMean / numberOfVoxels; + double medianAbsoluteDeviation = sumAbsoluteDistanceToMedian / numberOfVoxels; + double robustMeanAbsoluteDeviation = sumRobustAbsolulteDistanceToMean / numberOfRobustVoxel; + double skewness = sumValueMinusMeanThree / numberOfVoxels / variance / std::sqrt(variance); + double kurtosis = sumValueMinusMeanFour / numberOfVoxels / variance / variance; + double interquantileRange = p75idx - p25idx; + double coefficientOfVariation = std::sqrt(variance) / mean; + double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx + 2); + double coveredImageRange = (maximum - minimum)/ (absoluteMaximum - absoluteMinimum) ; + + featureList.push_back(std::make_pair(params.prefix + "Mean", mean)); + featureList.push_back(std::make_pair(params.prefix + "Variance", variance)); + featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); + featureList.push_back(std::make_pair(params.prefix + "Excess kurtosis", kurtosis-3)); + featureList.push_back(std::make_pair(params.prefix + "Median", median)); + featureList.push_back(std::make_pair(params.prefix + "Minimum", minimum)); + featureList.push_back(std::make_pair(params.prefix + "05th Percentile", percentiles[0])); + featureList.push_back(std::make_pair(params.prefix + "10th Percentile", percentiles[1])); + featureList.push_back(std::make_pair(params.prefix + "15th Percentile", percentiles[2])); + featureList.push_back(std::make_pair(params.prefix + "20th Percentile", percentiles[3])); + featureList.push_back(std::make_pair(params.prefix + "25th Percentile", percentiles[4])); + featureList.push_back(std::make_pair(params.prefix + "30th Percentile", percentiles[5])); + featureList.push_back(std::make_pair(params.prefix + "35th Percentile", percentiles[6])); + featureList.push_back(std::make_pair(params.prefix + "40th Percentile", percentiles[7])); + featureList.push_back(std::make_pair(params.prefix + "45th Percentile", percentiles[8])); + featureList.push_back(std::make_pair(params.prefix + "50th Percentile", percentiles[9])); + featureList.push_back(std::make_pair(params.prefix + "55th Percentile", percentiles[10])); + featureList.push_back(std::make_pair(params.prefix + "60th Percentile", percentiles[11])); + featureList.push_back(std::make_pair(params.prefix + "65th Percentile", percentiles[12])); + featureList.push_back(std::make_pair(params.prefix + "70th Percentile", percentiles[13])); + featureList.push_back(std::make_pair(params.prefix + "75th Percentile", percentiles[14])); + featureList.push_back(std::make_pair(params.prefix + "80th Percentile", percentiles[15])); + featureList.push_back(std::make_pair(params.prefix + "85th Percentile", percentiles[16])); + featureList.push_back(std::make_pair(params.prefix + "90th Percentile", percentiles[17])); + featureList.push_back(std::make_pair(params.prefix + "95th Percentile", percentiles[18])); + featureList.push_back(std::make_pair(params.prefix + "Maximum", maximum)); + featureList.push_back(std::make_pair(params.prefix + "Interquantile range", interquantileRange)); + featureList.push_back(std::make_pair(params.prefix + "Range", maximum-minimum)); + featureList.push_back(std::make_pair(params.prefix + "Mean absolute deviation", meanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean absolute deviation", robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Median absolute deviation", medianAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Coefficient of variation", coefficientOfVariation)); + featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of dispersion", quantileCoefficientOfDispersion)); + featureList.push_back(std::make_pair(params.prefix + "Energy", energy)); + featureList.push_back(std::make_pair(params.prefix + "Root mean square", rootMeanSquare)); + + featureList.push_back(std::make_pair(params.prefix + "Standard Deviation", std::sqrt(variance))); + featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean", robustMean)); + featureList.push_back(std::make_pair(params.prefix + "Robust variance", robustVariance)); + featureList.push_back(std::make_pair(params.prefix + "Covered image intensity range", coveredImageRange)); + featureList.push_back(std::make_pair(params.prefix + "Mode index", modeIdx)); + featureList.push_back(std::make_pair(params.prefix + "Mode value", params.quantifier->IndexToMeanIntensity(modeIdx))); + featureList.push_back(std::make_pair(params.prefix + "Mode probability", histogram[modeIdx] / (1.0*numberOfVoxels))); + featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); + featureList.push_back(std::make_pair(params.prefix + "Uniformtiy", uniformity)); + featureList.push_back(std::make_pair(params.prefix + "Number of voxels", numberOfVoxels)); + featureList.push_back(std::make_pair(params.prefix + "Sum of voxels", sum)); + featureList.push_back(std::make_pair(params.prefix + "Voxel space", voxelSpace)); + featureList.push_back(std::make_pair(params.prefix + "Voxel volume", voxelVolume)); + featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); + + return; +} + +mitk::GIFFirstOrderNumericStatistics::GIFFirstOrderNumericStatistics() +{ + SetShortName("fon"); + SetLongName("first-order-numeric"); + SetFeatureClassName("First Order Numeric"); +} + +mitk::GIFFirstOrderNumericStatistics::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + InitializeQuantifier(image, mask); + FeatureListType featureList; + + FirstOrderNumericParameterStruct params; + + params.quantifier = GetQuantifier(); + params.MinimumIntensity = GetQuantifier()->GetMinimum(); + params.MaximumIntensity = GetQuantifier()->GetMaximum(); + params.Bins = GetQuantifier()->GetBins(); + params.prefix = FeatureDescriptionPrefix(); + AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); + + return featureList; +} + +mitk::GIFFirstOrderNumericStatistics::FeatureNameListType mitk::GIFFirstOrderNumericStatistics::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use First Order Statistic (Numeric)", "calculates First Order Statistic (Numeric)", us::Any()); + AddQuantifierArguments(parser); +} + +void +mitk::GIFFirstOrderNumericStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + InitializeQuantifierFromParameters(feature, maskNoNAN); + MITK_INFO << "Start calculating first order features ...."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating first order features...."; + } +} + +std::string mitk::GIFFirstOrderNumericStatistics::GetCurrentFeatureEncoding() +{ + return QuantifierParameterString(); +} \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp index 827b67b4ef..29cf808810 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp @@ -1,177 +1,177 @@ /*=================================================================== 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 // ITK #include #include #include // STL #include template static void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, std::string prefix) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); unsigned int imageDimensionX = itkImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int imageDimensionY = itkImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int imageDimensionZ = itkImage->GetLargestPossibleRegion().GetSize()[2]; double imageVoxelSpacingX = itkImage->GetSpacing()[0]; double imageVoxelSpacingY = itkImage->GetSpacing()[1]; double imageVoxelSpacingZ = itkImage->GetSpacing()[2]; typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageMinimum = minMaxComputer->GetMinimum(); double imageMaximum = minMaxComputer->GetMaximum(); unsigned int maskDimensionX = maskImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = maskImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = maskImage->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = maskImage->GetSpacing()[0]; double maskVoxelSpacingY = maskImage->GetSpacing()[1]; double maskVoxelSpacingZ = maskImage->GetSpacing()[2]; unsigned int voxelCount = 0; unsigned int maskVoxelCount = 0; double maskMinimum = imageMaximum; double maskMaximum = imageMinimum; double imageMean = 0; double maskMean = 0; - unsigned int maskMinimumX = maskDimensionX; - unsigned int maskMaximumX = 0; - unsigned int maskMinimumY = maskDimensionY; - unsigned int maskMaximumY = 0; - unsigned int maskMinimumZ = maskDimensionZ; - unsigned int maskMaximumZ = 0; + int maskMinimumX = maskDimensionX; + int maskMaximumX = 0; + int maskMinimumY = maskDimensionY; + int maskMaximumY = 0; + int maskMinimumZ = maskDimensionZ; + int maskMaximumZ = 0; itk::ImageRegionConstIteratorWithIndex imIter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maIter(maskImage, maskImage->GetLargestPossibleRegion()); while (!imIter.IsAtEnd()) { auto pixelValue = imIter.Get(); if (maIter.Get() > 0) { ++maskVoxelCount; maskMean += pixelValue; maskMinimum = (maskMinimum > pixelValue) ? pixelValue : maskMinimum; maskMaximum = (maskMaximum < pixelValue) ? pixelValue : maskMaximum; maskMinimumX = (maskMinimumX > imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMaximumZ; } ++voxelCount; imageMean += pixelValue; ++imIter; ++maIter; } imageMean /= voxelCount; maskMean /= maskVoxelCount; featureList.push_back(std::make_pair(prefix + "Image Dimension X", imageDimensionX)); featureList.push_back(std::make_pair(prefix + "Image Dimension Y", imageDimensionY)); featureList.push_back(std::make_pair(prefix + "Image Dimension Z", imageDimensionZ)); featureList.push_back(std::make_pair(prefix + "Image Spacing X", imageVoxelSpacingX)); featureList.push_back(std::make_pair(prefix + "Image Spacing Y", imageVoxelSpacingY)); featureList.push_back(std::make_pair(prefix + "Image Spacing Z", imageVoxelSpacingZ)); featureList.push_back(std::make_pair(prefix + "Image Mean intensity", imageMean)); featureList.push_back(std::make_pair(prefix + "Image Minimum intensity", imageMinimum)); featureList.push_back(std::make_pair(prefix + "Image Maximum intensity", imageMaximum)); featureList.push_back(std::make_pair(prefix + "Mask Dimension X", maskDimensionX)); featureList.push_back(std::make_pair(prefix + "Mask Dimension Y", maskDimensionY)); featureList.push_back(std::make_pair(prefix + "Mask Dimension Z", maskDimensionZ)); featureList.push_back(std::make_pair(prefix + "Mask bounding box X", maskMaximumX - maskMinimumX + 1)); featureList.push_back(std::make_pair(prefix + "Mask bounding box Y", maskMaximumY - maskMinimumY + 1)); featureList.push_back(std::make_pair(prefix + "Mask bounding box Z", maskMaximumZ - maskMinimumZ + 1)); featureList.push_back(std::make_pair(prefix + "Mask Spacing X", maskVoxelSpacingX)); featureList.push_back(std::make_pair(prefix + "Mask Spacing Y", maskVoxelSpacingY)); featureList.push_back(std::make_pair(prefix + "Mask Spacing Z", maskVoxelSpacingZ)); featureList.push_back(std::make_pair(prefix + "Mask Voxel Count", maskVoxelCount)); featureList.push_back(std::make_pair(prefix + "Mask Mean intensity", maskMean)); featureList.push_back(std::make_pair(prefix + "Mask Minimum intensity", maskMinimum)); featureList.push_back(std::make_pair(prefix + "Mask Maximum intensity", maskMaximum)); } mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() { SetShortName("id"); SetLongName("image-diagnostic"); SetFeatureClassName("Diagnostic"); } mitk::GIFImageDescriptionFeatures::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, FeatureDescriptionPrefix()); return featureList; } mitk::GIFImageDescriptionFeatures::FeatureNameListType mitk::GIFImageDescriptionFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Image Description", "calculates image description features", us::Any()); } void mitk::GIFImageDescriptionFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating image description features...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating image description features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp index d29b4a9e0e..a531a1043d 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -1,173 +1,173 @@ /*=================================================================== 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 // ITK #include #include // STL #include struct GIFIntensityVolumeHistogramFeaturesParameters { mitk::IntensityQuantifier::Pointer quantifier; std::string prefix; }; template static void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, GIFIntensityVolumeHistogramFeaturesParameters params, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); mitk::IntensityQuantifier::Pointer quantifier = params.quantifier; std::string prefix = params.prefix; itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator iterMask(itkMask, itkMask->GetLargestPossibleRegion()); MITK_INFO << "Quantification: " << quantifier->GetMinimum() << " to " << quantifier->GetMaximum() << " with " << quantifier->GetBins()<< " bins"; iter.GoToBegin(); iterMask.GoToBegin(); std::vector hist; hist.resize(quantifier->GetBins() , 0); int count = 0; while (!iter.IsAtEnd()) { if (iterMask.Get() > 0) { double value = iter.Get(); //std::size_t index = std::floor((value - minimum) / (maximum - minimum) * (bins-1)); std::size_t index = quantifier->IntensityToIndex(value); ++count; hist[index] += 1.0;// / count; } ++iterMask; ++iter; } bool notFoundIntenstiy010 = true; bool notFoundIntenstiy090 = true; double intensity010 = -1; double intensity090 = -1; double fraction = 0; double auc = 0; bool firstRound = true; for (int i = quantifier->GetBins()-1; i >= 0; --i) { hist[i] /= count; hist[i] += fraction; fraction = hist[i]; if (!firstRound) { auc += 0.5 * (hist[i] + hist[i+1]) / (quantifier->GetBins()-1); } firstRound = false; if (notFoundIntenstiy010 && fraction > 0.1) { intensity010 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy010 = false; } if (notFoundIntenstiy090 && fraction > 0.9) { intensity090 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy090 = false; } } unsigned int index010 = std::ceil(quantifier->GetBins() * 0.1); unsigned int index090 = std::floor(quantifier->GetBins() * 0.9); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.10 intensity", hist[index010])); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.90 intensity", hist[index090])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.10 intensity", hist[index010])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.90 intensity", hist[index090])); featureList.push_back(std::make_pair(prefix + "Intensity at 0.10 volume", intensity010)); featureList.push_back(std::make_pair(prefix + "Intensity at 0.90 volume", intensity090)); - featureList.push_back(std::make_pair(prefix + "Difference volume fration at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair(prefix + "Difference volume fraction at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); featureList.push_back(std::make_pair(prefix + "Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); featureList.push_back(std::make_pair(prefix + "Area under IVH curve", auc)); //featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); } mitk::GIFIntensityVolumeHistogramFeatures::GIFIntensityVolumeHistogramFeatures() { SetLongName("intensity-volume-histogram"); SetShortName("ivoh"); SetFeatureClassName("Intensity Volume Histogram"); } mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask, 1000); FeatureListType featureList; GIFIntensityVolumeHistogramFeaturesParameters params; params.quantifier = GetQuantifier(); params.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); return featureList; } mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { InitializeQuantifierFromParameters(feature, mask, 1000); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating local intensity features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating local intensity features...."; } } std::string mitk::GIFIntensityVolumeHistogramFeatures::GetCurrentFeatureEncoding() { return QuantifierParameterString(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp index 7353fd353a..cd26bcfddb 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,460 +1,460 @@ /*=================================================================== 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 // VTK #include #include #include #include #include #include // STL #include template void CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->Update(); double volume = labelStatisticsImageFilter->GetCount(1); double voxelVolume = 1; for (int i = 0; i < (int)(VImageDimension); ++i) { volume *= itkImage->GetSpacing()[i]; voxelVolume *= itkImage->GetSpacing()[i]; } featureList.push_back(std::make_pair(prefix + "Voxel Volume", voxelVolume)); featureList.push_back(std::make_pair(prefix + "Volume (voxel based)", volume)); } template void CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ValueImageType; typename ValueImageType::Pointer itkValueImage = ValueImageType::New(); mitk::CastToItkImage(valueImage, itkValueImage); typedef itk::Image ImageType; typedef typename ImageType::PointType PointType; typename ImageType::SizeType radius; for (int i=0; i < (int)VImageDimension; ++i) radius[i] = 1; itk::NeighborhoodIterator iterator(radius, mask, mask->GetRequestedRegion()); itk::NeighborhoodIterator valueIter(radius, itkValueImage, itkValueImage->GetRequestedRegion()); std::vector borderPoints; unsigned int maskDimensionX = mask->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = mask->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = mask->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = mask->GetSpacing()[0]; double maskVoxelSpacingY = mask->GetSpacing()[1]; double maskVoxelSpacingZ = mask->GetSpacing()[2]; - unsigned int maskMinimumX = maskDimensionX; - unsigned int maskMaximumX = 0; - unsigned int maskMinimumY = maskDimensionY; - unsigned int maskMaximumY = 0; - unsigned int maskMinimumZ = maskDimensionZ; - unsigned int maskMaximumZ = 0; + int maskMinimumX = maskDimensionX; + int maskMaximumX = 0; + int maskMinimumY = maskDimensionY; + int maskMaximumY = 0; + int maskMinimumZ = maskDimensionZ; + int maskMaximumZ = 0; // // Calculate surface in different directions // double surface = 0; std::vector directionSurface; for (int i = 0; i < (int)(iterator.Size()); ++i) { auto offset = iterator.GetOffset(i); double deltaS = 1; int nonZeros = 0; for (unsigned int j = 0; j < VImageDimension; ++j) { if (offset[j] != 0 && nonZeros == 0) { for (unsigned int k = 0; k < VImageDimension; ++k) { if (k != j) deltaS *= mask->GetSpacing()[k]; } nonZeros++; } else if (offset[j] != 0) { deltaS = 0; } } if (nonZeros < 1) deltaS = 0; directionSurface.push_back(deltaS); } // // Prepare calulation of Centre of mass shift // PointType normalCenter(0); PointType normalCenterUncorrected(0); PointType weightedCenter(0); PointType currentPoint; int numberOfPoints = 0; int numberOfPointsUncorrected = 0; double sumOfPoints = 0; while(!iterator.IsAtEnd()) { if (iterator.GetCenterPixel() == 0) { ++iterator; ++valueIter; continue; } maskMinimumX = (maskMinimumX > iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMaximumZ; mask->TransformIndexToPhysicalPoint(iterator.GetIndex(), currentPoint); normalCenterUncorrected += currentPoint.GetVectorFromOrigin(); ++numberOfPointsUncorrected; double intensityValue = valueIter.GetCenterPixel(); if (intensityValue == intensityValue) { normalCenter += currentPoint.GetVectorFromOrigin(); weightedCenter += currentPoint.GetVectorFromOrigin() * intensityValue; sumOfPoints += intensityValue; ++numberOfPoints; } bool border = false; for (int i = 0; i < (int)(iterator.Size()); ++i) { if (iterator.GetPixel(i) == 0 || ( ! iterator.IndexInBounds(i))) { border = true; surface += directionSurface[i]; //break; } } if (border) { auto centerIndex = iterator.GetIndex(); PointType centerPoint; mask->TransformIndexToPhysicalPoint(centerIndex, centerPoint ); borderPoints.push_back(centerPoint); } ++iterator; ++valueIter; } auto normalCenterVector = normalCenter.GetVectorFromOrigin() / numberOfPoints; auto normalCenterVectorUncorrected = normalCenter.GetVectorFromOrigin() / numberOfPointsUncorrected; auto weightedCenterVector = weightedCenter.GetVectorFromOrigin() / sumOfPoints; auto differenceOfCentersUncorrected = (normalCenterVectorUncorrected - weightedCenterVector).GetNorm(); auto differenceOfCenters = (normalCenterVector - weightedCenterVector).GetNorm(); double longestDiameter = 0; unsigned long numberOfBorderPoints = borderPoints.size(); for (int i = 0; i < (int)numberOfBorderPoints; ++i) { auto point = borderPoints[i]; for (int j = i; j < (int)numberOfBorderPoints; ++j) { double newDiameter=point.EuclideanDistanceTo(borderPoints[j]); if (newDiameter > longestDiameter) longestDiameter = newDiameter; } } double boundingBoxVolume = maskVoxelSpacingX* (maskMaximumX - maskMinimumX) * maskVoxelSpacingY* (maskMaximumY - maskMinimumY) * maskVoxelSpacingZ* (maskMaximumZ - maskMinimumZ); featureList.push_back(std::make_pair(prefix + "Maximum 3D diameter", longestDiameter)); featureList.push_back(std::make_pair(prefix + "Surface (voxel based)", surface)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift", differenceOfCenters)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift (uncorrected)", differenceOfCentersUncorrected)); featureList.push_back(std::make_pair(prefix + "Bounding Box Volume", boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); SetFeatureClassName("Volumetric Features"); } mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, FeatureDescriptionPrefix()); AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, FeatureDescriptionPrefix()); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); double pixelVolume = featureList[1].second; double pixelSurface = featureList[3].second; MITK_INFO << "Surface: " << pixelSurface << " Volume: " << pixelVolume; double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0)); double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0)); //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead. double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf; double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0)); double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / meshVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1; double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1; //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]; 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"); 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) { dataset1ArrU->InsertNextValue(x*xd); dataset2ArrU->InsertNextValue(y*yd); dataset3ArrU->InsertNextValue(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 datasetTableU = vtkSmartPointer::New(); datasetTableU->AddColumn(dataset1ArrU); datasetTableU->AddColumn(dataset2ArrU); datasetTableU->AddColumn(dataset3ArrU); 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); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTableU); pcaStatistics->Update(); vtkSmartPointer eigenvaluesU = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvaluesU); std::vector eigen_val(3); std::vector eigen_valUC(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); eigen_valUC[2] = eigenvaluesU->GetValue(0); eigen_valUC[1] = eigenvaluesU->GetValue(1); eigen_valUC[0] = eigenvaluesU->GetValue(2); double major = 4*sqrt(eigen_val[2]); double minor = 4*sqrt(eigen_val[1]); double least = 4*sqrt(eigen_val[0]); double elongation = (major == 0) ? 0 : sqrt(eigen_val[1] / eigen_val[2]); double flatness = (major == 0) ? 0 : sqrt(eigen_val[0] / eigen_val[2]); double majorUC = 4*sqrt(eigen_valUC[2]); double minorUC = 4*sqrt(eigen_valUC[1]); double leastUC = 4*sqrt(eigen_valUC[0]); double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]); double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]); std::string prefix = FeatureDescriptionPrefix(); featureList.push_back(std::make_pair(prefix + "Volume (mesh based)",meshVolume)); featureList.push_back(std::make_pair(prefix + "Surface (mesh based)",meshSurf)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (mesh based)",surfaceToVolume)); featureList.push_back(std::make_pair(prefix + "Sphericity (mesh based)",sphericity)); featureList.push_back(std::make_pair(prefix + "Asphericity (mesh based)", asphericity)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh based)", compactness3)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (mesh based)" ,compactness1)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh based)",compactness2)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh based)", sphericalDisproportion)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (voxel based)", surfaceToVolumePixel)); featureList.push_back(std::make_pair(prefix + "Sphericity (voxel based)", sphericityPixel)); featureList.push_back(std::make_pair(prefix + "Asphericity (voxel based)", asphericityPixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (voxel based)", compactness3Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (voxel based)", compactness1Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (voxel based)", compactness2Pixel)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (voxel based)", sphericalDisproportionPixel)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length",major)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length",minor)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length",least)); featureList.push_back(std::make_pair(prefix + "PCA Elongation",elongation)); featureList.push_back(std::make_pair(prefix + "PCA Flatness",flatness)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length (uncorrected)", majorUC)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length (uncorrected)", minorUC)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length (uncorrected)", leastUC)); featureList.push_back(std::make_pair(prefix + "PCA Elongation (uncorrected)", elongationUC)); featureList.push_back(std::make_pair(prefix + "PCA Flatness (uncorrected)", flatnessUC)); return featureList; } mitk::GIFVolumetricStatistics::FeatureNameListType mitk::GIFVolumetricStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFVolumetricStatistics::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 Features::...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric features...."; } } diff --git a/Modules/Classification/CLUtilities/test/files.cmake b/Modules/Classification/CLUtilities/test/files.cmake index b0f32b97fe..579c0e0670 100644 --- a/Modules/Classification/CLUtilities/test/files.cmake +++ b/Modules/Classification/CLUtilities/test/files.cmake @@ -1,14 +1,18 @@ set(MODULE_TESTS + mitkGIFCooc2Test mitkGIFCurvatureStatisticTest mitkGIFFirstOrderHistogramStatisticsTest + mitkGIFFirstOrderNumericStatisticsTest + mitkGIFFirstOrderStatisticsTest mitkGIFGreyLevelDistanceZoneTest mitkGIFGreyLevelSizeZoneTest mitkGIFImageDescriptionFeaturesTest + mitkGIFIntensityVolumeHistogramTest mitkGIFLocalIntensityTest mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest mitkGIFNeighbouringGreyLevelDependenceFeatureTest mitkGIFVolumetricDensityStatisticsTest mitkGIFVolumetricStatisticsTest #mitkSmoothedClassProbabilitesTest.cpp #mitkGlobalFeaturesTest.cpp ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp new file mode 100644 index 0000000000..ef4dcd4254 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp @@ -0,0 +1,251 @@ +/*=================================================================== + +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 mitkGIFCooc2TestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFCooc2TestSuite); + + MITK_TEST(ImageDescription_PhantomTest_3D); + MITK_TEST(ImageDescription_PhantomTest_2D); + + 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_3D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::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 18 features.", std::size_t(93), featureList.size()); + + // These values are obtained with IBSI (3D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.509, results["Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.574, results["Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.379, results["Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.215, results["Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.641, results["Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.298, results["Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 2.110, results["Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.291, results["Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.118, results["Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.380, results["Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.688, results["Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.856, results["Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.631, results["Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.902, results["Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.057, results["Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.183, results["Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.192, results["Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 17.419, results["Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 147.464, results["Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0288, results["Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.269, results["Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.679, results["Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.306, results["Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (3D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.503, results["Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 3.099, results["Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.399, results["Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 3.056, results["Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.563, results["Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.2859, results["Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 7.072, results["Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.9226, results["Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.303, results["Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.3245, results["Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.6766, results["Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.8506, results["Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.6177, results["Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.8984, results["Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0604, results["Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", 0.157, results["Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.05544, results["Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 7.0728, results["Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 16.6441, results["Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 144.703, results["Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15684, results["Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.519588, results["Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.6808, results["Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 3.0993, results["Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.29699, results["Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::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->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + 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 558 features.", std::size_t(558), featureList.size()); + + // These values are obtained with IBSI + // Standard accuracy is 0.01 + // These values are obtained with IBSI (2D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.512, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.143, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 2.7115, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.2383, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.06426, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.49262, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.28686, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 5.65615, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 1.79494, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.351678, results["SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.19019, results["SliceWise Mean Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.683294, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.8538, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.625003, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.90088, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.055286, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.0173072, results["SliceWise Mean Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.13953, results["SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 5.6561, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 6.97661, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 80.3855, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0340891, results["SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.2625, results["SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.682689, results["SliceWise Mean Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.14343, results["SliceWise Mean Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 2.71158, results["SliceWise Mean Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.13773, results["SliceWise Mean Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (2D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.5188, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.04966, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 2.90159, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.39615, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.28484, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.60319, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.367529, results["SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.27785, results["SliceWise Mean Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.677949, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.851399, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.618737, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.899219, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0566983, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", -.012107, results["SliceWise Mean Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.09437, results["SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 6.99782, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 79.1126, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15512, results["SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.487457, results["SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.689717, results["SliceWise Mean Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.1238, results["SliceWise Mean Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFCooc2 ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp new file mode 100644 index 0000000000..31bac39039 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite); + + 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::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::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 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01); + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 0.83333, results["First Order Numeric::Covered image intensity range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp new file mode 100644 index 0000000000..d6af72b9a8 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp @@ -0,0 +1,112 @@ +/*=================================================================== + +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 mitkGIFFirstOrderStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderStatisticsTestSuite); + + 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::GIFFirstOrderStatistics::Pointer featureCalculator = mitk::GIFFirstOrderStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1); + 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 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean with Large IBSI Phantom Image", 2.15, results["First Order::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Variance with Large IBSI Phantom Image", 3.09, results["First Order::Unbiased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Variance with Large IBSI Phantom Image", 3.05, results["First Order::Biased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Skewness with Large IBSI Phantom Image", 1.08, results["First Order::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Kurtosis with Large IBSI Phantom Image", 2.65, results["First Order::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median with Large IBSI Phantom Image", 1, results["First Order::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Minimum with Large IBSI Phantom Image", 1, results["First Order::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Maximum with Large IBSI Phantom Image", 6, results["First Order::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Range with Large IBSI Phantom Image", 5, results["First Order::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean Absolute Deviation with Large IBSI Phantom Image", 1.55, results["First Order::Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust Mean Absolute Deviation with Large IBSI Phantom Image", 1.11, results["First Order::Robust Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median Absolute Deviation with Large IBSI Phantom Image", 1.15, results["First Order::Median Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order::Coefficient Of Variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.625, results["First Order::Quantile Coefficient Of Dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Energy with Large IBSI Phantom Image", 567, results["First Order::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order::Root Mean Square"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Entropy with Large IBSI Phantom Image", 1.26561, results["First Order::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Excess Kurtosis with Large IBSI Phantom Image", -0.35462, results["First Order::Excess Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Covered image intensity range with Large IBSI Phantom Image", 0.5555555, results["First Order::Covered Image Intensity Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order::Sum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode with Large IBSI Phantom Image", 1, results["First Order::Mode"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode Probability with Large IBSI Phantom Image", 50, results["First Order::Mode Probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Standard deviation with Large IBSI Phantom Image", 1.757, results["First Order::Unbiased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Standard deviation with Large IBSI Phantom Image", 1.74627, results["First Order::Biased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order::Robust Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Number Of Voxels with Large IBSI Phantom Image", 74, results["First Order::Number Of Voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::10th Percentile with Large IBSI Phantom Image", 0.648, results["First Order::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::90th Percentile with Large IBSI Phantom Image", 4.475, results["First Order::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Interquantile Range with Large IBSI Phantom Image", 2.91125, results["First Order::Interquartile Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Space with Large IBSI Phantom Image", 8, results["First Order::Voxel Space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Volume with Large IBSI Phantom Image", 8, results["First Order::Voxel Volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Image Dimension with Large IBSI Phantom Image", 3, results["First Order::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp new file mode 100644 index 0000000000..b0a0eebfa0 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp @@ -0,0 +1,159 @@ +/*=================================================================== + +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 mitkGIFIntensityVolumeHistogramTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE( mitkGIFIntensityVolumeHistogramTestSuite); + + MITK_TEST(ImageDescription_PhantomTest_Large); + MITK_TEST(ImageDescription_PhantomTest_Small); + MITK_TEST(ImageDescription_PhantomTest_2D); + + 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_Large() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::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 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_Small() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::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_Small, m_IBSI_Phantom_Mask_Small); + + 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 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::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->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + 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 42 features.", std::size_t(42), featureList.size()); + + + // These values are obtained by calculating on the features + // Could be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.31539, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.0924106, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 6, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.222979, results["SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 4, results["SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.314325, results["SliceWise Mean Intensity Volume Histogram::Area under IVH curve"], 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.0248178, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.00149203, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 0, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.01414, results["SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.0110923, results["SliceWise Var. Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFIntensityVolumeHistogram) \ No newline at end of file diff --git a/Modules/Core/include/mitkImageDataItem.h b/Modules/Core/include/mitkImageDataItem.h index 02780abe89..6f06aa77fa 100644 --- a/Modules/Core/include/mitkImageDataItem.h +++ b/Modules/Core/include/mitkImageDataItem.h @@ -1,167 +1,167 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef IMAGEDATAITEM_H #define IMAGEDATAITEM_H #include "mitkCommon.h" #include //#include //#include "mitkPixelType.h" #include "mitkImageDescriptor.h" //#include "mitkImageVtkAccessor.h" class vtkImageData; namespace mitk { class PixelType; class ImageVtkReadAccessor; class ImageVtkWriteAccessor; class Image; //##Documentation //## @brief Internal class for managing references on sub-images //## //## ImageDataItem is a container for image data which is used internal in //## mitk::Image to handle the communication between the different data types for images //## used in MITK (ipPicDescriptor, mitk::Image, vtkImageData). Common for these image data //## types is the actual image data, but they differ in representation of pixel type etc. //## The class is also used to convert ipPic images to vtkImageData. //## //## The class is mainly used to extract sub-images inside of mitk::Image, like single slices etc. //## It should not be used outside of this. //## //## @param manageMemory Determines if image data is removed while destruction of ImageDataItem or not. //## @ingroup Data class MITKCORE_EXPORT ImageDataItem : public itk::LightObject { friend class ImageAccessorBase; friend class ImageWriteAccessor; friend class ImageReadAccessor; template friend class ImagePixelAccessor; friend class Image; // template // friend class ImageToItk; public: typedef itk::SmartPointer ImagePointer; typedef itk::SmartPointer ImageConstPointer; mitkClassMacroItkParent(ImageDataItem, itk::LightObject); itkCloneMacro(ImageDataItem); itk::LightObject::Pointer InternalClone() const override; ImageDataItem(const ImageDataItem &aParent, const mitk::ImageDescriptor::Pointer desc, int timestep, unsigned int dimension, void *data = nullptr, bool manageMemory = false, size_t offset = 0); ~ImageDataItem() override; ImageDataItem(const mitk::ImageDescriptor::Pointer desc, int timestep, void *data, bool manageMemory); ImageDataItem(const mitk::PixelType &type, int timestep, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory); ImageDataItem(const ImageDataItem &other); /** \deprecatedSince{2012_09} Please use image accessors instead: See Doxygen/Related-Pages/Concepts/Image. This method can be replaced by ImageWriteAccessor::GetData() or ImageReadAccessor::GetData() */ DEPRECATED(void *GetData() const) { return m_Data; } bool IsComplete() const { return m_IsComplete; } void SetComplete(bool complete) { m_IsComplete = complete; } int GetOffset() const { return m_Offset; } PixelType GetPixelType() const { return *m_PixelType; } void SetTimestep(int t) { m_Timestep = t; } void SetManageMemory(bool b) { m_ManageMemory = b; } int GetDimension() const { return m_Dimension; } int GetDimension(int i) const { int returnValue = 0; // return the true size if dimension available if (i < (int)m_Dimension) returnValue = m_Dimensions[i]; return returnValue; } ImageDataItem::ConstPointer GetParent() const { return m_Parent; } /** * @brief GetVtkImageAccessor Returns a vtkImageDataItem, if none is present, a new one is constructed by the * ConstructVtkImageData method. * Due to historical development of MITK and VTK, the vtkImage origin is explicitly set * to * (0, 0, 0) for 3D images. * See bug 5050 for detailed information. * @return Pointer of type ImageVtkReadAccessor */ ImageVtkReadAccessor *GetVtkImageAccessor(ImageConstPointer) const; ImageVtkWriteAccessor *GetVtkImageAccessor(ImagePointer); // Returns if image data should be deleted on destruction of ImageDataItem. bool GetManageMemory() const { return m_ManageMemory; } virtual void ConstructVtkImageData(ImageConstPointer) const; - unsigned long GetSize() const { return m_Size; } + size_t GetSize() const { return m_Size; } virtual void Modified() const; protected: unsigned char *m_Data; PixelType *m_PixelType; bool m_ManageMemory; mutable vtkImageData *m_VtkImageData; mutable ImageVtkReadAccessor *m_VtkImageReadAccessor; ImageVtkWriteAccessor *m_VtkImageWriteAccessor; int m_Offset; bool m_IsComplete; - unsigned long m_Size; + size_t m_Size; private: void ComputeItemSize(const unsigned int *dimensions, unsigned int dimension); ImageDataItem::ConstPointer m_Parent; unsigned int m_Dimension; unsigned int m_Dimensions[MAX_IMAGE_DIMENSIONS]; int m_Timestep; }; } // namespace mitk #endif /* IMAGEDATAITEM_H */ diff --git a/Modules/Core/include/mitkInteractionConst.h b/Modules/Core/include/mitkInteractionConst.h index 6d3f2948e7..ba5d4483e9 100644 --- a/Modules/Core/include/mitkInteractionConst.h +++ b/Modules/Core/include/mitkInteractionConst.h @@ -1,780 +1,780 @@ /*=================================================================== 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 MITKINTERACTCONST_H #define MITKINTERACTCONST_H //##Documentation //## @file mitkInteractionConst.h //## @brief Constants for most interaction classes, due to the generic StateMachines. //## //## Changes in Type, ButtonState or Key has to be don in mitkEventMapper.cpp, too. //## @ingroup Interaction /*Prefixes for Constants: E = Enumeration EID = EventId's Op = Operations Ac = Action Type_ = Type of Event BS_ = ButtonStates and Buttons Key_ = Keys like in QT */ namespace mitk { // Constants for EventIds; use the according constant to through an event in the code enum EEventIds { - EIDnullptrEVENT = 0, + EIDNULLEVENT = 0, EIDLEFTMOUSEBTN = 1, EIDRIGHTMOUSEBTN = 2, EIDLEFTMOUSEBTNANDSHIFT = 3, EIDMIDDLEMOUSEBTN = 4, EIDLEFTMOUSEBTNANDCTRL = 5, EIDMIDDLEMOUSEBTNANDCTRL = 6, EIDRIGHTMOUSEBTNANDCTRL = 7, EIDLEFTMOUSEBTNDOUBLECLICK = 8, EIDMOUSEWHEEL = 9, EIDLEFTMOUSERELEASE = 505, EIDMIDDLEMOUSERELEASE = 506, EIDRIGHTMOUSERELEASE = 507, EIDLEFTMOUSERELEASEANDSHIFT = 508, EIDMOUSEMOVE = 520, EIDLEFTMOUSEBTNANDMOUSEWHEEL = 521, EIDRIGHTMOUSEBTNANDMOUSEWHEEL = 522, EIDMIDDLEMOUSEBTNANDMOUSEWHEEL = 523, EIDLEFTMOUSEBTNANDMOUSEMOVE = 530, EIDRIGHTMOUSEBTNANDMOUSEMOVE = 531, EIDMIDDLEMOUSEBTNANDMOUSEMOVE = 533, EIDCTRLANDLEFTMOUSEBTNANDMOUSEMOVE = 534, EIDCTRLANDRIGHTMOUSEBTNANDMOUSEMOVE = 535, EIDCTRLANDMIDDLEMOUSEBTNANDMOUSEMOVE = 536, EIDCTRLANDLEFTMOUSEBTNRELEASE = 537, EIDCTRLANDRIGHTMOUSEBTNRELEASE = 538, EIDCTRLANDMIDDLEMOUSEBTNRELEASE = 539, EIDSHIFTANDCTRLANDMIDDLEMOUSEBTN = 540, EIDSHIFTANDLEFTMOUSEBTNANDMOUSEMOVE = 541, EIDSHIFTANDCTRLANDMOUSEMOVE = 542, EIDSHIFTANDCTRLANDMOUSERELEASE = 543, EIDALTANDLEFTMOUSEBTN = 600, EIDALTANDLEFTMOUSEBTNANDMOUSEMOVE = 610, EIDALTANDLEFTMOUSERELEASE = 620, EIDCTRLANDLEFTMOUSEWHEEL = 630, EIDALTANDMOUSEWHEEL = 640, EIDALTANDMIDDLEMOUSEBTN = 641, EIDALTANDMIDDLEMOUSEBTNANDMOVE = 642, EIDALTANDMIDDLEMOUSEBTNRELEASE = 643, EIDALTANDSHIFTANDRIGHTMOUSEBTN = 644, EIDALTANDSHIFTANDRIGHTMOUSEBTNANDMOUSEMOVE = 645, EIDALTANDSHIFTANDRIGHTMOUSEBTNRELEASE = 646, EIDSHIFTANDRIGHTMOUSEPRESS = 2000, EIDSHIFTANDRIGHTMOUSEMOVE = 2001, EIDSHIFTANDRIGHTMOUSERELEASE = 2002, EIDSHIFTANDMIDDLEMOUSEPRESS = 2003, EIDSHIFTANDMIDDLEMOUSEMOVE = 2004, EIDSHIFTANDMIDDLEMOUSERELEASE = 2005, EIDSPACENAVIGATORINPUT = 4001, // 3d Mouse, SpaceNavigator input EIDSPACENAVIGATORKEYDOWN = 4002, // 3d Mouse, KeyDown EIDWIIMOTEINPUT = 4003, // WiiMote input EIDWIIMOTEBUTTON = 4004, // WiiMote home button EIDWIIMOTEBUTTONB = 4005, // WiiMote b button EIDSTRGANDN = 10, EIDSTRGANDE = 11, EIDDELETE = 12, EIDN = 13, EIDESCAPE = 14, EIDP = 15, EIDR = 16, EIDT = 17, EIDS = 18, EIDE = 19, EIDSTRGANDALTANDA = 20, EIDSTRGANDALTANDB = 21, EIDH = 22, EIDRETURN = 23, EIDENTER = 24, EIDSPACE = 25, EIDPLUS = 26, EIDMINUS = 27, EIDSTRGANDALTANDH = 30, EIDSTRGANDALTANDI = 31, EIDSTRGANDALTANDS = 40, EIDALT = 90, EIDSTRGANDB = 91, EIDNEW = 1000, EIDOLD = 1001, EIDFINISHED = 1002, EIDNO = 1003, EIDYES = 1004, EIDSAME = 1005, EIDNOANDLASTOBJECT = 1006, EIDNOANDNOTLASTOBJECT = 1007, EIDLAST = 1008, EIDNOTLAST = 1009, EIDSTSMALERNMINUS1 = 1010, EIDSTLARGERNMINUS1 = 1011, EIDPOSITIONEVENT = 1012, EIDEDIT = 1013, EIDSMALLERN = 1014, EIDEQUALSN = 1015, EIDLARGERN = 1016, EIDEMPTY = 1017, EIDSUBDESELECT = 1020, EIDSMTOSELECTED = 1030, EIDSMTODESELECTED = 1031, EIDTIP = 1050, EIDHEAD = 1051, EIDBODY = 1052, EIDCLEAR = 1100, EIDACTIVATETOOL = 1300, EIDPRINT = 3001, EV_INIT = 5551001, EV_PREVIOUS = 5551002, EV_PATH_COLLECTION_SELECTED = 5551003, EV_NAVIGATION_SELECTED = 5551004, EV_LESS_THEN_MIN_COUNT = 5551005, EV_READY = 5551006, EV_NEXT = 5551007, EV_DONE = 5551008, EV_NEW_LANDMARK = 5551009, EV_REMOVE_LANDMARK = 5551010, EIDINSIDE = 2500, EIDA = 4001, EIDB = 4002, EIDC = 4003, EIDD = 4004, EIDF = 4005, EIDG = 4006, EIDI = 4007, EIDJ = 4008, EIDK = 4009, EIDL = 4010, EIDM = 4011, EIDO = 4012, EIDQ = 4013, EIDU = 4014, EIDV = 4015, EIDW = 4016, EIDX = 4017, EIDY = 4018, EIDZ = 4019, EID1 = 4020, EID2 = 4021, EID3 = 4022, EID4 = 4023, EID5 = 4024, EID6 = 4025, EID7 = 4026, EID8 = 4027, EID9 = 4028, EID0 = 4029, EIDFIGUREHOVER = 12340, EIDNOFIGUREHOVER = 12341 }; //##Constants for Operations //## xomments are always examples of the usage enum EOperations { OpNOTHING = 0, OpTEST = 1, OpNEWCELL = 10, // add a new cell OpADD = 100, // add a point or a vessel OpUNDOADD = 101, OpADDLINE = 1001, // add a line OpINSERT = 200, // insert a point at position OpINSERTLINE = 201, // insert a line at position OpINSERTPOINT = 202, OpCLOSECELL = 250, // close a cell (to a polygon) OpOPENCELL = 251, // close a cell (to a polygon) OpMOVE = 300, // move a point OpMOVELINE = 301, // move a line OpMOVECELL = 302, // move a line OpUNDOMOVE = 303, OpMOVEPOINTUP = 304, OpMOVEPOINTDOWN = 305, OpREMOVE = 400, // remove a point at position OpREMOVELINE = 401, // remove a line at position OpREMOVECELL = 402, // remove a cell OpREMOVEPOINT = 403, OpDELETE = 500, // delete OpDELETELINE = 501, // delete the last line in a cell OpUNDELETE = 502, OpDELETECELL = 505, OpSTATECHANGE = 600, // change a state OpTIMECHANGE = 601, // change a state OpTERMINATE = 666, // change a state OpSELECTPOINT = 700, OpSELECTLINE = 701, OpSELECTCELL = 702, OpSELECTSUBOBJECT = 703, // for VesselGraphInteractor // OpSELECTNEWSUBOBJECT = 704, //for VesselGraphInteractor OpSELECT = 705, OpDESELECTPOINT = 800, OpDESELECTLINE = 801, OpDESELECTCELL = 802, OpDESELECTSUBOBJECT = 803, // for VesselGraphInteractor OpDESELECTALL = 804, // for VesselGraphInteractor OpDESELECT = 805, OpNAVIGATE = 900, OpZOOM = 1000, OpSCALE = 1100, OpROTATE = 1200, OpORIENT = 1201, OpRESTOREPLANEPOSITION = 1202, OpAPPLYTRANSFORMMATRIX = 1203, OpSETPOINTTYPE = 1210, OpMODECHANGE = 1500, OpSENDCOORDINATES = 1600, OpPERIPHERYSEARCH = 2000, // used in VesselGraphInteractor OpROOTSEARCH = 2001, // used in VesselGraphInteractor OpTHICKSTVESSELSEARCH = 2002, // used in VesselGraphInteractor OpSHORTESTPATHSEARCH = 2003, // used in VesselGraphInteractor OpATTRIBUTATION = 2004, // used in VesselGraphInteractor OpDEFAULT = 2006, // used in VesselGraphInteractor OpSURFACECHANGED = 3000, // used for changing polydata in surfaces }; //##Constants for EventMapping... //##connects the statemachine.xml-File with the implemented conditions. //##within one statemachine the choice of the actionconstants is freely //## //## ActionId enum EActions { AcDONOTHING = 0, AcINITNEWOBJECT = 5, AcINITEDITOBJECT = 6, AcINITEDITGROUP = 7, AcINITMOVEMENT = 8, AcINITMOVE = 9, AcINITFOREGROUND = 45, // used in SeedsInteractor for setting the foreground seeds AcINITBACKGROUND = 46, // used in SeedsInteractor for setting the background seeds AcINITNEUTRAL = 47, // used in SeedsInteractor for setting the neutral seeds (rubber) AcINITUPDATE = 1235, // For shape model deformation AcADDPOINT = 10, AcADDPOINTRMB = 6000, // in mitralPointSetInteractor used to set a different type of point AcADD = 11, AcADDLINE = 12, AcADDANDFINISH = 13, AcADDSELECTEDTOGROUP = 64, AcCHECKPOINT = 21, AcCHECKLINE = 22, AcCHECKCELL = 23, AcCHECKELEMENT = 30, // check if there is a element close enough (picking) AcCHECKOBJECT = 31, // check if an object is hit AcCHECKNMINUS1 = 32, // check if the number of elements is equal to N-1 AcCHECKEQUALS1 = 33, // check if the number of elements in the data is equal to 1 AcCHECKNUMBEROFPOINTS = 330, // check the number of elements in the data AcCHECKSELECTED = 34, // check if the given element is selected or not AcCHECKONESELECTED = 340, // check if there is an element that is selected AcCHECKHOVERING = 341, // check if there is an element that is selected AcCHECKGREATERZERO = 35, // check if the current number of elements is greater than 0 AcCHECKGREATERTWO = 36, // check if the current number of elements is greater than two AcCHECKOPERATION = 37, // check if the operation is of one spectial type AcCHECKONESUBINTERACTOR = 38, AcCHECKSUBINTERACTORS = 39, AcFINISHOBJECT = 40, AcFINISHGROUP = 41, AcFINISHMOVEMENT = 42, AcFINISHMOVE = 43, AcFINISH = 44, AcSEARCHOBJECT = 50, AcSEARCHGROUP = 51, AcSEARCHANOTHEROBJECT = 52, // one object is selected and another object is to be added to selection AcSELECTPICKEDOBJECT = 60, // select the picked object and deselect others AcSELECTANOTHEROBJECT = 61, AcSELECTGROUP = 62, AcSELECTALL = 63, AcSELECT = 65, AcSELECTPOINT = 66, AcSELECTLINE = 68, AcSELECTCELL = 67, AcSELECTSUBOBJECT = 69, // used in VesselGraphInteractor AcDESELECTOBJECT = 70, // deselect picked from group AcDESELECTALL = 72, AcDESELECT = 75, AcDESELECTPOINT = 76, AcDESELECTLINE = 78, AcDESELECTCELL = 77, AcNEWPOINT = 80, AcNEWSUBOBJECT = 81, AcMOVEPOINT = 90, AcMOVESELECTED = 91, AcMOVE = 92, AcMOVEPOINTUP = 93, AcMOVEPOINTDOWN = 94, AcREMOVEPOINT = 100, AcREMOVE = 101, AcREMOVELINE = 102, AcREMOVEALL = 103, AcREMOVESELECTEDSUBOBJECT = 104, // used in VesselGraphInteractor AcWHEEL = 105, AcPLUS = 106, AcMINUS = 107, AcDELETEPOINT = 120, AcCLEAR = 130, // clear all elements from a list AcINSERTPOINT = 110, AcINSERTLINE = 111, AC_SET_NEXT_BUTTON_VISIBLE = 5550001, AC_SET_NEXT_BUTTON_INVISIBLE = 5550002, AC_SET_PREVIOUS_BUTTON_VISIBLE = 5550003, AC_SET_PREVIOUS_BUTTON_INVISIBLE = 5550004, AC_SET_ASSISTAND_WIDGET_STECK = 5550005, AC_SETMAX_COUNT_REF_POINTS = 5550006, AC_SET_NEXT_BUTTON_TEXT = 5550007, AC_CHECK_LANDMARK_COUNT = 5550008, AC_SET_DONE_FALSE = 5550009, AC_INIT = 55500010, AC_SET_APPLICATION_SELECTED_FALSE = 55500011, AC_SENSOR_ATTACHED = 55500012, AC_CLOSE_ASSISTENT = 55500013, AC_START_APPLICATION_TEXT = 55500014, AC_START_NAVIGATION = 55500015, AC_START_PATHCOLLECTION = 55500016, AC_LOAD_LANDMARKS = 55500017, AC_CALCULATE_LANDMARK_TRANSFORM = 55500018, AcTERMINATE_INTERACTION = 666, AcTRANSLATESTART = 1000, AcTRANSLATE = 1001, AcSCALESTART = 1002, AcSCALE = 1003, AcROTATESTART = 1004, AcROTATE = 1005, AcINITAFFINEINTERACTIONS = 1006, AcFINISHAFFINEINTERACTIONS = 1007, AcTRANSLATEEND = 1008, AcSCALEEND = 1009, AcROTATEEND = 1010, AcINITZOOM = 1011, AcZOOM = 1012, AcSCROLL = 1013, AcLEVELWINDOW = 1014, AcSCROLLMOUSEWHEEL = 1015, AcSETSTARTPOINT = 1050, AcMODEDESELECT = 1100, // set interactor in not selected mode AcMODESELECT = 1101, // set interactor in selected mode AcMODESUBSELECT = 1102, // set interacor in sub selected mode AcINFORMLISTENERS = 1200, AcASKINTERACTORS = 1201, AcCHECKGREATERONE = 1500, AcCHECKBOUNDINGBOX = 1510, AcFORCESUBINTERACTORS = 1550, AcSENDCOORDINATES = 1600, AcTRANSMITEVENT = 2000, // to transmit an event to a lower Interactor/Statemachine AcPERIPHERYSEARCH = 3000, // used in VesselGraphInteractor AcROOTSEARCH = 3001, // used in VesselGraphInteractor AcTHICKSTVESSELSEARCH = 3002, // used in VesselGraphInteractor AcSHORTESTPATHSEARCH = 3003, // used in VesselGraphInteractor AcSINGLE = 3004, // used in VesselGraphInteractor AcATTRIBUTATION = 3005, // used in VesselGraphInteractor AcDEFAULT = 3007, // used in VesselGraphInteractor AcSETVESSELELEMENT = 3008, // used in VesselGraphInteractor AcCHECKBARRIERSTATUS = 3010, // used in VesselGraphInteractor AcUPDATEMESH = 1234, // For Shape Model Interaction AcINCREASE = 49012, AcDECREASE = 49013, AcMODIFY = 49014, AcUNDOUPDATE = 1236, // For restoring a mesh after an update AcENTEROBJECT = 48000, AcLEAVEOBJECT = 48001, AcSWITCHOBJECT = 48002, AcUPDATELINE = 48003, AcINITLINE = 48004, AcTERMINATELINE = 48005, AcCREATEBOX = 48006, AcCREATEOBJECTFROMLINE = 48007, AcCANCEL = 48008, AcACTIVATETOOL = 48009, AcROTATEAROUNDPOINT1 = 49002, AcROTATEAROUNDPOINT2 = 49003, AcMOVEPOINT1 = 49004, AcMOVEPOINT2 = 49005, AcUPDATEPOINT = 49006, AcUPDATERADIUSMOUSEWHEEL = 49007, AcDISPLAYOPTIONS = 49009, AcCYCLE = 49010, AcACCEPT = 49011, AcONSPACENAVIGATORMOUSEINPUT = 4001, // On input of 3D Mouse AcONPACENAVIGATORKEYDOWN = 4002, // On input of 3D Mouse AcONWIIMOTEINPUT = 4003, // used for wiimote to signal IR input AcRESETVIEW = 4004, // used for wiimote to reset view AcONWIIMOTEBUTTONRELEASED = 4005, // stops the surface interaction AcCHECKPOSITION = 5000, AcINITIALIZECONTOUR = 5001, AcCALCULATENEWSEGMENTATION_SP = 5002, AcINTERACTOR = 5003, AcCALCULATENEWSEGMENTATION_BB = 5004 }; /* //!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!! //EventMechanism: //If you change anything from here on, then change in mitkEventMapper.cpp (Array of constants) as well. //!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!! */ // Type of an Event; enum EEventType { Type_None = 0, // invalid event Type_Timer = 1, // timer event Type_MouseButtonPress = 2, // mouse button pressed Type_MouseButtonRelease = 3, // mouse button released Type_MouseButtonDblClick = 4, // mouse button double click Type_MouseMove = 5, // mouse move Type_KeyPress = 6, // key pressed Type_KeyRelease = 7, // key released Type_FocusIn = 8, // keyboard focus received Type_FocusOut = 9, // keyboard focus lost Type_Enter = 10, // mouse enters widget Type_Leave = 11, // mouse leaves widget Type_Paint = 12, // paint widget Type_Move = 13, // move widget Type_Resize = 14, // resize widget Type_Create = 15, // after object creation Type_Destroy = 16, // during object destruction Type_Show = 17, // widget is shown Type_Hide = 18, // widget is hidden Type_Close = 19, // request to close widget Type_Quit = 20, // request to quit application Type_Reparent = 21, // widget has been reparented Type_ShowMinimized = 22, // widget is shown minimized Type_ShowNormal = 23, // widget is shown normal Type_WindowActivate = 24, // window was activated Type_WindowDeactivate = 25, // window was deactivated Type_ShowToParent = 26, // widget is shown to parent Type_HideToParent = 27, // widget is hidden to parent Type_ShowMaximized = 28, // widget is shown maximized Type_ShowFullScreen = 29, // widget is shown full-screen Type_Accel = 30, // accelerator event Type_Wheel = 31, // wheel event Type_AccelAvailable = 32, // accelerator available event Type_CaptionChange = 33, // caption changed Type_IconChange = 34, // icon changed Type_ParentFontChange = 35, // parent font changed Type_ApplicationFontChange = 36, // application font changed Type_ParentPaletteChange = 37, // parent palette changed Type_ApplicationPaletteChange = 38, // application palette changed Type_PaletteChange = 39, // widget palette changed Type_Clipboard = 40, // internal clipboard event Type_Speech = 42, // reserved for speech input Type_SockAct = 50, // socket activation Type_AccelOverride = 51, // accelerator override event Type_DeferredDelete = 52, // deferred delete event Type_DragEnter = 60, // drag moves into widget Type_DragMove = 61, // drag moves in widget Type_DragLeave = 62, // drag leaves or is cancelled Type_Drop = 63, // actual drop Type_DragResponse = 64, // drag accepted/rejected Type_ChildInserted = 70, // new child widget Type_ChildRemoved = 71, // deleted child widget Type_LayoutHint = 72, // child min/max size changed Type_ShowWindowRequest = 73, // widget's window should be mapped Type_ActivateControl = 80, // ActiveX activation Type_DeactivateControl = 81, // ActiveX deactivation Type_ContextMenu = 82, // context popup menu Type_IMStart = 83, // input method composition start Type_IMCompose = 84, // input method composition Type_IMEnd = 85, // input method composition end Type_Accessibility = 86, // accessibility information is requested Type_TabletMove = 87, // Wacom tablet event Type_LocaleChange = 88, // the system locale changed Type_LanguageChange = 89, // the application language changed Type_LayoutDirectionChange = 90, // the layout direction changed Type_Style = 91, // internal style event Type_TabletPress = 92, // tablet press Type_TabletRelease = 93, // tablet release Type_User = 1000, // first user event id Type_SpaceNavigatorInput = 1094, // 3D mouse input occured Type_SpaceNavigatorKeyDown = 1095, // 3D mouse input occured Type_WiiMoteInput = 1096, // WiiMote input occured Type_WiiMoteButton = 1097, // WiiMote button pressed Type_MaxUser = 65535 }; //##ButtonState // mouse/keyboard state values // QT combinations if MOUSEBUTTONRelease: left MouseButton + ControlButton: 0x201 enum EButtonStates { BS_NoButton = 0x0000, BS_LeftButton = 0x0001, BS_RightButton = 0x0002, BS_MidButton = 0x0004, BS_MouseButtonMask = 0x0007, BS_ShiftButton = 0x0100, BS_ControlButton = 0x0200, BS_AltButton = 0x0400, BS_MetaButton = 0x0800, BS_KeyButtonMask = 0x0f00, BS_Keypad = 0x4000 }; //##Key enum EKeys { Key_Escape = 0x1000, // misc keys Key_Tab = 0x1001, Key_Backtab = 0x1002, Key_BackTab = 0x1002, //= Key_Backtab Key_Backspace = 0x1003, Key_BackSpace = 0x1003, //= Key_Backspace Key_Return = 0x1004, Key_Enter = 0x1005, Key_Insert = 0x1006, Key_Delete = 0x1007, Key_Pause = 0x1008, Key_Print = 0x1009, Key_SysReq = 0x100a, Key_Home = 0x1010, // cursor movement Key_End = 0x1011, Key_Left = 0x1012, Key_Up = 0x1013, Key_Right = 0x1014, Key_Down = 0x1015, Key_Prior = 0x1016, Key_PageUp = 0x1016, //=Key_Prior Key_Next = 0x1017, Key_PageDown = 0x1017, //=Key_Next Key_Shift = 0x1020, // modifiers Key_Control = 0x1021, Key_Meta = 0x1022, Key_Alt = 0x1023, Key_CapsLock = 0x1024, Key_NumLock = 0x1025, Key_ScrollLock = 0x1026, Key_F1 = 0x1030, // function keys Key_F2 = 0x1031, Key_F3 = 0x1032, Key_F4 = 0x1033, Key_F5 = 0x1034, Key_F6 = 0x1035, Key_F7 = 0x1036, Key_F8 = 0x1037, Key_F9 = 0x1038, Key_F10 = 0x1039, Key_F11 = 0x103a, Key_F12 = 0x103b, Key_F13 = 0x103c, Key_F14 = 0x103d, Key_F15 = 0x103e, Key_F16 = 0x103f, Key_F17 = 0x1040, Key_F18 = 0x1041, Key_F19 = 0x1042, Key_F20 = 0x1043, Key_F21 = 0x1044, Key_F22 = 0x1045, Key_F23 = 0x1046, Key_F24 = 0x1047, Key_F25 = 0x1048, // F25 .. F35 only on X11 Key_F26 = 0x1049, Key_F27 = 0x104a, Key_F28 = 0x104b, Key_F29 = 0x104c, Key_F30 = 0x104d, Key_F31 = 0x104e, Key_F32 = 0x104f, Key_F33 = 0x1050, Key_F34 = 0x1051, Key_F35 = 0x1052, Key_Super_L = 0x1053, // extra keys Key_Super_R = 0x1054, Key_Menu = 0x1055, Key_Hyper_L = 0x1056, Key_Hyper_R = 0x1057, Key_Help = 0x1058, // International input method support (X keycode - = 0xEE00) // Only interesting if you are writing your own input method Key_Muhenkan = 0x1122, // Cancel Conversion Key_Henkan = 0x1123, // Start/Stop Conversion Key_Hiragana_Katakana = 0x1127, // Hiragana/Katakana toggle Key_Zenkaku_Hankaku = 0x112A, // Zenkaku/Hankaku toggle Key_Space = 0x20, // 7 bit printable ASCII Key_Any = 0x20, //= Key_Space Key_Exclam = 0x21, Key_QuoteDbl = 0x22, Key_NumberSign = 0x23, Key_Dollar = 0x24, Key_Percent = 0x25, Key_Ampersand = 0x26, Key_Apostrophe = 0x27, Key_ParenLeft = 0x28, Key_ParenRight = 0x29, Key_Asterisk = 0x2a, Key_Plus = 0x2b, Key_Comma = 0x2c, Key_Minus = 0x2d, Key_Period = 0x2e, Key_Slash = 0x2f, Key_0 = 0x30, Key_1 = 0x31, Key_2 = 0x32, Key_3 = 0x33, Key_4 = 0x34, Key_5 = 0x35, Key_6 = 0x36, Key_7 = 0x37, Key_8 = 0x38, Key_9 = 0x39, Key_Colon = 0x3a, Key_Semicolon = 0x3b, Key_Less = 0x3c, Key_Equal = 0x3d, Key_Greater = 0x3e, Key_Question = 0x3f, Key_At = 0x40, Key_A = 0x41, Key_B = 0x42, Key_C = 0x43, Key_D = 0x44, Key_E = 0x45, Key_F = 0x46, Key_G = 0x47, Key_H = 0x48, Key_I = 0x49, Key_J = 0x4a, Key_K = 0x4b, Key_L = 0x4c, Key_M = 0x4d, Key_N = 0x4e, Key_O = 0x4f, Key_P = 0x50, Key_Q = 0x51, Key_R = 0x52, Key_S = 0x53, Key_T = 0x54, Key_U = 0x55, Key_V = 0x56, Key_W = 0x57, Key_X = 0x58, Key_Y = 0x59, Key_Z = 0x5a, Key_BracketLeft = 0x5b, Key_Backslash = 0x5c, Key_BracketRight = 0x5d, Key_AsciiCircum = 0x5e, Key_Underscore = 0x5f, Key_QuoteLeft = 0x60, Key_BraceLeft = 0x7b, Key_Bar = 0x7c, Key_BraceRight = 0x7d, Key_AsciiTilde = 0x7e, Key_nobreakspace = 0x0a0, Key_exclamdown = 0x0a1, Key_cent = 0x0a2, Key_sterling = 0x0a3, Key_currency = 0x0a4, Key_yen = 0x0a5, Key_brokenbar = 0x0a6, Key_section = 0x0a7, Key_diaeresis = 0x0a8, Key_copyright = 0x0a9, Key_ordfeminine = 0x0aa, Key_guillemotleft = 0x0ab, // left angle quotation mark Key_notsign = 0x0ac, Key_hyphen = 0x0ad, Key_registered = 0x0ae, Key_macron = 0x0af, Key_degree = 0x0b0, Key_plusminus = 0x0b1, Key_twosuperior = 0x0b2, Key_threesuperior = 0x0b3, Key_acute = 0x0b4, Key_mu = 0x0b5, Key_paragraph = 0x0b6, Key_periodcentered = 0x0b7, Key_cedilla = 0x0b8, Key_onesuperior = 0x0b9, Key_masculine = 0x0ba, Key_guillemotright = 0x0bb, // right angle quotation mark Key_onequarter = 0x0bc, Key_onehalf = 0x0bd, Key_threequarters = 0x0be, Key_questiondown = 0x0bf, Key_Agrave = 0x0c0, Key_Aacute = 0x0c1, Key_Acircumflex = 0x0c2, Key_Atilde = 0x0c3, Key_Adiaeresis = 0x0c4, Key_Aring = 0x0c5, Key_AE = 0x0c6, Key_Ccedilla = 0x0c7, Key_Egrave = 0x0c8, Key_Eacute = 0x0c9, Key_Ecircumflex = 0x0ca, Key_Ediaeresis = 0x0cb, Key_Igrave = 0x0cc, Key_Iacute = 0x0cd, Key_Icircumflex = 0x0ce, Key_Idiaeresis = 0x0cf, Key_ETH = 0x0d0, Key_Ntilde = 0x0d1, Key_Ograve = 0x0d2, Key_Oacute = 0x0d3, Key_Ocircumflex = 0x0d4, Key_Otilde = 0x0d5, Key_Odiaeresis = 0x0d6, Key_multiply = 0x0d7, Key_Ooblique = 0x0d8, Key_Ugrave = 0x0d9, Key_Uacute = 0x0da, Key_Ucircumflex = 0x0db, Key_Udiaeresis = 0x0dc, Key_Yacute = 0x0dd, Key_THORN = 0x0de, Key_ssharp = 0x0df, Key_agrave = 0x0e0, Key_aacute = 0x0e1, Key_acircumflex = 0x0e2, Key_atilde = 0x0e3, Key_adiaeresis = 0x0e4, Key_aring = 0x0e5, Key_ae = 0x0e6, Key_ccedilla = 0x0e7, Key_egrave = 0x0e8, Key_eacute = 0x0e9, Key_ecircumflex = 0x0ea, Key_ediaeresis = 0x0eb, Key_igrave = 0x0ec, Key_iacute = 0x0ed, Key_icircumflex = 0x0ee, Key_idiaeresis = 0x0ef, Key_eth = 0x0f0, Key_ntilde = 0x0f1, Key_ograve = 0x0f2, Key_oacute = 0x0f3, Key_ocircumflex = 0x0f4, Key_otilde = 0x0f5, Key_odiaeresis = 0x0f6, Key_division = 0x0f7, Key_oslash = 0x0f8, Key_ugrave = 0x0f9, Key_uacute = 0x0fa, Key_ucircumflex = 0x0fb, Key_udiaeresis = 0x0fc, Key_yacute = 0x0fd, Key_thorn = 0x0fe, Key_ydiaeresis = 0x0ff, Key_unknown = 0xffff, Key_none = 0xffff //= Key_unknown }; } // namespace mitk #endif // ifndef MITKINTERACTCONST_H diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Modules/Core/test/mitkImageDataItemTest.cpp index b332e9eca7..735c88d1ae 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Modules/Core/test/mitkImageDataItemTest.cpp @@ -1,32 +1,74 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#include "mitkImage.h" -#include "mitkImageDataItem.h" +#include -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +#include + +#include +#include +#include + +class mitkImageDataItemTestSuite : public mitk::TestFixture { - auto pixels = new unsigned long[100]; - void *data = pixels; + 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; - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; + CPPUNIT_ASSERT(writeAccess.GetData() != nullptr); + auto* accessCheck = voxelEnd - 1; + *accessCheck = 1; + } + catch (const itk::MemoryAllocationError& e) + { + MITK_ERROR << e.what(); + exit(77); + } + } +}; - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +MITK_TEST_SUITE_REGISTRATION(mitkImageDataItem) diff --git a/Modules/DICOMReader/src/mitkDICOMTagBasedSorter.cpp b/Modules/DICOMReader/src/mitkDICOMTagBasedSorter.cpp index 08512c2a75..b82d8abdeb 100644 --- a/Modules/DICOMReader/src/mitkDICOMTagBasedSorter.cpp +++ b/Modules/DICOMReader/src/mitkDICOMTagBasedSorter.cpp @@ -1,596 +1,599 @@ /*=================================================================== 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 "mitkDICOMTagBasedSorter.h" #include #include mitk::DICOMTagBasedSorter::CutDecimalPlaces ::CutDecimalPlaces(unsigned int precision) :m_Precision(precision) { } mitk::DICOMTagBasedSorter::CutDecimalPlaces ::CutDecimalPlaces(const CutDecimalPlaces& other) :m_Precision(other.m_Precision) { } std::string mitk::DICOMTagBasedSorter::CutDecimalPlaces ::operator()(const std::string& input) const { // be a bit tolerant for tags such as image orientation orienatation, let only the first few digits matter (http://bugs.mitk.org/show_bug.cgi?id=12263) // iterate all fields, convert each to a number, cut this number as configured, then return a concatenated string with all cut-off numbers std::ostringstream resultString; resultString.str(std::string()); resultString.clear(); resultString.setf(std::ios::fixed, std::ios::floatfield); resultString.precision(m_Precision); std::stringstream ss(input); ss.str(input); ss.clear(); std::string item; double number(0); std::istringstream converter(item); while (std::getline(ss, item, '\\')) { converter.str(item); converter.clear(); if (converter >> number && converter.eof()) { // converted to double resultString << number; } else { // did not convert to double resultString << item; // just paste the unmodified string } if (!ss.eof()) { resultString << "\\"; } } return resultString.str(); } mitk::DICOMTagBasedSorter::TagValueProcessor* mitk::DICOMTagBasedSorter::CutDecimalPlaces ::Clone() const { return new CutDecimalPlaces(*this); } unsigned int mitk::DICOMTagBasedSorter::CutDecimalPlaces ::GetPrecision() const { return m_Precision; } mitk::DICOMTagBasedSorter ::DICOMTagBasedSorter() :DICOMDatasetSorter() ,m_StrictSorting(m_DefaultStrictSorting) ,m_ExpectDistanceOne(m_DefaultExpectDistanceOne) { } mitk::DICOMTagBasedSorter ::~DICOMTagBasedSorter() { for(auto ti = m_TagValueProcessor.cbegin(); ti != m_TagValueProcessor.cend(); ++ti) { delete ti->second; } } mitk::DICOMTagBasedSorter ::DICOMTagBasedSorter(const DICOMTagBasedSorter& other ) :DICOMDatasetSorter(other) ,m_DistinguishingTags( other.m_DistinguishingTags ) ,m_SortCriterion( other.m_SortCriterion ) ,m_StrictSorting( other.m_StrictSorting ) ,m_ExpectDistanceOne( other.m_ExpectDistanceOne ) { for(auto ti = other.m_TagValueProcessor.cbegin(); ti != other.m_TagValueProcessor.cend(); ++ti) { m_TagValueProcessor[ti->first] = ti->second->Clone(); } } mitk::DICOMTagBasedSorter& mitk::DICOMTagBasedSorter ::operator=(const DICOMTagBasedSorter& other) { if (this != &other) { DICOMDatasetSorter::operator=(other); m_DistinguishingTags = other.m_DistinguishingTags; m_SortCriterion = other.m_SortCriterion; m_StrictSorting = other.m_StrictSorting; m_ExpectDistanceOne = other.m_ExpectDistanceOne; for(auto ti = other.m_TagValueProcessor.cbegin(); ti != other.m_TagValueProcessor.cend(); ++ti) { m_TagValueProcessor[ti->first] = ti->second->Clone(); } } return *this; } bool mitk::DICOMTagBasedSorter ::operator==(const DICOMDatasetSorter& other) const { if (const auto* otherSelf = dynamic_cast(&other)) { if (this->m_StrictSorting != otherSelf->m_StrictSorting) return false; if (this->m_ExpectDistanceOne != otherSelf->m_ExpectDistanceOne) return false; bool allTagsPresentAndEqual(true); if (this->m_DistinguishingTags.size() != otherSelf->m_DistinguishingTags.size()) return false; for (auto myTag = this->m_DistinguishingTags.cbegin(); myTag != this->m_DistinguishingTags.cend(); ++myTag) { allTagsPresentAndEqual &= (std::find( otherSelf->m_DistinguishingTags.cbegin(), otherSelf->m_DistinguishingTags.cend(), *myTag ) != otherSelf->m_DistinguishingTags.cend()); // other contains this tags // since size is equal, we don't need to check the inverse } if (!allTagsPresentAndEqual) return false; if (this->m_SortCriterion.IsNotNull() && otherSelf->m_SortCriterion.IsNotNull()) { return *(this->m_SortCriterion) == *(otherSelf->m_SortCriterion); } else { return this->m_SortCriterion.IsNull() && otherSelf->m_SortCriterion.IsNull(); } } else { return false; } } void mitk::DICOMTagBasedSorter ::PrintConfiguration(std::ostream& os, const std::string& indent) const { os << indent << "Tag based sorting " << "(strict=" << (m_StrictSorting?"true":"false") << ", expectDistanceOne=" << (m_ExpectDistanceOne?"true":"false") << "):" << std::endl; for (auto tagIter = m_DistinguishingTags.begin(); tagIter != m_DistinguishingTags.end(); ++tagIter) { os << indent << " Split on "; tagIter->Print(os); os << std::endl; } DICOMSortCriterion::ConstPointer crit = m_SortCriterion.GetPointer(); while (crit.IsNotNull()) { os << indent << " Sort by "; crit->Print(os); os << std::endl; crit = crit->GetSecondaryCriterion(); } } void mitk::DICOMTagBasedSorter ::SetStrictSorting(bool strict) { m_StrictSorting = strict; } bool mitk::DICOMTagBasedSorter ::GetStrictSorting() const { return m_StrictSorting; } void mitk::DICOMTagBasedSorter ::SetExpectDistanceOne(bool strict) { m_ExpectDistanceOne = strict; } bool mitk::DICOMTagBasedSorter ::GetExpectDistanceOne() const { return m_ExpectDistanceOne; } mitk::DICOMTagList mitk::DICOMTagBasedSorter ::GetTagsOfInterest() { DICOMTagList allTags = m_DistinguishingTags; - const DICOMTagList sortingRelevantTags = m_SortCriterion->GetAllTagsOfInterest(); - allTags.insert( allTags.end(), sortingRelevantTags.cbegin(), sortingRelevantTags.cend() ); // append + if (m_SortCriterion.IsNotNull()) + { + const DICOMTagList sortingRelevantTags = m_SortCriterion->GetAllTagsOfInterest(); + allTags.insert( allTags.end(), sortingRelevantTags.cbegin(), sortingRelevantTags.cend() ); // append + } return allTags; } mitk::DICOMTagList mitk::DICOMTagBasedSorter ::GetDistinguishingTags() const { return m_DistinguishingTags; } const mitk::DICOMTagBasedSorter::TagValueProcessor* mitk::DICOMTagBasedSorter ::GetTagValueProcessorForDistinguishingTag(const DICOMTag& tag) const { auto loc = m_TagValueProcessor.find(tag); if (loc != m_TagValueProcessor.cend()) { return loc->second; } else { return nullptr; } } void mitk::DICOMTagBasedSorter ::AddDistinguishingTag( const DICOMTag& tag, TagValueProcessor* tagValueProcessor ) { m_DistinguishingTags.push_back(tag); m_TagValueProcessor[tag] = tagValueProcessor; } void mitk::DICOMTagBasedSorter ::SetSortCriterion( DICOMSortCriterion::ConstPointer criterion ) { m_SortCriterion = criterion; } mitk::DICOMSortCriterion::ConstPointer mitk::DICOMTagBasedSorter ::GetSortCriterion() const { return m_SortCriterion; } void mitk::DICOMTagBasedSorter ::Sort() { // 1. split // 2. sort each group GroupIDToListType groups = this->SplitInputGroups(); GroupIDToListType& sortedGroups = this->SortGroups( groups ); // 3. define output this->SetNumberOfOutputs(sortedGroups.size()); unsigned int outputIndex(0); for (auto groupIter = sortedGroups.cbegin(); groupIter != sortedGroups.cend(); ++outputIndex, ++groupIter) { this->SetOutput(outputIndex, groupIter->second); } } std::string mitk::DICOMTagBasedSorter ::BuildGroupID( DICOMDatasetAccess* dataset ) { // just concatenate all tag values assert(dataset); std::stringstream groupID; groupID << "g"; for (auto tagIter = m_DistinguishingTags.cbegin(); tagIter != m_DistinguishingTags.cend(); ++tagIter) { groupID << tagIter->GetGroup() << tagIter->GetElement(); // make group/element part of the id to cover empty tags DICOMDatasetFinding rawTagValue = dataset->GetTagValueAsString(*tagIter); std::string processedTagValue; if ( m_TagValueProcessor[*tagIter] != nullptr && rawTagValue.isValid) { processedTagValue = (*m_TagValueProcessor[*tagIter])(rawTagValue.value); } else { processedTagValue = rawTagValue.value; } groupID << processedTagValue; } // shorten ID? return groupID.str(); } mitk::DICOMTagBasedSorter::GroupIDToListType mitk::DICOMTagBasedSorter ::SplitInputGroups() { DICOMDatasetList input = GetInput(); // copy GroupIDToListType listForGroupID; for (auto dsIter = input.cbegin(); dsIter != input.cend(); ++dsIter) { DICOMDatasetAccess* dataset = *dsIter; assert(dataset); std::string groupID = this->BuildGroupID( dataset ); MITK_DEBUG << "Group ID for for " << dataset->GetFilenameIfAvailable() << ": " << groupID; listForGroupID[groupID].push_back(dataset); } MITK_DEBUG << "After tag based splitting: " << listForGroupID.size() << " groups"; return listForGroupID; } mitk::DICOMTagBasedSorter::GroupIDToListType& mitk::DICOMTagBasedSorter ::SortGroups(GroupIDToListType& groups) { if (m_SortCriterion.IsNotNull()) { /* Three steps here: 1. sort within each group - this may result in orders such as 1 2 3 4 6 7 8 10 12 13 14 2. create new groups by enforcing consecutive order within each group - resorts above example like 1 2 3 4 ; 6 7 8 ; 10 ; 12 13 14 3. sort all of the groups (not WITHIN each group) by their first frame - if earlier "distinguish" steps created groups like 6 7 8 ; 1 2 3 4 ; 10, then this step would sort them like 1 2 3 4 ; 6 7 8 ; 10 */ // Step 1: sort within the groups // for each output // sort by all configured tags, use secondary tags when equal or empty // make configurable: // - sorting order (ascending, descending) // - sort numerically // - ... ? unsigned int groupIndex(0); for (auto gIter = groups.begin(); gIter != groups.end(); ++groupIndex, ++gIter) { DICOMDatasetList& dsList = gIter->second; #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << " --------------------------------------------------------------------------------"; MITK_DEBUG << " DICOMTagBasedSorter before sorting group : " << groupIndex; for (auto oi = dsList.begin(); oi != dsList.cend(); ++oi) { MITK_DEBUG << " INPUT : " << (*oi)->GetFilenameIfAvailable(); } #endif // #ifdef MBILOG_ENABLE_DEBUG std::sort( dsList.begin(), dsList.end(), ParameterizedDatasetSort( m_SortCriterion ) ); #ifdef MBILOG_ENABLE_DEBUG MITK_DEBUG << " --------------------------------------------------------------------------------"; MITK_DEBUG << " DICOMTagBasedSorter after sorting group : " << groupIndex; for (auto oi = dsList.cbegin(); oi != dsList.cend(); ++oi) { MITK_DEBUG << " OUTPUT : " << (*oi)->GetFilenameIfAvailable(); } MITK_DEBUG << " --------------------------------------------------------------------------------"; #endif // MBILOG_ENABLE_DEBUG } GroupIDToListType consecutiveGroups; if (m_StrictSorting) { // Step 2: create new groups by enforcing consecutive order within each group unsigned int groupIndex(0); for (auto gIter = groups.begin(); gIter != groups.end(); ++gIter) { std::stringstream groupKey; groupKey << std::setfill('0') << std::setw(6) << groupIndex++; DICOMDatasetList& dsList = gIter->second; DICOMDatasetAccess* previousDS(nullptr); unsigned int dsIndex(0); double constantDistance(0.0); bool constantDistanceInitialized(false); for (auto dataset = dsList.cbegin(); dataset != dsList.cend(); ++dsIndex, ++dataset) { if (dsIndex >0) // ignore the first dataset, we cannot check any distances yet.. { // for the second and every following dataset: // let the sorting criterion calculate a "distance" // if the distance is not 1, split off a new group! const double currentDistance = m_SortCriterion->NumericDistance(previousDS, *dataset); if (constantDistanceInitialized) { if (fabs(currentDistance - constantDistance) < fabs(constantDistance * 0.01)) // ok, deviation of up to 1% of distance is tolerated { // nothing to do, just ok MITK_DEBUG << "Checking currentDistance==" << currentDistance << ": small enough"; } //else if (currentDistance < mitk::eps) // close enough to 0 else { MITK_DEBUG << "Split consecutive group at index " << dsIndex << " (current distance " << currentDistance << ", constant distance " << constantDistance << ")"; // split! this is done by simply creating a new group (key) groupKey.str(std::string()); groupKey.clear(); groupKey << std::setfill('0') << std::setw(6) << groupIndex++; } } else { // second slice: learn about the expected distance! // heuristic: if distance is an integer, we check for a special case: // if the distance is integer and not 1/-1, then we assume // a missing slice right after the first slice // ==> split off slices // in all other cases: second dataset at this position, no need to split already, we are still learning about the images // addition to the above: when sorting by imagepositions, a distance other than 1 between the first two slices is // not unusual, actually expected... then we should not split if (m_ExpectDistanceOne) { if ((currentDistance - (int)currentDistance == 0.0) && fabs(currentDistance) != 1.0) // exact comparison. An integer should not be expressed as 1.000000000000000000000000001! { MITK_DEBUG << "Split consecutive group at index " << dsIndex << " (special case: expected distance 1 exactly)"; groupKey.str(std::string()); groupKey.clear(); groupKey << std::setfill('0') << std::setw(6) << groupIndex++; } } MITK_DEBUG << "Initialize strict distance to currentDistance=" << currentDistance; constantDistance = currentDistance; constantDistanceInitialized = true; } } consecutiveGroups[groupKey.str()].push_back(*dataset); previousDS = *dataset; } } } else { consecutiveGroups = groups; } // Step 3: sort all of the groups (not WITHIN each group) by their first frame /* build a list-1 of datasets with the first dataset one of each group sort this list-1 build a new result list-2: - iterate list-1, for each dataset - find the group that contains this dataset - add this group as the next element to list-2 return list-2 as the sorted output */ DICOMDatasetList firstSlices; for (auto gIter = consecutiveGroups.cbegin(); gIter != consecutiveGroups.cend(); ++gIter) { assert(!gIter->second.empty()); firstSlices.push_back(gIter->second.front()); } std::sort( firstSlices.begin(), firstSlices.end(), ParameterizedDatasetSort( m_SortCriterion ) ); GroupIDToListType sortedResultBlocks; unsigned int groupKeyValue(0); for (auto firstSlice = firstSlices.cbegin(); firstSlice != firstSlices.cend(); ++firstSlice) { for (auto gIter = consecutiveGroups.cbegin(); gIter != consecutiveGroups.cend(); ++groupKeyValue, ++gIter) { if (gIter->second.front() == *firstSlice) { std::stringstream groupKey; groupKey << std::setfill('0') << std::setw(6) << groupKeyValue; // try more than 999,999 groups and you are doomed (your application already is) sortedResultBlocks[groupKey.str()] = gIter->second; } } } groups = sortedResultBlocks; } #ifdef MBILOG_ENABLE_DEBUG unsigned int groupIndex( 0 ); for ( auto gIter = groups.begin(); gIter != groups.end(); ++groupIndex, ++gIter ) { DICOMDatasetList& dsList = gIter->second; MITK_DEBUG << " --------------------------------------------------------------------------------"; MITK_DEBUG << " DICOMTagBasedSorter after sorting group : " << groupIndex; for ( auto oi = dsList.begin(); oi != dsList.end(); ++oi ) { MITK_DEBUG << " OUTPUT : " << ( *oi )->GetFilenameIfAvailable(); } MITK_DEBUG << " --------------------------------------------------------------------------------"; } #endif // MBILOG_ENABLE_DEBUG return groups; } mitk::DICOMTagBasedSorter::ParameterizedDatasetSort ::ParameterizedDatasetSort(DICOMSortCriterion::ConstPointer criterion) :m_SortCriterion(criterion) { } bool mitk::DICOMTagBasedSorter::ParameterizedDatasetSort ::operator() (const mitk::DICOMDatasetAccess* left, const mitk::DICOMDatasetAccess* right) { assert(left); assert(right); assert(m_SortCriterion.IsNotNull()); return m_SortCriterion->IsLeftBeforeRight(left, right); } diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionImageDicomReaderService.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionImageDicomReaderService.cpp index d2ff95a095..ede4fc7775 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionImageDicomReaderService.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionImageDicomReaderService.cpp @@ -1,337 +1,326 @@ /*=================================================================== 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 __mitkDiffusionImageDicomReaderService_cpp #define __mitkDiffusionImageDicomReaderService_cpp #include "mitkDiffusionImageDicomReaderService.h" #include #include // Diffusion properties #include #include #include #include #include #include #include "itksys/SystemTools.hxx" #include "itkImageFileReader.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include "mitkCustomMimeType.h" #include "mitkDiffusionCoreIOMimeTypes.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { DiffusionImageDicomReaderService:: DiffusionImageDicomReaderService(const DiffusionImageDicomReaderService & other) : AbstractFileReader(other) { } DiffusionImageDicomReaderService* DiffusionImageDicomReaderService::Clone() const { return new DiffusionImageDicomReaderService(*this); } DiffusionImageDicomReaderService:: ~DiffusionImageDicomReaderService() {} DiffusionImageDicomReaderService:: DiffusionImageDicomReaderService() : mitk::AbstractFileReader( CustomMimeType( mitk::DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE() ), mitk::DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE_DESCRIPTION() ) { Options defaultOptions; defaultOptions["Load recursive"] = false; defaultOptions["Split mosaic"] = true; this->SetDefaultOptions(defaultOptions); m_ServiceReg = this->RegisterService(); } std::vector > DiffusionImageDicomReaderService::Read() { return InternalRead(); } std::vector > DiffusionImageDicomReaderService::InternalRead() { std::vector > result_images; OutputType::Pointer outputForCache = OutputType::New(); if ( this->GetInputLocation() == "") { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, the filename to be read is empty!"); } else { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } try { Options options = this->GetOptions(); bool load_recursive = us::any_cast(options["Load recursive"]); bool split_mosaic = us::any_cast(options["Split mosaic"]); gdcm::Directory::FilenamesType complete_list; std::string folderName = itksys::SystemTools::GetFilenamePath( this->GetInputLocation() ); if( load_recursive ) { std::string subdir_prefix = ""; itksys::Directory rootdir; rootdir.Load( folderName.c_str() ); for( unsigned int idx=0; idxAddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0010) ); // Number of Rows tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0011) ); // Number of Columns tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0030) ); // Pixel Spacing tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0037) ); // Image Orientation (Patient) // TODO add tolerance parameter (l. 1572 of original code) // TODO handle as real vectors! cluster with configurable errors! tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x000e) ); // Series Instance UID tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0018, 0x0050) ); // Slice Thickness tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0028, 0x0008) ); // Number of Frames //tagSorter->AddDistinguishingTag( mitk::DICOMTag(0x0020, 0x0052) ); // Frame of Reference UID - // gdcmReader->AddSortingElement( tagSorter ); - //mitk::DICOMFileReaderTestHelper::TestOutputsContainInputs( gdcmReader ); - - mitk::DICOMSortCriterion::ConstPointer sorting = - mitk::SortByImagePositionPatient::New( // Image Position (Patient) - //mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0013), // instance number - mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0012), // aqcuisition number - mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0032), // aqcuisition time - mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0018, 0x1060), // trigger time - mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0018) // SOP instance UID (last resort, not really meaningful but decides clearly) - ).GetPointer() - ).GetPointer() - ).GetPointer() - ).GetPointer() - // ).GetPointer() - ).GetPointer(); + auto tag_sop_instance_uid = mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0018), nullptr ); // SOP instance UID (last resort, not really meaningful but decides clearly) + auto tag_trigger_time = mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0018, 0x1060), tag_sop_instance_uid.GetPointer() ); // trigger time + auto tag_aqcuisition_time = mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0008, 0x0032), tag_trigger_time.GetPointer()); // aqcuisition time + auto tag_aqcuisition_number = mitk::DICOMSortByTag::New( mitk::DICOMTag(0x0020, 0x0012), tag_aqcuisition_time.GetPointer()); // aqcuisition number + mitk::DICOMSortCriterion::ConstPointer sorting = mitk::SortByImagePositionPatient::New(tag_aqcuisition_number.GetPointer()).GetPointer(); tagSorter->SetSortCriterion( sorting ); // mosaic gdcmReader->SetResolveMosaic( split_mosaic ); gdcmReader->AddSortingElement( tagSorter ); gdcmReader->SetInputFiles( complete_list ); try { gdcmReader->AnalyzeInputFiles(); } catch( const itk::ExceptionObject &e) { MITK_ERROR << "Failed to analyze data. " << e.what(); } catch( const std::exception &se) { MITK_ERROR << "Std Exception " << se.what(); } gdcmReader->LoadImages(); for( unsigned int o = 0; o < gdcmReader->GetNumberOfOutputs(); o++ ) { mitk::Image::Pointer loaded_image = gdcmReader->GetOutput(o).GetMitkImage(); StringProperty::Pointer nameProp; if (gdcmReader->GetSeriesName(o)!="-") nameProp = StringProperty::New(gdcmReader->GetSeriesName(o)); else if (gdcmReader->GetStudyName(o)!="-") nameProp = StringProperty::New(gdcmReader->GetStudyName(o)); else nameProp = StringProperty::New(folderName); loaded_image->SetProperty("name", nameProp); std::string val = "-"; if (gdcmReader->patient_ids().size()>o) { val = gdcmReader->patient_ids().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.patient_id",val.c_str()); } if (gdcmReader->patient_names().size()>o) { val = gdcmReader->patient_names().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.patient_name",val.c_str()); } if (gdcmReader->study_instance_uids().size()>o) { val = gdcmReader->study_instance_uids().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.study_instance_uid",val.c_str()); } if (gdcmReader->series_instance_uids().size()>o) { val = gdcmReader->series_instance_uids().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.series_instance_uid",val.c_str()); } if (gdcmReader->sop_instance_uids().size()>o) { val = gdcmReader->sop_instance_uids().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.sop_instance_uid",val.c_str()); } if (gdcmReader->frame_of_reference_uids().size()>o) { val = gdcmReader->frame_of_reference_uids().at(o); loaded_image->GetPropertyList()->SetStringProperty("DICOM.frame_of_reference_uid",val.c_str()); } result_images.push_back(loaded_image.GetPointer()); } // Since we have already read the tree, we can store it in a cache variable // so that it can be assigned to the DataObject in GenerateData(); m_OutputCache = outputForCache; m_CacheTime.Modified(); try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } } catch(std::exception& e) { try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } MITK_INFO << "Std::Exception while reading file!!"; MITK_INFO << e.what(); throw itk::ImageFileReaderException(__FILE__, __LINE__, e.what()); } catch(...) { try { setlocale(LC_ALL, currLocale.c_str()); } catch(...) { MITK_INFO << "Could not reset locale " << currLocale; } MITK_INFO << "Exception while reading file!!"; throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, an error occurred while reading the requested vessel tree file!"); } } return result_images; } } //namespace MITK #endif diff --git a/Modules/IGT/IO/mitkNavigationToolReader.cpp b/Modules/IGT/IO/mitkNavigationToolReader.cpp index 122866a5f9..4587e31948 100644 --- a/Modules/IGT/IO/mitkNavigationToolReader.cpp +++ b/Modules/IGT/IO/mitkNavigationToolReader.cpp @@ -1,272 +1,282 @@ /*=================================================================== 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. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolReader.h" #include "mitkTrackingTypes.h" #include #include //All Tracking devices, which should be available by default #include "mitkNDIAuroraTypeInformation.h" #include "mitkNDIPolarisTypeInformation.h" #include "mitkVirtualTrackerTypeInformation.h" #include "mitkMicronTrackerTypeInformation.h" #include "mitkNPOptitrackTrackingTypeInformation.h" #include "mitkOpenIGTLinkTypeInformation.h" #include "mitkUnspecifiedTrackingTypeInformation.h" mitk::NavigationToolReader::NavigationToolReader() { m_ToolfilePath = mitk::IOUtil::GetTempPath() + Poco::Path::separator() + "IGT_Toolfiles" + Poco::Path::separator(); } mitk::NavigationToolReader::~NavigationToolReader() { } mitk::NavigationTool::Pointer mitk::NavigationToolReader::DoRead(std::string filename) { //decompress all files into a temporary directory std::ifstream file(filename.c_str(), std::ios::binary); if (!file.good()) { m_ErrorMessage = "Cannot open '" + filename + "' for reading"; return nullptr; } std::string tempDirectory = m_ToolfilePath + GetFileWithoutPath(filename); Poco::Zip::Decompress unzipper(file, Poco::Path(tempDirectory)); unzipper.decompressAllFiles(); //use SceneSerialization to load the DataStorage mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mitk::DataStorage::Pointer loadedStorage = mySceneIO->LoadScene(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage"); if (loadedStorage->GetAll()->size() == 0 || loadedStorage.IsNull()) { m_ErrorMessage = "Invalid file: cannot parse tool data."; return nullptr; } //convert the DataStorage back to a NavigationTool-Object mitk::DataNode::Pointer myNode = loadedStorage->GetAll()->ElementAt(0); mitk::NavigationTool::Pointer returnValue = ConvertDataNodeToNavigationTool(myNode, tempDirectory); //delete the data-storage file which is not needed any more. The toolfile must be left in the temporary directory becauses it is linked in the datatreenode of the tool std::remove((std::string(tempDirectory + Poco::Path::separator() + GetFileWithoutPath(filename) + ".storage")).c_str()); return returnValue; } mitk::NavigationTool::Pointer mitk::NavigationToolReader::ConvertDataNodeToNavigationTool(mitk::DataNode::Pointer node, std::string toolPath) { mitk::NavigationTool::Pointer returnValue = mitk::NavigationTool::New(); //DateTreeNode with Name and Surface - mitk::DataNode::Pointer newNode = mitk::DataNode::New(); - newNode->SetName(node->GetName()); - newNode->SetData(node->GetData()); - bool visible = true; - node->GetVisibility(visible, nullptr); - newNode->SetVisibility(visible); - returnValue->SetDataNode(newNode); + returnValue->SetDataNode(node); //Identifier std::string identifier; node->GetStringProperty("identifier", identifier); returnValue->SetIdentifier(identifier); + node->RemoveProperty("identifier"); + //Serial Number std::string serial; node->GetStringProperty("serial number", serial); returnValue->SetSerialNumber(serial); + node->RemoveProperty("serial number"); + //Tracking Device mitk::TrackingDeviceType device_type; node->GetStringProperty("tracking device type", device_type); //For backward compability with old tool stroages (before 12/2015 device_type was an int value, now it is string) if (device_type.size() == 0) { /* This was the old enum. Numbers inserted for better readibility. Don't delete this if-case to allow loading of ols storages... enum TrackingDeviceType { 0 NDIPolaris, ///< Polaris: optical Tracker from NDI 1 NDIAurora, ///< Aurora: electromagnetic Tracker from NDI 2 ClaronMicron, ///< Micron Tracker: optical Tracker from Claron 3 IntuitiveDaVinci, ///< Intuitive Surgical: DaVinci Telemanipulator API Interface 4 AscensionMicroBird, ///< Ascension microBird / PCIBird family 5 VirtualTracker, ///< Virtual Tracking device class that produces random tracking coordinates 6 TrackingSystemNotSpecified, ///< entry for not specified or initialized tracking system 7 TrackingSystemInvalid, ///< entry for invalid state (mainly for testing) 8 NPOptitrack, ///< NaturalPoint: Optitrack optical Tracking System 9 OpenIGTLinkTrackingDeviceConnection ///< Device which is connected via open igt link }; */ int device_type_old; node->GetIntProperty("tracking device type", device_type_old); switch (device_type_old) { case 0:device_type = mitk::NDIPolarisTypeInformation::GetTrackingDeviceName(); break; case 1:device_type = mitk::NDIAuroraTypeInformation::GetTrackingDeviceName(); break; case 2:device_type = mitk::MicronTrackerTypeInformation::GetTrackingDeviceName(); break; case 3:device_type = "IntuitiveDaVinci"; break; case 4:device_type = "AscensionMicroBird"; break; case 5:device_type = mitk::VirtualTrackerTypeInformation::GetTrackingDeviceName(); break; case 6:device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; case 7:device_type = "TrackingSystemInvalid"; break; case 8:device_type = mitk::NPOptitrackTrackingTypeInformation::GetTrackingDeviceName(); break; case 9:device_type = mitk::OpenIGTLinkTypeInformation::GetTrackingDeviceName(); break; default: device_type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); break; //default... unknown... } } + node->RemoveProperty("tracking device type"); + returnValue->SetTrackingDeviceType(static_cast(device_type)); //Tool Type int type; node->GetIntProperty("tracking tool type", type); returnValue->SetType(static_cast(type)); + node->RemoveProperty("tracking tool type"); + //Calibration File Name std::string calibration_filename; node->GetStringProperty("toolfileName", calibration_filename); if (calibration_filename == "none") { returnValue->SetCalibrationFile("none"); } else { std::string calibration_filename_with_path = toolPath + Poco::Path::separator() + calibration_filename; returnValue->SetCalibrationFile(calibration_filename_with_path); } + node->RemoveProperty("toolfileName"); + //Tool Landmarks mitk::PointSet::Pointer ToolRegLandmarks = mitk::PointSet::New(); mitk::PointSet::Pointer ToolCalLandmarks = mitk::PointSet::New(); std::string RegLandmarksString; std::string CalLandmarksString; node->GetStringProperty("ToolRegistrationLandmarks", RegLandmarksString); node->GetStringProperty("ToolCalibrationLandmarks", CalLandmarksString); ToolRegLandmarks = ConvertStringToPointSet(RegLandmarksString); ToolCalLandmarks = ConvertStringToPointSet(CalLandmarksString); returnValue->SetToolLandmarks(ToolRegLandmarks); returnValue->SetToolControlPoints(ToolCalLandmarks); + node->RemoveProperty("ToolRegistrationLandmarks"); + node->RemoveProperty("ToolCalibrationLandmarks"); + //Tool Tip std::string toolTipPositionString; std::string toolTipOrientationString; bool positionSet = node->GetStringProperty("ToolTipPosition", toolTipPositionString); bool orientationSet = node->GetStringProperty("ToolAxisOrientation", toolTipOrientationString); if (positionSet && orientationSet) //only define tooltip if it is set { returnValue->SetToolTipPosition(ConvertStringToPoint(toolTipPositionString)); returnValue->SetToolAxisOrientation(ConvertStringToQuaternion(toolTipOrientationString)); } else if (positionSet != orientationSet) { MITK_WARN << "Tooltip definition incomplete: position and orientation have to be set! Skipping tooltip definition."; } + node->RemoveProperty("ToolTipPosition"); + node->RemoveProperty("ToolAxisOrientation"); + //Tool Axis std::string ToolAxisString; node->GetStringProperty("ToolAxis", ToolAxisString); - //returnValue->SetToolAxis(ConvertStringToPoint(ToolAxisString)); + returnValue->SetToolAxis(ConvertStringToPoint(ToolAxisString)); return returnValue; } std::string mitk::NavigationToolReader::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } mitk::PointSet::Pointer mitk::NavigationToolReader::ConvertStringToPointSet(std::string string) { mitk::PointSet::Pointer returnValue = mitk::PointSet::New(); std::string pointSeperator = "|"; std::string valueSeperator = ";"; std::vector points; split(string, pointSeperator, points); for (unsigned int i = 0; i < points.size(); i++) { std::vector values; split(points.at(i), valueSeperator, values); if (values.size() == 4) { double index = atof(values.at(0).c_str()); mitk::Point3D point; point[0] = atof(values.at(1).c_str()); point[1] = atof(values.at(2).c_str()); point[2] = atof(values.at(3).c_str()); returnValue->SetPoint(index, point); } } return returnValue; } mitk::Point3D mitk::NavigationToolReader::ConvertStringToPoint(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Point3D point; if (values.size() == 3) { point[0] = atof(values.at(0).c_str()); point[1] = atof(values.at(1).c_str()); point[2] = atof(values.at(2).c_str()); } return point; } mitk::Quaternion mitk::NavigationToolReader::ConvertStringToQuaternion(std::string string) { std::string valueSeperator = ";"; std::vector values; split(string, valueSeperator, values); mitk::Quaternion quat = mitk::Quaternion(0, 0, 0, 1); if (values.size() == 4) { quat = mitk::Quaternion(atof(values.at(0).c_str()), atof(values.at(1).c_str()), atof(values.at(2).c_str()), atof(values.at(3).c_str())); } return quat; } void mitk::NavigationToolReader::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop + 1); } } diff --git a/Modules/IGT/IO/mitkNavigationToolWriter.cpp b/Modules/IGT/IO/mitkNavigationToolWriter.cpp index 5046614950..d4ffeb0134 100644 --- a/Modules/IGT/IO/mitkNavigationToolWriter.cpp +++ b/Modules/IGT/IO/mitkNavigationToolWriter.cpp @@ -1,179 +1,173 @@ /*=================================================================== 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. ===================================================================*/ //Poco headers #include #include //mitk headers #include "mitkNavigationToolWriter.h" #include #include #include #include #include //std headers #include mitk::NavigationToolWriter::NavigationToolWriter() { } mitk::NavigationToolWriter::~NavigationToolWriter() { } bool mitk::NavigationToolWriter::DoWrite(std::string FileName,mitk::NavigationTool::Pointer Tool) { //some initial validation checks... if ( Tool.IsNull()) { m_ErrorMessage = "Cannot write a navigation tool containing invalid tool data, aborting!"; MITK_ERROR << m_ErrorMessage; return false; } // Workaround for a problem: the geometry might be modified if the tool is tracked. If this // modified geometry is saved the surface representation is moved by this offset. To avoid // this bug, the geometry is set to identity for the saving progress and restored later. mitk::BaseGeometry::Pointer geometryBackup; if ( Tool->GetDataNode().IsNotNull() && (Tool->GetDataNode()->GetData()!=nullptr) && (Tool->GetDataNode()->GetData()->GetGeometry()!=nullptr) ) { geometryBackup = Tool->GetDataNode()->GetData()->GetGeometry()->Clone(); Tool->GetDataNode()->GetData()->GetGeometry()->SetIdentity(); } else {MITK_WARN << "Saving a tool with invalid data node, proceeding but errors might occure!";} //convert whole data to a mitk::DataStorage mitk::StandaloneDataStorage::Pointer saveStorage = mitk::StandaloneDataStorage::New(); mitk::DataNode::Pointer thisTool = ConvertToDataNode(Tool); saveStorage->Add(thisTool); //use SceneSerialization to save the DataStorage std::string DataStorageFileName = mitk::IOUtil::CreateTemporaryDirectory() + Poco::Path::separator() + GetFileWithoutPath(FileName) + ".storage"; mitk::SceneIO::Pointer mySceneIO = mitk::SceneIO::New(); mySceneIO->SaveScene(saveStorage->GetAll(),saveStorage,DataStorageFileName); //now put the DataStorage and the Toolfile in a ZIP-file std::ofstream file( FileName.c_str(), std::ios::binary | std::ios::out); if (!file.good()) { m_ErrorMessage = "Could not open a zip file for writing: '" + FileName + "'"; MITK_ERROR << m_ErrorMessage; return false; } else { Poco::Zip::Compress zipper( file, true ); zipper.addFile(DataStorageFileName,GetFileWithoutPath(DataStorageFileName)); if (Tool->GetCalibrationFile()!="none") zipper.addFile(Tool->GetCalibrationFile(),GetFileWithoutPath(Tool->GetCalibrationFile())); zipper.close(); } //delete the data storage std::remove(DataStorageFileName.c_str()); //restore original geometry if (geometryBackup.IsNotNull()) {Tool->GetDataNode()->GetData()->SetGeometry(geometryBackup);} return true; } mitk::DataNode::Pointer mitk::NavigationToolWriter::ConvertToDataNode(mitk::NavigationTool::Pointer Tool) { - mitk::DataNode::Pointer thisTool = mitk::DataNode::New(); + mitk::DataNode::Pointer thisTool = Tool->GetDataNode(); //Name - if (Tool->GetDataNode().IsNull()) thisTool->SetName("none"); - else thisTool->SetName(Tool->GetDataNode()->GetName().c_str()); + if (Tool->GetDataNode().IsNull()) + { + thisTool = mitk::DataNode::New(); + thisTool->SetName("none"); + } + //Identifier thisTool->AddProperty("identifier",mitk::StringProperty::New(Tool->GetIdentifier().c_str())); //Serial Number thisTool->AddProperty("serial number",mitk::StringProperty::New(Tool->GetSerialNumber().c_str())); //Tracking Device thisTool->AddProperty("tracking device type",mitk::StringProperty::New(Tool->GetTrackingDeviceType())); //Tool Type thisTool->AddProperty("tracking tool type",mitk::IntProperty::New(Tool->GetType())); //Calibration File Name thisTool->AddProperty("toolfileName",mitk::StringProperty::New(GetFileWithoutPath(Tool->GetCalibrationFile()))); - //Surface - if (Tool->GetDataNode().IsNotNull()) if (Tool->GetDataNode()->GetData() != nullptr) - { - thisTool->SetData(Tool->GetDataNode()->GetData()); - //Visibility - bool visible = true; - Tool->GetDataNode()->GetVisibility(visible, nullptr); - thisTool->SetVisibility(visible); - } - //Tool Landmarks thisTool->AddProperty("ToolRegistrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolLandmarks()))); thisTool->AddProperty("ToolCalibrationLandmarks",mitk::StringProperty::New(ConvertPointSetToString(Tool->GetToolControlPoints()))); //Tool Tip if (Tool->IsToolTipSet()) { thisTool->AddProperty("ToolTipPosition",mitk::StringProperty::New(ConvertPointToString(Tool->GetToolTipPosition()))); thisTool->AddProperty("ToolAxisOrientation",mitk::StringProperty::New(ConvertQuaternionToString(Tool->GetToolAxisOrientation()))); } - //Tool Axis + //Tool Axis thisTool->AddProperty("ToolAxis", mitk::StringProperty::New(ConvertPointToString(Tool->GetToolAxis()))); - ////Material is not needed, to avoid errors in scene serialization we have to do this: - thisTool->ReplaceProperty("material",nullptr); + //Material is not needed, to avoid errors in scene serialization we have to do this: + thisTool->RemoveProperty("material"); return thisTool; } std::string mitk::NavigationToolWriter::GetFileWithoutPath(std::string FileWithPath) { Poco::Path myFile(FileWithPath.c_str()); return myFile.getFileName(); } std::string mitk::NavigationToolWriter::ConvertPointSetToString(mitk::PointSet::Pointer pointSet) { std::stringstream returnValue; mitk::PointSet::PointDataIterator it; for ( it = pointSet->GetPointSet()->GetPointData()->Begin();it != pointSet->GetPointSet()->GetPointData()->End();it++ ) { mitk::Point3D thisPoint = pointSet->GetPoint(it->Index()); returnValue << it->Index() << ";" << ConvertPointToString(thisPoint) << "|"; } return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertPointToString(mitk::Point3D point) { std::stringstream returnValue; returnValue << point[0] << ";" << point[1] << ";" << point[2]; return returnValue.str(); } std::string mitk::NavigationToolWriter::ConvertQuaternionToString(mitk::Quaternion quat) { std::stringstream returnValue; returnValue << quat.x() << ";" << quat.y() << ";" << quat.z() << ";" << quat.r(); return returnValue.str(); } diff --git a/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp b/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp index 916fea69b1..ffde4634ce 100644 --- a/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp +++ b/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp @@ -1,153 +1,153 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkNDIAuroraTypeInformation.h" #include "mitkIGTHardwareException.h" #include "mitkNDITrackingDevice.h" namespace mitk { std::string NDIAuroraTypeInformation::GetTrackingDeviceName() { return "NDI Aurora"; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraCompact() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Compact", "NDIAuroraCompactFG_Dome.stl", "A" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarCube() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Planar (Cube)", "NDIAurora.stl", "9" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarDome() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Planar (Dome)", "NDIAuroraPlanarFG_Dome.stl", "A" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraTabletop() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Tabletop", "NDIAuroraTabletopFG_Dome.stl", "A" }; return data; } NDIAuroraTypeInformation::NDIAuroraTypeInformation() { m_DeviceName = NDIAuroraTypeInformation::GetTrackingDeviceName(); - m_TrackingDeviceData.push_back(GetDeviceDataAuroraCompact()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraPlanarCube()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraPlanarDome()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraTabletop()); + m_TrackingDeviceData.push_back(GetDeviceDataAuroraCompact()); } NDIAuroraTypeInformation::~NDIAuroraTypeInformation() { } mitk::TrackingDeviceSource::Pointer NDIAuroraTypeInformation::CreateTrackingDeviceSource( mitk::TrackingDevice::Pointer trackingDevice, mitk::NavigationToolStorage::Pointer navigationTools, std::string* errorMessage, std::vector* toolCorrespondencesInToolStorage) { MITK_DEBUG << "Creating Aurora tracking device."; mitk::TrackingDeviceSource::Pointer returnValue = mitk::TrackingDeviceSource::New(); mitk::NDITrackingDevice::Pointer thisDevice = dynamic_cast(trackingDevice.GetPointer()); try { //connect to aurora to dectect tools automatically thisDevice->OpenConnection(); } catch (mitk::IGTHardwareException& e) { errorMessage->append("Hardware error on opening the connection ("); errorMessage->append(e.GetDescription()); errorMessage->append(")"); return nullptr; } catch (mitk::IGTException& e) { errorMessage->append("Error on opening the connection ("); errorMessage->append(e.GetDescription()); errorMessage->append(")"); return nullptr; } //now search for automatically detected tools in the tool storage and save them mitk::NavigationToolStorage::Pointer newToolStorageInRightOrder = mitk::NavigationToolStorage::New(); std::vector alreadyFoundTools = std::vector(); *toolCorrespondencesInToolStorage = std::vector(); for (unsigned int i = 0; i < thisDevice->GetToolCount(); i++) { bool toolFound = false; for (unsigned int j = 0; j < navigationTools->GetToolCount(); j++) { //check if the serial number is the same to identify the tool if ((dynamic_cast(thisDevice->GetTool(i)))->GetSerialNumber() == navigationTools->GetTool(j)->GetSerialNumber()) { //check if this tool was already added to make sure that every tool is only added once (in case of same serial numbers) bool toolAlreadyAdded = false; for (unsigned int k = 0; k < alreadyFoundTools.size(); k++) { if (alreadyFoundTools.at(k) == j) { toolAlreadyAdded = true; } } if (!toolAlreadyAdded) { //add tool in right order newToolStorageInRightOrder->AddTool(navigationTools->GetTool(j)); toolCorrespondencesInToolStorage->push_back(j); //adapt name of tool dynamic_cast(thisDevice->GetTool(i))->SetToolName(navigationTools->GetTool(j)->GetToolName()); //set tip of tool dynamic_cast(thisDevice->GetTool(i))->SetToolTipPosition(navigationTools->GetTool(j)->GetToolTipPosition(), navigationTools->GetTool(j)->GetToolAxisOrientation()); //rember that this tool was already found alreadyFoundTools.push_back(j); toolFound = true; break; } } } if (!toolFound) { errorMessage->append("Error: did not find every automatically detected tool in the loaded tool storage: aborting initialization."); return nullptr; } } //And resort them (this was done in TrackingToolBoxWorker before). for (unsigned int i = 0; i < newToolStorageInRightOrder->GetToolCount(); i++) { navigationTools->AssignToolNumber(newToolStorageInRightOrder->GetTool(i)->GetIdentifier(), i); } returnValue->SetTrackingDevice(thisDevice); MITK_DEBUG << "Number of tools of created tracking device: " << thisDevice->GetToolCount(); MITK_DEBUG << "Number of outputs of created source: " << returnValue->GetNumberOfOutputs(); return returnValue; } } diff --git a/Modules/IGT/TrackingDevices/mitkNDITrackingDevice.cpp b/Modules/IGT/TrackingDevices/mitkNDITrackingDevice.cpp index 7e1bc082e2..2d14a067c3 100644 --- a/Modules/IGT/TrackingDevices/mitkNDITrackingDevice.cpp +++ b/Modules/IGT/TrackingDevices/mitkNDITrackingDevice.cpp @@ -1,1314 +1,1353 @@ /*=================================================================== 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 "mitkNDITrackingDevice.h" #include "mitkIGTTimeStamp.h" #include "mitkIGTHardwareException.h" #include #include #include #include #include #include // vtk #include typedef itk::MutexLockHolder MutexLockHolder; const unsigned char CR = 0xD; // == '\r' - carriage return const unsigned char LF = 0xA; // == '\n' - line feed mitk::NDITrackingDevice::NDITrackingDevice() : TrackingDevice(), m_DeviceName(""), m_PortNumber(mitk::SerialCommunication::COM5), m_BaudRate(mitk::SerialCommunication::BaudRate9600), m_DataBits(mitk::SerialCommunication::DataBits8), m_Parity(mitk::SerialCommunication::None), m_StopBits(mitk::SerialCommunication::StopBits1), m_HardwareHandshake(mitk::SerialCommunication::HardwareHandshakeOff), m_IlluminationActivationRate(Hz20), m_DataTransferMode(TX), m_6DTools(), m_ToolsMutex(nullptr), m_SerialCommunication(nullptr), m_SerialCommunicationMutex(nullptr), m_DeviceProtocol(nullptr), m_MultiThreader(nullptr), m_ThreadID(0), m_OperationMode(ToolTracking6D), m_MarkerPointsMutex(nullptr), m_MarkerPoints() { m_Data = mitk::UnspecifiedTrackingTypeInformation::GetDeviceDataUnspecified(); m_6DTools.clear(); m_SerialCommunicationMutex = itk::FastMutexLock::New(); m_DeviceProtocol = NDIProtocol::New(); m_DeviceProtocol->SetTrackingDevice(this); m_DeviceProtocol->UseCRCOn(); m_MultiThreader = itk::MultiThreader::New(); m_ToolsMutex = itk::FastMutexLock::New(); m_MarkerPointsMutex = itk::FastMutexLock::New(); m_MarkerPoints.reserve(50); // a maximum of 50 marker positions can be reported by the tracking device } bool mitk::NDITrackingDevice::UpdateTool(mitk::TrackingTool* tool) { if (this->GetState() != Setup) { mitk::NDIPassiveTool* ndiTool = dynamic_cast(tool); if (ndiTool == nullptr) return false; std::string portHandle = ndiTool->GetPortHandle(); //return false if the SROM Data has not been set if (ndiTool->GetSROMData() == nullptr) return false; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PVWR(&portHandle, ndiTool->GetSROMData(), ndiTool->GetSROMDataLength()); if (returnvalue != NDIOKAY) return false; returnvalue = m_DeviceProtocol->PINIT(&portHandle); if (returnvalue != NDIOKAY) return false; returnvalue = m_DeviceProtocol->PENA(&portHandle, ndiTool->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) return false; return true; } else { return false; } } void mitk::NDITrackingDevice::SetRotationMode(RotationMode r) { m_RotationMode = r; } mitk::NDITrackingDevice::~NDITrackingDevice() { /* stop tracking and disconnect from tracking device */ if (GetState() == Tracking) { this->StopTracking(); } if (GetState() == Ready) { this->CloseConnection(); } /* cleanup tracking thread */ if ((m_ThreadID != 0) && (m_MultiThreader.IsNotNull())) { m_MultiThreader->TerminateThread(m_ThreadID); } m_MultiThreader = nullptr; /* free serial communication interface */ if (m_SerialCommunication.IsNotNull()) { m_SerialCommunication->ClearReceiveBuffer(); m_SerialCommunication->ClearSendBuffer(); m_SerialCommunication->CloseConnection(); m_SerialCommunication = nullptr; } } void mitk::NDITrackingDevice::SetPortNumber(const PortNumber _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting PortNumber to " << _arg); if (this->m_PortNumber != _arg) { this->m_PortNumber = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetDeviceName(std::string _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting eviceName to " << _arg); if (this->m_DeviceName != _arg) { this->m_DeviceName = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetBaudRate(const BaudRate _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting BaudRate to " << _arg); if (this->m_BaudRate != _arg) { this->m_BaudRate = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetDataBits(const DataBits _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting DataBits to " << _arg); if (this->m_DataBits != _arg) { this->m_DataBits = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetParity(const Parity _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting Parity to " << _arg); if (this->m_Parity != _arg) { this->m_Parity = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetStopBits(const StopBits _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting StopBits to " << _arg); if (this->m_StopBits != _arg) { this->m_StopBits = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetHardwareHandshake(const HardwareHandshake _arg) { if (this->GetState() != Setup) return; itkDebugMacro("setting HardwareHandshake to " << _arg); if (this->m_HardwareHandshake != _arg) { this->m_HardwareHandshake = _arg; this->Modified(); } } void mitk::NDITrackingDevice::SetIlluminationActivationRate(const IlluminationActivationRate _arg) { if (this->GetState() == Tracking) return; itkDebugMacro("setting IlluminationActivationRate to " << _arg); if (this->m_IlluminationActivationRate != _arg) { this->m_IlluminationActivationRate = _arg; this->Modified(); if (this->GetState() == Ready) // if the connection to the tracking system is established, send the new rate to the tracking device too m_DeviceProtocol->IRATE(this->m_IlluminationActivationRate); } } void mitk::NDITrackingDevice::SetDataTransferMode(const DataTransferMode _arg) { itkDebugMacro("setting DataTransferMode to " << _arg); if (this->m_DataTransferMode != _arg) { this->m_DataTransferMode = _arg; this->Modified(); } } mitk::NDIErrorCode mitk::NDITrackingDevice::Send(const std::string* input, bool addCRC) { if (input == nullptr) return SERIALSENDERROR; std::string message; if (addCRC == true) message = *input + CalcCRC(input) + std::string(1, CR); else message = *input + std::string(1, CR); //unsigned int messageLength = message.length() + 1; // +1 for CR // Clear send buffer this->ClearSendBuffer(); // Send the date to the device MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Send(message); if (returnvalue == 0) return SERIALSENDERROR; else return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::Receive(std::string* answer, unsigned int numberOfBytes) { if (answer == nullptr) return SERIALRECEIVEERROR; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Receive(*answer, numberOfBytes); // never read more bytes than the device has send, the function will block until enough bytes are send... if (returnvalue == 0) return SERIALRECEIVEERROR; else return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::ReceiveByte(char* answer) { if (answer == nullptr) return SERIALRECEIVEERROR; std::string m; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex long returnvalue = m_SerialCommunication->Receive(m, 1); if ((returnvalue == 0) || (m.size() != 1)) return SERIALRECEIVEERROR; *answer = m.at(0); return NDIOKAY; } mitk::NDIErrorCode mitk::NDITrackingDevice::ReceiveLine(std::string* answer) { if (answer == nullptr) return SERIALRECEIVEERROR; std::string m; MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex do { long returnvalue = m_SerialCommunication->Receive(m, 1); if ((returnvalue == 0) || (m.size() != 1)) return SERIALRECEIVEERROR; *answer += m; } while (m.at(0) != LF); return NDIOKAY; } void mitk::NDITrackingDevice::ClearSendBuffer() { MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex m_SerialCommunication->ClearSendBuffer(); } void mitk::NDITrackingDevice::ClearReceiveBuffer() { MutexLockHolder lock(*m_SerialCommunicationMutex); // lock and unlock the mutex m_SerialCommunication->ClearReceiveBuffer(); } const std::string mitk::NDITrackingDevice::CalcCRC(const std::string* input) { if (input == nullptr) return ""; /* the crc16 calculation code is taken from the NDI API guide example code section */ static int oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; unsigned int data; // copy of the input string's current character unsigned int crcValue = 0; // the crc value is stored here unsigned int* puCRC16 = &crcValue; // the algorithm uses a pointer to crcValue, so it's easier to provide that than to change the algorithm for (unsigned int i = 0; i < input->length(); i++) { data = (*input)[i]; data = (data ^ (*(puCRC16)& 0xff)) & 0xff; *puCRC16 >>= 8; if (oddparity[data & 0x0f] ^ oddparity[data >> 4]) { *(puCRC16) ^= 0xc001; } data <<= 6; *puCRC16 ^= data; data <<= 1; *puCRC16 ^= data; } // crcValue contains now the CRC16 value. Convert it to a string and return it char returnvalue[13]; sprintf(returnvalue, "%04X", crcValue); // 4 hexadecimal digit with uppercase format return std::string(returnvalue); } bool mitk::NDITrackingDevice::OpenConnection() { //this->m_ModeMutex->Lock(); if (this->GetState() != Setup) { mitkThrowException(mitk::IGTException) << "Can only try to open the connection if in setup mode"; } m_SerialCommunication = mitk::SerialCommunication::New(); /* init local com port to standard com settings for a NDI tracking device: 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake */ if (m_DeviceName.empty()) m_SerialCommunication->SetPortNumber(m_PortNumber); else m_SerialCommunication->SetDeviceName(m_DeviceName); m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); m_SerialCommunication->SetParity(mitk::SerialCommunication::None); m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); if (m_SerialCommunication->OpenConnection() == 0) // 0 == ERROR_VALUE { m_SerialCommunication->CloseConnection(); m_SerialCommunication = nullptr; mitkThrowException(mitk::IGTHardwareException) << "Can not open serial port"; } /* Reset Tracking device by sending a serial break for 500ms */ m_SerialCommunication->SendBreak(400); /* Read answer from tracking device (RESETBE6F) */ static const std::string reset("RESETBE6F\r"); std::string answer = ""; this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset if (reset.compare(answer) != 0) // check for RESETBE6F { if (m_SerialCommunication.IsNotNull()) { m_SerialCommunication->CloseConnection(); m_SerialCommunication = nullptr; } mitkThrowException(mitk::IGTHardwareException) << "Hardware Reset of tracking device did not work"; } /* Now the tracking device isSetData reset, start initialization */ NDIErrorCode returnvalue; /* set device com settings to new values and wait for the device to change them */ returnvalue = m_DeviceProtocol->COMM(m_BaudRate, m_DataBits, m_Parity, m_StopBits, m_HardwareHandshake); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not set comm settings in trackingdevice"; } //after changing COMM wait at least 100ms according to NDI Api documentation page 31 itksys::SystemTools::Delay(500); /* now change local com settings accordingly */ m_SerialCommunication->CloseConnection(); m_SerialCommunication->SetBaudRate(m_BaudRate); m_SerialCommunication->SetDataBits(m_DataBits); m_SerialCommunication->SetParity(m_Parity); m_SerialCommunication->SetStopBits(m_StopBits); m_SerialCommunication->SetHardwareHandshake(m_HardwareHandshake); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); m_SerialCommunication->OpenConnection(); /* initialize the tracking device */ returnvalue = m_DeviceProtocol->INIT(); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not initialize the tracking device"; } if (this->GetType() == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName()) // if the type of tracking device is not specified, try to query the connected device { mitk::TrackingDeviceType deviceType; returnvalue = m_DeviceProtocol->VER(deviceType); if ((returnvalue != NDIOKAY) || (deviceType == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName())) { mitkThrowException(mitk::IGTHardwareException) << "Could not determine tracking device type. Please set manually and try again."; } this->SetType(deviceType); } /**** Optional Polaris specific code, Work in progress // start diagnostic mode returnvalue = m_DeviceProtocol->DSTART(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not start diagnostic mode"); return false; } else // we are in diagnostic mode { // initialize extensive IR checking returnvalue = m_DeviceProtocol->IRINIT(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not initialize intense infrared light checking"); return false; } bool intenseIR = false; returnvalue = m_DeviceProtocol->IRCHK(&intenseIR); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not execute intense infrared light checking"); return false; } if (intenseIR == true) // do something - warn the user, raise exception, write to protocol or similar std::cout << "Warning: Intense infrared light detected. Accurate tracking will probably not be possible.\n"; // stop diagnictic mode returnvalue = m_DeviceProtocol->DSTOP(); if (returnvalue != NDIOKAY) { this->SetErrorMessage("Could not stop diagnostic mode"); return false; } } *** end of optional polaris code ***/ /** * now add tools to the tracking system **/ /* First, check if the tracking device has port handles that need to be freed and free them */ returnvalue = FreePortHandles(); // non-critical, therefore no error handling /** * POLARIS: initialize the tools that were added manually **/ { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex std::string portHandle; auto endIt = m_6DTools.end(); for (auto it = m_6DTools.begin(); it != endIt; ++it) { /* get a port handle for the tool */ returnvalue = m_DeviceProtocol->PHRQ(&portHandle); if (returnvalue == NDIOKAY) { (*it)->SetPortHandle(portHandle.c_str()); /* now write the SROM file of the tool to the tracking system using PVWR */ if (this->m_Data.Line == mitk::NDIPolarisTypeInformation::GetTrackingDeviceName()) { returnvalue = m_DeviceProtocol->PVWR(&portHandle, (*it)->GetSROMData(), (*it)->GetSROMDataLength()); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not write SROM file for tool '") + (*it)->GetToolName() + std::string("' to tracking device")).c_str(); } returnvalue = m_DeviceProtocol->PINIT(&portHandle); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not initialize tool '") + (*it)->GetToolName()).c_str(); } if ((*it)->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&portHandle, (*it)->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not enable port '") + portHandle + std::string("' for tool '") + (*it)->GetToolName() + std::string("'")).c_str(); } } } } } } // end of toolsmutexlockholder scope /* check for wired tools and add them too */ if (this->DiscoverWiredTools() == false) // query the tracking device for wired tools and add them to our tool list return false; // \TODO: could we continue anyways? /*POLARIS: set the illuminator activation rate */ if (this->m_Data.Line == mitk::NDIPolarisTypeInformation::GetTrackingDeviceName()) { returnvalue = m_DeviceProtocol->IRATE(this->m_IlluminationActivationRate); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not set the illuminator activation rate"; } } /* finish - now all tools should be added, initialized and enabled, so that tracking can be started */ this->SetState(Ready); try { SetVolume(this->m_Data); } catch (mitk::IGTHardwareException e) { MITK_WARN << e.GetDescription(); } return true; } bool mitk::NDITrackingDevice::InitializeWiredTools() { NDIErrorCode returnvalue; std::string portHandle; returnvalue = m_DeviceProtocol->PHSR(OCCUPIED, &portHandle); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that are connected"; } /* if there are port handles that need to be initialized, initialize them. Furthermore instantiate tools for each handle that has no tool yet. */ std::string ph; for (unsigned int i = 0; i < portHandle.size(); i += 2) { ph = portHandle.substr(i, 2); mitk::NDIPassiveTool* pt = this->GetInternalTool(ph); if (pt == nullptr) // if we don't have a tool, something is wrong. Tools should be discovered first by calling DiscoverWiredTools() continue; if (pt->GetSROMData() == nullptr) continue; returnvalue = m_DeviceProtocol->PVWR(&ph, pt->GetSROMData(), pt->GetSROMDataLength()); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not write SROM file for tool '") + pt->GetToolName() + std::string("' to tracking device")).c_str(); } returnvalue = m_DeviceProtocol->PINIT(&ph); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not initialize tool '") + pt->GetToolName()).c_str(); } if (pt->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&ph, pt->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not enable port '") + portHandle + std::string("' for tool '") + pt->GetToolName() + std::string("'")).c_str(); } } } return true; } mitk::TrackingDeviceType mitk::NDITrackingDevice::TestConnection() { if (this->GetState() != Setup) { return mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); } m_SerialCommunication = mitk::SerialCommunication::New(); //m_DeviceProtocol = mitk::NDIProtocol::New(); //m_DeviceProtocol->SetTrackingDevice(this); //m_DeviceProtocol->UseCRCOn(); /* init local com port to standard com settings for a NDI tracking device: 9600 baud, 8 data bits, no parity, 1 stop bit, no hardware handshake */ if (m_DeviceName.empty()) m_SerialCommunication->SetPortNumber(m_PortNumber); else m_SerialCommunication->SetDeviceName(m_DeviceName); m_SerialCommunication->SetBaudRate(mitk::SerialCommunication::BaudRate9600); m_SerialCommunication->SetDataBits(mitk::SerialCommunication::DataBits8); m_SerialCommunication->SetParity(mitk::SerialCommunication::None); m_SerialCommunication->SetStopBits(mitk::SerialCommunication::StopBits1); m_SerialCommunication->SetSendTimeout(5000); m_SerialCommunication->SetReceiveTimeout(5000); if (m_SerialCommunication->OpenConnection() == 0) // error { m_SerialCommunication = nullptr; return mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); } /* Reset Tracking device by sending a serial break for 500ms */ m_SerialCommunication->SendBreak(400); /* Read answer from tracking device (RESETBE6F) */ static const std::string reset("RESETBE6F\r"); std::string answer = ""; this->Receive(&answer, reset.length()); // read answer (should be RESETBE6F) this->ClearReceiveBuffer(); // flush the receive buffer of all remaining data (carriage return, strings other than reset if (reset.compare(answer) != 0) // check for RESETBE6F { m_SerialCommunication->CloseConnection(); m_SerialCommunication = nullptr; mitkThrowException(mitk::IGTHardwareException) << "Hardware Reset of tracking device did not work"; } /* Now the tracking device is reset, start initialization */ NDIErrorCode returnvalue; /* initialize the tracking device */ //returnvalue = m_DeviceProtocol->INIT(); //if (returnvalue != NDIOKAY) //{ // this->SetErrorMessage("Could not initialize the tracking device"); // return mitk::TrackingSystemNotSpecified; //} mitk::TrackingDeviceType deviceType; returnvalue = m_DeviceProtocol->VER(deviceType); if ((returnvalue != NDIOKAY) || (deviceType == mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName())) { m_SerialCommunication = nullptr; return mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); } m_SerialCommunication = nullptr; return deviceType; } bool mitk::NDITrackingDevice::CloseConnection() { if (this->GetState() != Setup) { //init before closing to force the field generator from aurora to switch itself off m_DeviceProtocol->INIT(); /* close the serial connection */ m_SerialCommunication->CloseConnection(); /* invalidate all tools */ this->InvalidateAll(); /* return to setup mode */ this->SetState(Setup); m_SerialCommunication = nullptr; } return true; } ITK_THREAD_RETURN_TYPE mitk::NDITrackingDevice::ThreadStartTracking(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; if (pInfo == nullptr) { return ITK_THREAD_RETURN_VALUE; } if (pInfo->UserData == nullptr) { return ITK_THREAD_RETURN_VALUE; } NDITrackingDevice *trackingDevice = (NDITrackingDevice*)pInfo->UserData; if (trackingDevice != nullptr) { if (trackingDevice->GetOperationMode() == ToolTracking6D) trackingDevice->TrackTools(); // call TrackTools() from the original object else if (trackingDevice->GetOperationMode() == MarkerTracking3D) trackingDevice->TrackMarkerPositions(); // call TrackMarkerPositions() from the original object else if (trackingDevice->GetOperationMode() == ToolTracking5D) trackingDevice->TrackMarkerPositions(); // call TrackMarkerPositions() from the original object else if (trackingDevice->GetOperationMode() == HybridTracking) { trackingDevice->TrackToolsAndMarkers(); } } trackingDevice->m_ThreadID = 0; // erase thread id, now that this thread will end. return ITK_THREAD_RETURN_VALUE; } bool mitk::NDITrackingDevice::StartTracking() { if (this->GetState() != Ready) return false; this->SetState(Tracking); // go to mode Tracking this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking this->m_StopTracking = false; this->m_StopTrackingMutex->Unlock(); m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method mitk::IGTTimeStamp::GetInstance()->Start(this); return true; } void mitk::NDITrackingDevice::TrackTools() { /* lock the TrackingFinishedMutex to signal that the execution rights are now transfered to the tracking thread */ MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope if (this->GetState() != Tracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->TSTART(); if (returnvalue != NDIOKAY) return; bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking localStopTracking = this->m_StopTracking; this->m_StopTrackingMutex->Unlock(); while ((this->GetState() == Tracking) && (localStopTracking == false)) { if (this->m_DataTransferMode == TX) { returnvalue = this->m_DeviceProtocol->TX(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors break; } else { returnvalue = this->m_DeviceProtocol->BX(); if (returnvalue != NDIOKAY) break; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->TSTOP(); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "An error occured while tracking tools."; } return; // returning from this function (and ThreadStartTracking()) this will end the thread and transfer control back to main thread by releasing trackingFinishedLockHolder } void mitk::NDITrackingDevice::TrackMarkerPositions() { MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope if (m_OperationMode == ToolTracking6D) return; if (this->GetState() != Tracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->DSTART(); // Start Diagnostic Mode if (returnvalue != NDIOKAY) return; bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking localStopTracking = this->m_StopTracking; this->m_StopTrackingMutex->Unlock(); while ((this->GetState() == Tracking) && (localStopTracking == false)) { m_MarkerPointsMutex->Lock(); // lock points data structure returnvalue = this->m_DeviceProtocol->POS3D(&m_MarkerPoints); // update points data structure with new position data from tracking device m_MarkerPointsMutex->Unlock(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors { std::cout << "Error in POS3D: could not read data. Possibly no markers present." << std::endl; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); itksys::SystemTools::Delay(1); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->DSTOP(); if (returnvalue != NDIOKAY) return; // how can this thread tell the application, that an error has occured? this->SetState(Ready); return; // returning from this function (and ThreadStartTracking()) this will end the thread } void mitk::NDITrackingDevice::TrackToolsAndMarkers() { MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope if (m_OperationMode != HybridTracking) return; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->TSTART(); // Start Diagnostic Mode if (returnvalue != NDIOKAY) return; bool localStopTracking; // Because m_StopTracking is used by two threads, access has to be guarded by a mutex. To minimize thread locking, a local copy is used here this->m_StopTrackingMutex->Lock(); // update the local copy of m_StopTracking localStopTracking = this->m_StopTracking; this->m_StopTrackingMutex->Unlock(); while ((this->GetState() == Tracking) && (localStopTracking == false)) { m_MarkerPointsMutex->Lock(); // lock points data structure returnvalue = this->m_DeviceProtocol->TX(true, &m_MarkerPoints); // update points data structure with new position data from tracking device m_MarkerPointsMutex->Unlock(); if (!((returnvalue == NDIOKAY) || (returnvalue == NDICRCERROR) || (returnvalue == NDICRCDOESNOTMATCH))) // right now, do not stop on crc errors { std::cout << "Error in TX: could not read data. Possibly no markers present." << std::endl; } /* Update the local copy of m_StopTracking */ this->m_StopTrackingMutex->Lock(); localStopTracking = m_StopTracking; this->m_StopTrackingMutex->Unlock(); } /* StopTracking was called, thus the mode should be changed back to Ready now that the tracking loop has ended. */ returnvalue = m_DeviceProtocol->TSTOP(); if (returnvalue != NDIOKAY) return; // how can this thread tell the application, that an error has occurred? this->SetState(Ready); return; // returning from this function (and ThreadStartTracking()) this will end the thread } mitk::TrackingTool* mitk::NDITrackingDevice::GetTool(unsigned int toolNumber) const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex if (toolNumber < m_6DTools.size()) return m_6DTools.at(toolNumber); return nullptr; } mitk::TrackingTool* mitk::NDITrackingDevice::GetToolByName(std::string name) const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex auto end = m_6DTools.end(); for (auto iterator = m_6DTools.begin(); iterator != end; ++iterator) if (name.compare((*iterator)->GetToolName()) == 0) return *iterator; return nullptr; } mitk::NDIPassiveTool* mitk::NDITrackingDevice::GetInternalTool(std::string portHandle) { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex auto end = m_6DTools.end(); for (auto iterator = m_6DTools.begin(); iterator != end; ++iterator) if (portHandle.compare((*iterator)->GetPortHandle()) == 0) return *iterator; return nullptr; } unsigned int mitk::NDITrackingDevice::GetToolCount() const { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex return m_6DTools.size(); } bool mitk::NDITrackingDevice::Beep(unsigned char count) { if (this->GetState() != Setup) { return (m_DeviceProtocol->BEEP(count) == NDIOKAY); } else { return false; } } mitk::TrackingTool* mitk::NDITrackingDevice::AddTool(const char* toolName, const char* fileName, TrackingPriority p /*= NDIPassiveTool::Dynamic*/) { mitk::NDIPassiveTool::Pointer t = mitk::NDIPassiveTool::New(); if (t->LoadSROMFile(fileName) == false) return nullptr; t->SetToolName(toolName); t->SetTrackingPriority(p); if (this->InternalAddTool(t) == false) return nullptr; return t.GetPointer(); } bool mitk::NDITrackingDevice::InternalAddTool(mitk::NDIPassiveTool* tool) { if (tool == nullptr) return false; NDIPassiveTool::Pointer p = tool; /* if the connection to the tracking device is already established, add the new tool to the device now */ if (this->GetState() == Ready) { /* get a port handle for the tool */ std::string newPortHandle; NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PHRQ(&newPortHandle); if (returnvalue == NDIOKAY) { p->SetPortHandle(newPortHandle.c_str()); /* now write the SROM file of the tool to the tracking system using PVWR */ returnvalue = m_DeviceProtocol->PVWR(&newPortHandle, p->GetSROMData(), p->GetSROMDataLength()); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not write SROM file for tool '") + p->GetToolName() + std::string("' to tracking device")).c_str(); } /* initialize the port handle */ returnvalue = m_DeviceProtocol->PINIT(&newPortHandle); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not initialize port '") + newPortHandle + std::string("' for tool '") + p->GetToolName() + std::string("'")).c_str(); } /* enable the port handle */ if (p->IsEnabled() == true) { returnvalue = m_DeviceProtocol->PENA(&newPortHandle, p->GetTrackingPriority()); // Enable tool if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not enable port '") + newPortHandle + std::string("' for tool '") + p->GetToolName() + std::string("'")).c_str(); } } } /* now that the tool is added to the device, add it to list too */ m_ToolsMutex->Lock(); this->m_6DTools.push_back(p); m_ToolsMutex->Unlock(); this->Modified(); return true; } else if (this->GetState() == Setup) { /* In Setup mode, we only add it to the list, so that OpenConnection() can add it later */ m_ToolsMutex->Lock(); this->m_6DTools.push_back(p); m_ToolsMutex->Unlock(); this->Modified(); return true; } else // in Tracking mode, no tools can be added return false; } bool mitk::NDITrackingDevice::RemoveTool(mitk::TrackingTool* tool) { mitk::NDIPassiveTool* ndiTool = dynamic_cast(tool); if (ndiTool == nullptr) return false; std::string portHandle = ndiTool->GetPortHandle(); /* a valid portHandle has length 2. If a valid handle exists, the tool is already added to the tracking device, so we have to remove it there if the connection to the tracking device has already been established. */ if ((portHandle.length() == 2) && (this->GetState() == Ready)) // do not remove a tool in tracking mode { NDIErrorCode returnvalue; returnvalue = m_DeviceProtocol->PHF(&portHandle); if (returnvalue != NDIOKAY) return false; /* Now that the tool is removed from the tracking device, remove it from our tool list too */ MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex (scope is inside the if-block auto end = m_6DTools.end(); for (auto iterator = m_6DTools.begin(); iterator != end; ++iterator) { if (iterator->GetPointer() == ndiTool) { m_6DTools.erase(iterator); this->Modified(); return true; } } return false; } else if (this->GetState() == Setup) // in Setup Mode, we are not connected to the tracking device, so we can just remove the tool from the tool list { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex auto end = m_6DTools.end(); for (auto iterator = m_6DTools.begin(); iterator != end; ++iterator) { if ((*iterator).GetPointer() == ndiTool) { m_6DTools.erase(iterator); this->Modified(); return true; } } return false; } return false; } void mitk::NDITrackingDevice::InvalidateAll() { MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex auto end = m_6DTools.end(); for (auto iterator = m_6DTools.begin(); iterator != end; ++iterator) (*iterator)->SetDataValid(false); } bool mitk::NDITrackingDevice::SetOperationMode(OperationMode mode) { if (GetState() == Tracking) return false; m_OperationMode = mode; return true; } mitk::OperationMode mitk::NDITrackingDevice::GetOperationMode() { return m_OperationMode; } bool mitk::NDITrackingDevice::GetMarkerPositions(MarkerPointContainerType* markerpositions) { m_MarkerPointsMutex->Lock(); *markerpositions = m_MarkerPoints; // copy the internal vector to the one provided m_MarkerPointsMutex->Unlock(); return (markerpositions->size() != 0); } bool mitk::NDITrackingDevice::DiscoverWiredTools() { /* First, check for disconnected tools and remove them */ this->FreePortHandles(); - /* check for new tools, add and initialize them */ - NDIErrorCode returnvalue; + //NDI handling (PHSR 02, PINIT, PHSR 02, PHSR 00) => all initialized and all handles available + //creation of MITK tools + //NDI enable all tools (PENA) + //NDI get all serial numbers (PHINF) + + /** + NDI handling (PHSR 02, PINIT, PHSR 02, PHSR 00) => all initialized and all handles available + **/ + + /* check for occupied port handles on channel 0 */ std::string portHandle; + NDIErrorCode returnvalue = m_DeviceProtocol->PHSR(OCCUPIED, &portHandle); + + if (returnvalue != NDIOKAY) + { + mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that are connected on channel 0."; + } + + /* Initialize all port handles on channel 0 */ + for (unsigned int i = 0; i < portHandle.size(); i += 2) + { + std::string ph = portHandle.substr(i, 2); + returnvalue = m_DeviceProtocol->PINIT(&ph); + + if (returnvalue != NDIOKAY) + { + mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not initialize port '") + ph + std::string(".")); + } + } + + /* check for occupied port handles on channel 1 (initialize automatically, portHandle is empty although additional tools were detected) */ + //For a split port on a dual 5DOF tool, the first PHSR sent will report only one port handle. After the port handle is + //initialized, it is assigned to channel 0. You must then use PHSR again to assign a port handle to channel 1. The + //port handle for channel 1 is initialized automatically. returnvalue = m_DeviceProtocol->PHSR(OCCUPIED, &portHandle); if (returnvalue != NDIOKAY) { - mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that are connected"; + mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that are connected on channel 1."; } - /* if there are port handles that need to be initialized, initialize them. Furthermore instantiate tools for each handle that has no tool yet. */ - std::string ph; + /* read all port handles */ + returnvalue = m_DeviceProtocol->PHSR(ALL, &portHandle); - /* we need to remember the ports which are occupied to be able to readout the serial numbers of the connected tools later */ - std::vector occupiedPorts = std::vector(); - int numberOfToolsAtStart = this->GetToolCount(); //also remember the number of tools at start to identify the automatically detected tools later + if (returnvalue != NDIOKAY) + { + mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that are connected on all channels."; + } + + /** + 1. Create MITK tracking tool representations of NDI tools + 2. NDI enable all tools (PENA) + **/ for (unsigned int i = 0; i < portHandle.size(); i += 2) { - ph = portHandle.substr(i, 2); - if (this->GetInternalTool(ph) != nullptr) // if we already have a tool with this handle - continue; // then skip the initialization - - //instantiate an object for each tool that is connected - mitk::NDIPassiveTool::Pointer newTool = mitk::NDIPassiveTool::New(); - newTool->SetPortHandle(ph.c_str()); - newTool->SetTrackingPriority(mitk::NDIPassiveTool::Dynamic); - - //set a name for identification - newTool->SetToolName((std::string("Port ") + ph).c_str()); - - returnvalue = m_DeviceProtocol->PINIT(&ph); - if (returnvalue != NDIINITIALIZATIONFAILED) //if the initialization failed (AURORA) it can not be enabled. A srom file will have to be specified manually first. Still return true to be able to continue - { - if (returnvalue != NDIOKAY) - { - mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not initialize port '") + ph + - std::string("' for tool '") + newTool->GetToolName() + std::string("'")).c_str(); - } - /* enable the port handle */ - returnvalue = m_DeviceProtocol->PENA(&ph, newTool->GetTrackingPriority()); // Enable tool - if (returnvalue != NDIOKAY) - { + std::string ph = portHandle.substr(i, 2); + if (this->GetInternalTool(ph) != nullptr) // if we already have a tool with this handle + continue; // then skip the initialization + + //define tracking priority + auto trackingPriority = mitk::NDIPassiveTool::Dynamic; + + //instantiate an object for each tool that is connected + mitk::NDIPassiveTool::Pointer newTool = mitk::NDIPassiveTool::New(); + newTool->SetPortHandle(ph.c_str()); + newTool->SetTrackingPriority(trackingPriority); + + //set a name for identification + newTool->SetToolName((std::string("Port ") + ph).c_str()); + + /* enable the port handle */ + returnvalue = m_DeviceProtocol->PENA(&ph, trackingPriority); // Enable tool + + if (returnvalue != NDIOKAY) + { mitkThrowException(mitk::IGTHardwareException) << (std::string("Could not enable port '") + ph + - std::string("' for tool '") + newTool->GetToolName() + std::string("'")).c_str(); - } - } - //we have to temporarily unlock m_ModeMutex here to avoid a deadlock with another lock inside InternalAddTool() - if (this->InternalAddTool(newTool) == false) - { - mitkThrowException(mitk::IGTException) << "Error while adding new tool"; - } - else occupiedPorts.push_back(i); + std::string("' for tool '") + newTool->GetToolName() + std::string("'")).c_str(); + } + + //we have to temporarily unlock m_ModeMutex here to avoid a deadlock with another lock inside InternalAddTool() + if (this->InternalAddTool(newTool) == false) + { + mitkThrowException(mitk::IGTException) << "Error while adding new tool"; + } } + /** + NDI get all serial numbers (PHINF) + **/ + // after initialization readout serial numbers of automatically detected tools - for (unsigned int i = 0; i < occupiedPorts.size(); i++) + for (unsigned int i = 0; i < portHandle.size(); i += 2) { - ph = portHandle.substr(occupiedPorts.at(i), 2); - std::string portInfo; - NDIErrorCode returnvaluePort = m_DeviceProtocol->PHINF(ph, &portInfo); - if ((returnvaluePort == NDIOKAY) && (portInfo.size()>31)) dynamic_cast(this->GetTool(i + numberOfToolsAtStart))->SetSerialNumber(portInfo.substr(23, 8)); - itksys::SystemTools::Delay(10); + std::string ph = portHandle.substr(i, 2); + + std::string portInfo; + NDIErrorCode returnvaluePort = m_DeviceProtocol->PHINF(ph, &portInfo); + if ((returnvaluePort == NDIOKAY) && (portInfo.size() > 31)) + dynamic_cast(this->GetInternalTool(ph))->SetSerialNumber(portInfo.substr(23, 8)); + MITK_INFO << "portInfo: " << portInfo; + itksys::SystemTools::Delay(10); } return true; } mitk::NDIErrorCode mitk::NDITrackingDevice::FreePortHandles() { /* first search for port handles that need to be freed: e.g. because of a reset of the tracking system */ NDIErrorCode returnvalue = NDIOKAY; std::string portHandle; returnvalue = m_DeviceProtocol->PHSR(FREED, &portHandle); if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not obtain a list of port handles that need to be freed"; } /* if there are port handles that need to be freed, free them */ if (portHandle.empty() == true) return returnvalue; std::string ph; for (unsigned int i = 0; i < portHandle.size(); i += 2) { ph = portHandle.substr(i, 2); mitk::NDIPassiveTool* t = this->GetInternalTool(ph); if (t != nullptr) // if we have a tool for the port handle that needs to be freed { if (this->RemoveTool(t) == false) // remove it (this will free the port too) returnvalue = NDIERROR; } else // we don't have a tool, the port handle exists only in the tracking device { returnvalue = m_DeviceProtocol->PHF(&ph); // free it there // What to do if port handle could not be freed? This seems to be a non critical error if (returnvalue != NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not free all port handles"; } } } return returnvalue; } int mitk::NDITrackingDevice::GetMajorFirmwareRevisionNumber() { std::string revision; if (m_DeviceProtocol->APIREV(&revision) != mitk::NDIOKAY || revision.empty() || (revision.size() != 9)) { MITK_ERROR << "Could not receive firmware revision number!"; return 0; } const std::string majrevno = revision.substr(2, 3); //cut out "004" from "D.004.001" return std::atoi(majrevno.c_str()); } const char* mitk::NDITrackingDevice::GetFirmwareRevisionNumber() { static std::string revision; if (m_DeviceProtocol->APIREV(&revision) != mitk::NDIOKAY || revision.empty() || (revision.size() != 9)) { MITK_ERROR << "Could not receive firmware revision number!"; revision = ""; return revision.c_str(); } return revision.c_str(); } bool mitk::NDITrackingDevice::AutoDetectToolsAvailable() { if (this->GetType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) { return true; } else { return false; } } bool mitk::NDITrackingDevice::AddSingleToolIsAvailable() { //For Aurora, only AutoDetecion or loading of toolStorage should be used. It is not possible to add a single tool. if (this->GetType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) { return false; } //For Polaris, a single tool can be added, there is no autoDetection. else { return true; } } mitk::NavigationToolStorage::Pointer mitk::NDITrackingDevice::AutoDetectTools() { mitk::NavigationToolStorage::Pointer autoDetectedStorage = mitk::NavigationToolStorage::New(); if (this->GetType() == mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()) { try { this->OpenConnection(); this->StartTracking(); } catch (mitk::Exception& e) { MITK_WARN << "Warning, can not auto-detect tools! (" << e.GetDescription() << ")"; return autoDetectedStorage; } for (unsigned int i = 0; i < this->GetToolCount(); i++) { //create a navigation tool with sphere as surface std::stringstream toolname; toolname << "AutoDetectedTool" << i; mitk::NavigationTool::Pointer newTool = mitk::NavigationTool::New(); newTool->SetSerialNumber(dynamic_cast(this->GetTool(i))->GetSerialNumber()); newTool->SetIdentifier(toolname.str()); newTool->SetTrackingDeviceType(mitk::NDIAuroraTypeInformation::GetTrackingDeviceName()); newTool->GetDataNode()->SetName(toolname.str()); autoDetectedStorage->AddTool(newTool); } this->StopTracking(); this->CloseConnection(); } return autoDetectedStorage; } bool mitk::NDITrackingDevice::GetSupportedVolumes(unsigned int* numberOfVolumes, mitk::NDITrackingDevice::NDITrackingVolumeContainerType* volumes, mitk::NDITrackingDevice::TrackingVolumeDimensionType* volumesDimensions) { if (numberOfVolumes == nullptr || volumes == nullptr || volumesDimensions == nullptr) return false; static std::string info; if (m_DeviceProtocol->SFLIST(&info) != mitk::NDIOKAY || info.empty()) { MITK_ERROR << "Could not receive tracking volume information of tracking system!"; return false; } /*info contains the following: (+n times:) */ (*numberOfVolumes) = (unsigned int)std::atoi(info.substr(0, 1).c_str()); for (unsigned int i = 0; i < (*numberOfVolumes); i++) { //e.g. for cube: "9-025000+025000-025000+025000-055000-005000+000000+000000+000000+00000011" //for dome: "A+005000+048000+005000+066000+000000+000000+000000+000000+000000+00000011" std::string::size_type offset, end; offset = (i * 73) + 1; end = 73 + (i * 73); std::string currentVolume = info.substr(offset, end);//i=0: from 1 to 73 characters; i=1: from 75 to 148 char; // if i>0 then we have a return statement infront if (i > 0) currentVolume = currentVolume.substr(1, currentVolume.size()); if (currentVolume.compare(0, 1, NDIPolarisTypeInformation::GetDeviceDataPolarisOldModel().HardwareCode) == 0) volumes->push_back(NDIPolarisTypeInformation::GetDeviceDataPolarisOldModel().Model); if (currentVolume.compare(0, 3, NDIPolarisTypeInformation::GetDeviceDataPolarisSpectra().HardwareCode) == 0) volumes->push_back(NDIPolarisTypeInformation::GetDeviceDataPolarisSpectra().Model); if (currentVolume.compare(1, 3, NDIPolarisTypeInformation::GetDeviceDataSpectraExtendedPyramid().HardwareCode) == 0) { currentVolume = currentVolume.substr(1, currentVolume.size()); volumes->push_back(NDIPolarisTypeInformation::GetDeviceDataSpectraExtendedPyramid().Model); } if (currentVolume.compare(0, 1, NDIPolarisTypeInformation::GetDeviceDataPolarisVicra().HardwareCode) == 0) volumes->push_back(NDIPolarisTypeInformation::GetDeviceDataPolarisVicra().Model); else if (currentVolume.compare(0, 1, mitk::NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarCube().HardwareCode) == 0) volumes->push_back(mitk::NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarCube().Model);//alias cube else if (currentVolume.compare(0, 1, mitk::NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarDome().HardwareCode) == 0) volumes->push_back(mitk::NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarDome().Model); //fill volumesDimensions for (unsigned int index = 0; index < 10; index++) { std::string::size_type offD, endD; offD = 1 + (index * 7); //7 digits per dimension and the first is the type of volume endD = offD + 7; int dimension = std::atoi(currentVolume.substr(offD, endD).c_str()); dimension /= 100; //given in mm. 7 digits are xxxx.xx according to NDI //strange, the last two digits (11) also for the metal flag get read also... volumesDimensions->push_back(dimension); } } return true; } bool mitk::NDITrackingDevice::SetVolume(mitk::TrackingDeviceData volume) { if (m_DeviceProtocol->VSEL(volume) != mitk::NDIOKAY) { mitkThrowException(mitk::IGTHardwareException) << "Could not set volume!"; } return true; } \ No newline at end of file diff --git a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui index 843344e01c..2fff9363fc 100755 --- a/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkFiducialRegistrationWidget.ui @@ -1,279 +1,307 @@ QmitkFiducialRegistrationWidget 0 0 - 569 - 402 + 580 + 525 0 0 Form - - - Fiducial Registration method - - - - - - true - - - Static - - - true - - - - - - - true - - - Hybrid Continuous - - - false - - - - - - - - - - - - Move Image Points - - - - - - - - 0 - 40 - - - - <html><head/><body><p>Find fiducial correspondences (needs 6+ fiducial pairs)</p></body></html> - - - - Find fiducial - correspondences - - - - - - - - - - - 0 - 0 - - - - - 0 - 40 - - - - Register (object is moved) - - - - - + - - - - 0 - 0 - - - - Image / object / moving fiducials - - - - - - - 0 - 0 - + + + + + Fiducial Registration method + + + + true - - - - - - - 0 - 55 - + + + 10 + 23 + 50 + 17 + - - QFrame::NoFrame + + Static - - QFrame::Raised + + true - - - - - - 0 - 0 - - - - - 0 - 35 - - - - Add image fiducial - - - - - - - - - - - - - 0 - 0 - - - - Tracker / fixed fiducials - - - - - - - 0 - 0 - + + + true - - - - - - - 0 - 55 - + + + 66 + 23 + 111 + 17 + - - QFrame::NoFrame + + Hybrid Continuous - - QFrame::Raised + + false - - - - - - 0 - 0 - - - - - 0 - 35 - - - - &Add current - instrument position - - - - - - - + + + + + + + + Move Image Points + + + + + + + + 0 + 40 + + + + <html><head/><body><p>Find fiducial correspondences (needs 6+ fiducial pairs)</p></body></html> + + + + Find fiducial + correspondences + + + + + + + + + + + 0 + 0 + + + + + 40 + 40 + + + + Register (object is moved) + + + + - - - - - - - - 0 - 0 - - - - Status: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - + + + + + + 0 + 0 + + + + + 16777215 + 400 + + + + Image / object / moving fiducials + + + + + + + 0 + 0 + + + + + + + + + 0 + 55 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + 0 + 35 + + + + Add image fiducial + + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 400 + + + + Tracker / fixed fiducials + + + + + + + 0 + 0 + + + + + + + + + 0 + 55 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + 0 + 0 + + + + + 0 + 35 + + + + &Add current + instrument position + + + + + + + + + + - - - - - - Qt::AlignCenter - - + + + + + + 0 + 0 + + + + Status: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + Qt::AlignCenter + + + + - m_RegisterFiducialsBtn - m_gbFiducialRegistration QmitkPointListWidget QListWidget
QmitkPointListWidget.h
diff --git a/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui b/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui index 24cc19d363..76de061393 100644 --- a/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui @@ -1,177 +1,195 @@ QmitkNDIAuroraWidget 0 0 400 153 - - + + + + + 0 + 0 + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Aurora</span></p></body></html> - - + + - + Com Port: + + + 0 + 0 + + COM + + + 0 + 0 + + Auto Scan Qt::Horizontal 40 20 Port Type: /dev/ttyUSB /dev/ttyS Qt::Horizontal 40 20 Qt::Vertical 20 40 + + + + Qt::Horizontal + + + + 40 + 20 + + + + - - - 120 - 50 - - - - - 120 - 80 - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;" bgcolor="#000000"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; text-decoration: underline; color:#ffffff;">output:</span><span style=" font-size:8pt;"> </span></p></body></html> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;" bgcolor="#000000"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline; color:#ffffff;">output:</span> </p></body></html>
Qt::NoTextInteraction - - - 120 - 0 - - - - - 120 - 16777215 - - Test Connection + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui index cc0877213e..2b5778c388 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui @@ -1,586 +1,586 @@ QmitkNavigationToolCreationWidgetControls 0 0 618 650 Form Device Type: 150 0 150 16777215 0 0 0 600 433 Basic Information 100 0 Name: NewTool 100 0 Calibration File: none - 40 + 60 16777215 Load Qt::Vertical 20 40 0 0 600 433 Tool Visualization Default representation (shows tool coordinates) true Use surface from data storage 200 0 150 16777215 Qt::Horizontal 40 20 Load surface from file false - 40 + 60 16777215 Load Qt::Horizontal 40 20 Qt::Vertical 20 8 0 0 600 433 Tool Landmarks 0 Control Points for Registration Tool Landmarks 0 0 600 433 Advanced 100 0 Tool Type: 150 0 150 16777215 Instrument Fiducial Skinmarker Unkown 100 0 Identifier: <not given> 100 0 Serial Number: <not given> Tooltip: Qt::Horizontal 40 20 Edit Tooltip true Qt::Vertical 20 40 Tool Axis: Qt::Horizontal 40 20 QAbstractSpinBox::CorrectToPreviousValue -9999 9999 1 -9999 9999 -9999 9999 Qt::Horizontal Qt::Horizontal 40 20 Cancel Finished QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
1
QmitkPointListWidget QWidget
QmitkPointListWidget.h
1
diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui index b246da95c5..6b1cae8454 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui @@ -1,315 +1,273 @@ QmitkNavigationToolManagementWidgetControls 0 0 443 781 Form Qt::Horizontal 40 20 Whole Storage: Create New Load Save Qt::Horizontal 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Storage Name:</span></p></body></html> <none> Qt::Horizontal 40 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Tools:</span></p></body></html> Qt::Horizontal 40 20 - - - 50 - 16777215 - - Add - - - 50 - 16777215 - - Load <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Selected:</span></p></body></html> - - - 50 - 16777215 - - Up - - - 50 - 16777215 - - Down - - - 50 - 16777215 - - Delete - - - 50 - 16777215 - - Edit - - - 50 - 16777215 - - Save Qt::Vertical 20 40 0 150 Qt::Vertical 20 40 QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1
diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 8ac0be92e5..89c06dd6e0 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,77 +1,78 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine AppUtil RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation QtWidgets QtWidgetsExt Chart SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DicomUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware DiffusionImaging TumorInvasionAnalysis BoundingShape RenderWindowManager RenderWindowManagerUI CEST + BasicImageProcessing ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp index d5bdd9d7cb..00a94cfe98 100644 --- a/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp +++ b/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp @@ -1,73 +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 "mitkBasicCombinationOpenCVImageFilter.h" -#include "cv.h" +#include namespace mitk { bool BasicCombinationOpenCVImageFilter::OnFilterImage( cv::Mat& image ) { int imageId = this->GetCurrentImageId(); // go through the list of all filters for ( auto it = m_FilterList.begin(); it != m_FilterList.end(); ++it ) { // apply current filter and return false if the filter returned false if (! (*it)->FilterImage(image, imageId) ) { return false; } } return true; } void BasicCombinationOpenCVImageFilter::PushFilter( AbstractOpenCVImageFilter::Pointer filter ) { m_FilterList.push_back(filter); } AbstractOpenCVImageFilter::Pointer BasicCombinationOpenCVImageFilter::PopFilter( ) { AbstractOpenCVImageFilter::Pointer lastFilter = m_FilterList.at(m_FilterList.size()-1); m_FilterList.pop_back(); return lastFilter; } bool BasicCombinationOpenCVImageFilter::RemoveFilter( AbstractOpenCVImageFilter::Pointer filter ) { for ( auto it = m_FilterList.begin(); it != m_FilterList.end(); it++ ) { if (*it == filter) { m_FilterList.erase(it); return true; } } return false; } bool BasicCombinationOpenCVImageFilter::GetIsFilterOnTheList( AbstractOpenCVImageFilter::Pointer filter ) { return std::find(m_FilterList.begin(), m_FilterList.end(), filter) != m_FilterList.end(); } bool BasicCombinationOpenCVImageFilter::GetIsEmpty() { return m_FilterList.empty(); } } // namespace mitk diff --git a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h index 848267132f..a01353983b 100644 --- a/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h +++ b/Modules/OpenCVVideoSupport/UI/QmitkOpenCVVideoControls.h @@ -1,119 +1,120 @@ /*=================================================================== 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 QmitkOpenCVVideoControls_h #define QmitkOpenCVVideoControls_h -#include #include #include #include +#include "opencv2/core.hpp" + class QmitkRenderWindow; class QmitkVideoBackground; namespace mitk { class VideoSource; class OpenCVVideoSource; } class QmitkOpenCVVideoControlsPrivate; /// /// \brief Offers widgets to play/pause/stop a video on a certain render window with /// the use of an !initialized! QmitkVideoBackground. The QmitkVideoBackground should /// contain an OpenCVVideoSource is then owned by this widget (and deleted) /// class MITKOPENCVVIDEOSUPPORTUI_EXPORT QmitkOpenCVVideoControls : public QWidget, public mitk::PropertyListReplacedObserver { Q_OBJECT public: /// /// Construct the widget with the given render window and the given preset values /// QmitkOpenCVVideoControls(QmitkVideoBackground* _VideoBackground, QmitkRenderWindow* _RenderWindow , QWidget* parent = nullptr, Qt::WindowFlags f = nullptr); /// /// call reset if video playback is enabled here /// ~QmitkOpenCVVideoControls() override; /// /// sets the render window for this video player /// void SetRenderWindow(QmitkRenderWindow* _RenderWindow); /// /// returns the current render window /// QmitkRenderWindow* GetRenderWindow() const; /// /// sets the qmitkvideobackground for this /// void SetVideoBackground(QmitkVideoBackground* _VideoBackground); /// /// returns the current QmitkVideoBackground /// QmitkVideoBackground* GetVideoBackground() const; /// /// calls FromPropertyList /// void AfterPropertyListReplaced(const std::string& id, mitk::PropertyList* propertyList) override; signals: /// /// When playback is started this informs when a new frame was grabbed /// void NewOpenCVFrameAvailable(const IplImage*); protected slots: void on_UseGrabbingDeviceButton_clicked(bool checked = false); void on_UseVideoFileButton_clicked(bool checked = false); void on_VideoProgressSlider_sliderPressed(); void on_VideoProgressSlider_sliderReleased(); void on_VideoProgressSlider_valueChanged(int value); void on_RepeatVideoButton_clicked(bool checked = false); void on_PlayButton_clicked(bool checked = false); void on_StopButton_clicked(bool checked = false); void Play(); void Stop(); void Reset(); void IsPlaying(bool paused); void QObjectDestroyed(QObject * obj = nullptr); void NewFrameAvailable(mitk::VideoSource* videoSource); void EndOfVideoSourceReached(mitk::VideoSource* videoSource); protected: QmitkVideoBackground* m_VideoBackground; QmitkRenderWindow* m_RenderWindow; mitk::OpenCVVideoSource* m_VideoSource; Ui::QmitkOpenCVVideoControls* m_Controls; bool m_SliderCurrentlyMoved; private: friend class QmitkOpenCVVideoControlsPrivate; QScopedPointer d; }; #endif diff --git a/Modules/OpenCVVideoSupport/mitkOpenCVImageSource.h b/Modules/OpenCVVideoSupport/mitkOpenCVImageSource.h index 25ef0e9d91..eaeb509dae 100644 --- a/Modules/OpenCVVideoSupport/mitkOpenCVImageSource.h +++ b/Modules/OpenCVVideoSupport/mitkOpenCVImageSource.h @@ -1,42 +1,43 @@ /*=================================================================== 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 MITKOPENCVIMAGESOURCE_H #define MITKOPENCVIMAGESOURCE_H -#include #include +#include "opencv2/core.hpp" + namespace mitk { /// /// interface for a class providing opencv images /// class OpenCVImageSource: virtual public itk::Object { public: /// /// provide smart pointer defs /// mitkClassMacroItkParent( OpenCVImageSource, itk::Object ); /// /// \return a image as opencv 2 Mat /// virtual cv::Mat GetImage() = 0; }; } #endif // MITKOPENCVIMAGESOURCE_H diff --git a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h index e9561d8d62..bb709aad58 100644 --- a/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h +++ b/Modules/OpenCVVideoSupport/mitkUndistortCameraImage.h @@ -1,128 +1,130 @@ /*=================================================================== 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 __mitkUndistortCameraImage_h #define __mitkUndistortCameraImage_h #include "mitkCommon.h" #include #include "itkObject.h" #include "mitkPoint.h" -#include "cv.h" + +#include "opencv2/core.hpp" +#include "opencv2/imgproc.hpp" /*! \brief UndistortCameraImage This class is used to undistort camera images. Before any undistortion the class has to be initialized using the functions: SetFocalLength(),SetPrinzipalPoint() and SetCameraDistortion(). After this you can either use UndistortPixel() to undistort a single pixel's coordinates or UndistortImage() to undistort an OpenCV image. A faster version of UndistortImage() is UndistortImageFast(), however, it has to be initialized once with SetUndistortImageFastInfo() instead of the Set... methods before use. \sa QmitkFunctionality \ingroup Functionalities */ namespace mitk { class MITKOPENCVVIDEOSUPPORT_EXPORT UndistortCameraImage : public itk::Object { public: mitkClassMacroItkParent(UndistortCameraImage,itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /// Initialization /// /* * Set the camera's intrinsic focal length */ void SetFocalLength(float fc_x, float fc_y) { m_fcX = fc_x; m_fcY = fc_y; } /* * Set the camera's intrinsic principal point */ void SetPrincipalPoint(float cc_x, float cc_y) { m_ccX = cc_x; m_ccY = cc_y; } /* * Set the camera's intrinsic distortion parameters */ void SetCameraDistortion(float kc1, float kc2, float kc3, float kc4) { m_distortionMatrixData[0] = kc1; m_distortionMatrixData[1] = kc2; m_distortionMatrixData[2] = kc3; m_distortionMatrixData[3] = kc4; } /* * Pre-Calculates matrices for the later use of UndistortImageFast() */ void InitRemapUndistortion(int sizeX, int sizeY); /// USAGE /// /* * Undistort a single pixel, returns undistorted pixel */ mitk::Point2D UndistortPixel(const mitk::Point2D& src); /* * Complete undistortion of an OpenCV image, including all calculations */ void UndistortImage(IplImage* src, IplImage* dst); /* * Complete undistortion of an OpenCV image, using pre-calculated matrices from SetUndistortImageFastInfo() * The use of only a source parameter will cause the source to be overwritten. * NOTE: Using the Fast undistortion methods does not require a initialization via the Set... methods. */ void UndistortImageFast( IplImage * src, IplImage* dst = nullptr ); void SetUndistortImageFastInfo(float in_dF1, float in_dF2, float in_dPrincipalX, float in_dPrincipalY, float in_Dist[4], float ImageSizeX, float ImageSizeY); UndistortCameraImage(); ~UndistortCameraImage() override; protected: // principal point and focal length parameters float m_ccX, m_ccY, m_fcX, m_fcY; // undistortion parameters float m_distortionMatrixData[4]; // intrinsic camera parameters float m_intrinsicMatrixData[9]; // precalculated matrices for fast image undistortion with UndistortImageFast() CvMat * m_mapX, * m_mapY; // intrinsic and undistortion camera matrices CvMat m_intrinsicMatrix, m_distortionMatrix; // temp image IplImage * m_tempImage; CvMat *m_DistortionCoeffs; CvMat *m_CameraMatrix; }; } #endif diff --git a/Modules/OpenCVVideoSupport/mitkVideoInputSource.h b/Modules/OpenCVVideoSupport/mitkVideoInputSource.h index 3fc2186dcb..7ec84293fb 100644 --- a/Modules/OpenCVVideoSupport/mitkVideoInputSource.h +++ b/Modules/OpenCVVideoSupport/mitkVideoInputSource.h @@ -1,78 +1,77 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _mitk_VideoInput_Source_h_ #define _mitk_VideoInput_Source_h_ #include "mitkConfig.h" #include "mitkOpenCVVideoSource.h" #include "mitkUndistortCameraImage.h" #include -#include "cv.h" // open CV class videoInput; namespace mitk { class MITKOPENCVVIDEOSUPPORT_EXPORT VideoInputSource : public OpenCVVideoSource { public: mitkClassMacro( VideoInputSource, OpenCVVideoSource ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) ////##Documentation ////## @brief All functions behave like OpenCVVideoSource to the outside. //void GetCurrentFrameAsOpenCVImage(IplImage * image); void FetchFrame(); ////##Documentation ////## @brief returns a pointer to the image data array for opengl rendering. //unsigned char * GetVideoTexture(); void StartCapturing(); void StopCapturing(); void SetVideoCameraInput(int cameraindex, bool useCVCAMLib); void SetVideoFileInput(const char * filename, bool repeatVideo, bool useCVCAMLib); itkGetConstMacro(ShowSettingsWindow, bool); itkSetMacro(ShowSettingsWindow, bool); itkGetMacro(VideoInput, bool); protected: VideoInputSource(); virtual ~VideoInputSource(); videoInput* m_VideoInput; int m_DeviceNumber; int m_CaptureSize; // current Video image unsigned char* m_CurrentVideoTexture; /// /// Show vendor specific settings window? /// bool m_ShowSettingsWindow; }; } #endif // Header diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index fc924b63fb..3caa14abb6 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,87 +1,107 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES -QmitkApplicationCursor.cpp -QmitkDataStorageComboBox.cpp -QmitkDataStorageListModel.cpp -QmitkDataStorageTableModel.cpp -QmitkDataStorageTreeModel.cpp -QmitkFileReaderOptionsDialog.cpp -QmitkFileReaderWriterOptionsWidget.cpp -QmitkFileWriterOptionsDialog.cpp -QmitkIOUtil.cpp -QmitkLevelWindowPresetDefinitionDialog.cpp -QmitkLevelWindowRangeChangeDialog.cpp -QmitkLevelWindowWidgetContextMenu.cpp -QmitkLevelWindowWidget.cpp -QmitkLineEditLevelWindowWidget.cpp -QmitkMemoryUsageIndicatorView.cpp -QmitkMimeTypes.cpp -QmitkNodeDescriptor.cpp -QmitkColoredNodeDescriptor.cpp -QmitkNodeDescriptorManager.cpp -QmitkRenderWindowMenu.cpp -QmitkProgressBar.cpp -QmitkPropertiesTableEditor.cpp -QmitkPropertiesTableModel.cpp -QmitkPropertyDelegate.cpp -QmitkRegisterClasses.cpp -QmitkRenderingManager.cpp -QmitkRenderingManagerFactory.cpp -QmitkRenderWindow.cpp -QmitkServiceListWidget.cpp -QmitkSliderLevelWindowWidget.cpp -QmitkStdMultiWidget.cpp -QmitkMouseModeSwitcher.cpp -QmitkDataStorageFilterProxyModel.cpp -QmitkDataStorageComboBoxWithSelectNone.cpp -QmitkPropertyItem.cpp -QmitkPropertyItemDelegate.cpp -QmitkPropertyItemModel.cpp -QmitkStyleManager.cpp + QmitkAbstractDataStorageModel.cpp + QmitkApplicationCursor.cpp + QmitkDataStorageComboBox.cpp + QmitkDataStorageDefaultListModel.cpp + QmitkDataStorageListModel.cpp + QmitkDataStorageTableModel.cpp + QmitkDataStorageSimpleTreeModel.cpp + QmitkDataStorageTreeModel.cpp + QmitkDataStorageTreeModelInternalItem.cpp + QmitkFileReaderOptionsDialog.cpp + QmitkFileReaderWriterOptionsWidget.cpp + QmitkFileWriterOptionsDialog.cpp + QmitkIOUtil.cpp + QmitkLevelWindowPresetDefinitionDialog.cpp + QmitkLevelWindowRangeChangeDialog.cpp + QmitkLevelWindowWidgetContextMenu.cpp + QmitkLevelWindowWidget.cpp + QmitkLineEditLevelWindowWidget.cpp + QmitkMemoryUsageIndicatorView.cpp + QmitkMimeTypes.cpp + QmitkNodeDescriptor.cpp + QmitkColoredNodeDescriptor.cpp + QmitkNodeDescriptorManager.cpp + QmitkRenderWindowMenu.cpp + QmitkProgressBar.cpp + QmitkPropertiesTableEditor.cpp + QmitkPropertiesTableModel.cpp + QmitkPropertyDelegate.cpp + QmitkRegisterClasses.cpp + QmitkRenderingManager.cpp + QmitkRenderingManagerFactory.cpp + QmitkRenderWindow.cpp + QmitkServiceListWidget.cpp + QmitkSliderLevelWindowWidget.cpp + QmitkStdMultiWidget.cpp + QmitkMouseModeSwitcher.cpp + QmitkDataStorageFilterProxyModel.cpp + QmitkDataStorageComboBoxWithSelectNone.cpp + QmitkPropertyItem.cpp + QmitkPropertyItemDelegate.cpp + QmitkPropertyItemModel.cpp + QmitkStyleManager.cpp + QmitkAbstractDataStorageInspector.cpp + QmitkDataStorageListInspector.cpp + QmitkDataStorageTreeInspector.cpp + QmitkModelViewSelectionConnector.cpp + QmitkIDataStorageInspectorProvider.cpp + mitkQtWidgetsActivator.cpp + QmitkDataStorageInspectorGenerator.cpp ) set(MOC_H_FILES + include/QmitkAbstractDataStorageModel.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h + include/QmitkDataStorageSimpleTreeModel.h + include/QmitkDataStorageDefaultListModel.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkRenderWindowMenu.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMouseModeSwitcher.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h + include/QmitkDataStorageListInspector.h + include/QmitkAbstractDataStorageInspector.h + include/QmitkDataStorageTreeInspector.h + include/QmitkModelViewSelectionConnector.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkServiceListWidgetControls.ui + src/QmitkDataStorageListInspector.ui + src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h new file mode 100644 index 0000000000..3a6e8ad903 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h @@ -0,0 +1,131 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKABSTRACTDATASTORAGEINSPECTOR_H +#define QMITKABSTRACTDATASTORAGEINSPECTOR_H + +#include + +#include + +// mitk core +#include +#include + +// qt +#include + +class QAbstractItemVew; + +/** +* @brief This abstract class is a convinient base class for easy implementation of widgets that +* offer a specific view onto a given DataStorage instance to inspect its contents. +* One may also get the selection in this inspector of the data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageInspector : public QWidget +{ + Q_OBJECT + +public: + virtual ~QmitkAbstractDataStorageInspector(); + + /** + * @brief Sets the data storage that will be used /monitored by the widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + /** Returns the list of currently selected nodes.*/ + NodeList GetSelectedNodes() const; + + /** Returns an pointer to the view that is used in the inspector to show the content.*/ + virtual QAbstractItemView* GetView() = 0; + virtual const QAbstractItemView* GetView() const = 0; + + /** Returns the setting of the internal connector. It can be changed by SetSelectOnlyVisibleNodes()*/ + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + /** Sets the selection mode of the inspector.*/ + virtual void SetSelectionMode(SelectionMode mode) = 0; + virtual SelectionMode GetSelectionMode() const = 0; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /** + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + +protected: + /** Helper function is called if data storage or predicate is changed to (re) initialize the widget correctly. + Implement the function in derived classes.*/ + virtual void Initialize() = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + std::unique_ptr m_Connector; + + QmitkAbstractDataStorageInspector(QWidget* parent = nullptr); + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h new file mode 100644 index 0000000000..30faaec032 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h @@ -0,0 +1,92 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKABSTRACTDATASTORAGEMODEL_H +#define QMITKABSTRACTDATASTORAGEMODEL_H + +#include + +// mitk core +#include +#include +#include + +// qt +#include + +/* +* @brief This abstract class extends the 'QAbstractItemModel' to accept an 'mitk::DataStorage' and a 'mitk::NodePredicateBase'. +* It registers itself as a node event listener of the data storage. +* The 'QmitkAbstractDataStorageModel' provides three empty functions, 'NodeAdded', 'NodeChanged' and 'NodeRemoved', that +* may be implemented by subclasses. These functions allow to react to the 'AddNodeEvent', 'ChangedNodeEvent' and +* 'RemoveNodeEvent' of the data storage. This might be useful to force an update on a custom view to correctly +* represent the content of the data storage. +* +* A concrete implementation of this class is used to store the temporarily shown data nodes of the data storage. +* These nodes may be a subset of all the nodes inside the data storage, if a specific node predicate is set. +* +* A model that implements this class has to return mitk::DataNode::Pointer objects for model indexes when the +* role is QmitkDataNodeRole. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + + virtual ~QmitkAbstractDataStorageModel(); + /* + * @brief Sets the data storage and adds listener for node events. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + mitk::DataStorage* GetDataStorage() { return m_DataStorage.Lock().GetPointer(); } + /* + * @brief Sets the node predicate and updates the model data, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() { return m_NodePredicate; } + +protected: + + virtual void DataStorageChanged() = 0; + virtual void NodePredicateChanged() = 0; + + virtual void NodeAdded(const mitk::DataNode* node) = 0; + virtual void NodeChanged(const mitk::DataNode* node) = 0; + virtual void NodeRemoved(const mitk::DataNode* node) = 0; + + QmitkAbstractDataStorageModel(QObject* parent = nullptr); + QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent = nullptr); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + +private: + + /** Helper triggered on the storage delete event */ + void SetDataStorageDeleted(); + + unsigned long m_DataStorageDeletedTag; + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h new file mode 100644 index 0000000000..cbfdf81916 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h @@ -0,0 +1,82 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGEDEFAULTLISTMODEL_H +#define QMITKDATASTORAGEDEFAULTLISTMODEL_H + +#include + +// qt widgets module +#include + +/** +* @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model. +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkDataStorageDefaultListModel(QObject *parent); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + // override for customization + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +private: + + void UpdateModelData(); + + std::vector m_DataNodes; + +}; + +#endif // QMITKDATASTORAGEDEFAULTLISTMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h new file mode 100644 index 0000000000..d8fc1dd641 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h @@ -0,0 +1,41 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkDataStorageInspectorGenerator_H +#define QmitkDataStorageInspectorGenerator_H + +#include "QmitkIDataStorageInspectorProvider.h" + +#include + +class MITKQTWIDGETS_EXPORT QmitkDataStorageInspectorGenerator +{ +public: + using IDType = std::string; + + using ProviderMapType = std::map; + static ProviderMapType GetProviders(); + + static mitk::IDataStorageInspectorProvider *GetProvider(const IDType &id); + +protected: + QmitkDataStorageInspectorGenerator(); + virtual ~QmitkDataStorageInspectorGenerator(); + QmitkDataStorageInspectorGenerator(const QmitkDataStorageInspectorGenerator &source) = delete; + QmitkDataStorageInspectorGenerator& operator=(const QmitkDataStorageInspectorGenerator &) = delete; +}; + +#endif diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h new file mode 100644 index 0000000000..2e964cf019 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h @@ -0,0 +1,79 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H +#define __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H + +#include + +// Microservices +#include +#include +#include + +// MITK +#include + + +/** + * @brief Base class for DataStorage inspector provider. + */ +template +class QmitkDataStorageInspectorProviderBase : public mitk::IDataStorageInspectorProvider +{ +public: + virtual QmitkAbstractDataStorageInspector* CreateInspector() const override; + + virtual std::string GetInspectorID() const override; + virtual std::string GetInspectorDisplayName() const override; + virtual std::string GetInspectorDescription() const override; + + us::ServiceRegistration RegisterService( + us::ModuleContext *context = us::GetModuleContext()); + + void UnregisterService(); + + QmitkDataStorageInspectorProviderBase(const std::string& id); + QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc= "" ); + virtual ~QmitkDataStorageInspectorProviderBase(); + +protected: + QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other); + QmitkDataStorageInspectorProviderBase &operator=(const QmitkDataStorageInspectorProviderBase &other) = delete; + + virtual us::ServiceProperties GetServiceProperties() const; + + /** + * \brief Set the service ranking for this file reader. + * + * Default is zero and should only be chosen differently for a reason. + * The ranking is used to determine which reader to use if several + * equivalent providers have been found. + * It may be used to replace a default provider from MITK in your own project. + */ + void SetRanking(int ranking); + int GetRanking() const; + +private: + class Impl; + std::unique_ptr d; +}; + +#ifndef ITK_MANUAL_INSTANTIATION +#include "QmitkDataStorageInspectorProviderBase.tpp" +#endif + +#endif /* __MODEL_FIT_PROVIDER_BASE_H */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp new file mode 100644 index 0000000000..f7982f867c --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp @@ -0,0 +1,149 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include + +#include +#include +#include + + template + class QmitkDataStorageInspectorProviderBase::Impl + { + public: + Impl(const std::string& id, const std::string& displayName, const std::string& desc) : m_Ranking(0), m_ID(id), m_DisplayName(displayName), m_Desc(desc) + { + }; + + Impl(const Impl &other) = default; + + void SetRanking(int ranking) + { + m_Ranking = ranking; + }; + + int GetRanking() const + { + return m_Ranking; + }; + + us::ServiceRegistration m_Reg; + int m_Ranking; + std::string m_ID; + std::string m_DisplayName; + std::string m_Desc; + }; + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id) : QmitkDataStorageInspectorProviderBase(id, id) + { + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc) + { + d.reset(new Impl(id, displayName, desc)); + RegisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::~QmitkDataStorageInspectorProviderBase() + { + UnregisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other) : IDataStorageInspectorProvider(), d(new Impl(*other.d.get())) + { + } + + template + QmitkAbstractDataStorageInspector* + QmitkDataStorageInspectorProviderBase::CreateInspector() const + { + return new TInspector; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorID() const + { + return d->m_ID; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDisplayName() const + { + return d->m_DisplayName; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDescription() const + { + return d->m_Desc; + }; + + template + us::ServiceRegistration + QmitkDataStorageInspectorProviderBase::RegisterService(us::ModuleContext *context) + { + if (d->m_Reg) + return d->m_Reg; + + if (context == nullptr) + { + context = us::GetModuleContext(); + } + + us::ServiceProperties props = this->GetServiceProperties(); + d->m_Reg = context->RegisterService(this, props); + return d->m_Reg; + } + + template + void + QmitkDataStorageInspectorProviderBase::UnregisterService() + { + try + { + d->m_Reg.Unregister(); + } + catch (const std::exception &) + { + } + } + + template + us::ServiceProperties + QmitkDataStorageInspectorProviderBase::GetServiceProperties() const + { + us::ServiceProperties result; + + result[IDataStorageInspectorProvider::PROP_INSPECTOR_ID()] = this->d->m_ID; + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + return result; + } + + template + void + QmitkDataStorageInspectorProviderBase::SetRanking(int ranking) { d->SetRanking(ranking); } + + template + int + QmitkDataStorageInspectorProviderBase::GetRanking() const { return d->GetRanking(); } diff --git a/Modules/QtWidgets/include/QmitkDataStorageListInspector.h b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h new file mode 100644 index 0000000000..393469b6f3 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h @@ -0,0 +1,50 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGELISTVIEWWIDGET_H +#define QMITKDATASTORAGELISTVIEWWIDGET_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageListInspector.h" + +/* +* @brief This is an inspector that offers a simple list view on a data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageListInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageListInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageListInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h new file mode 100644 index 0000000000..e2dd6b31f9 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h @@ -0,0 +1,105 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGESIMPLETREEMODEL_H +#define QMITKDATASTORAGESIMPLETREEMODEL_H + +#include + +// qt widgets module +#include + +class QmitkDataStorageTreeModelInternalItem; + +/** +* @brief The 'QmitkDataStorageSimpleTreeModel' is a basic tree model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model.* +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +* This model is a "light" version of the classic QmitkDataStorgageTreeModel. The differences between both are the following: +* - This class currently does not support DragNDrop. +* - This class does not have the ability to change hirarchy or changes the layer property +*of nodes. This was skipped on purpose, because that is not the job of the storage model. +* - If a tree item A is removed this class does not attach children of A to the parent +*of A. Instead the complete tree representation is updated. This was changed on purpose +*because otherwise the internal representation of the model would not reflect the data storage graph anymore. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageSimpleTreeModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + QmitkDataStorageSimpleTreeModel(QObject *parent); + virtual ~QmitkDataStorageSimpleTreeModel(); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode *node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +protected: + using TreeItem = QmitkDataStorageTreeModelInternalItem; + +private: + void UpdateModelData(); + void AddNodeInternal(const mitk::DataNode *node); + + mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; + + TreeItem *TreeItemFromIndex(const QModelIndex &index) const; + QModelIndex IndexFromTreeItem(TreeItem *item) const; + + void ResetTree(); + + TreeItem *m_Root; + + /**helper structure to check, if a tree item is realy part of the model. + Prefered over iterating over the tree by hand because we can use std::find.*/ + std::list m_TreeItems; +}; + +#endif // QmitkDataStorageSimpleTreeModel_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h new file mode 100644 index 0000000000..90e90de04b --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGETREEINSPECTOR_H +#define QMITKDATASTORAGETREEINSPECTOR_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageTreeInspector.h" + +/* +* @brief This is an inspector that offers a simple tree view on a data storage. +* Something like the "data manager plugin", but in simple/light (with less functionality) +* It uses the QmitkDataStorageSimpleTreeModel. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageTreeInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageTreeInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h index 1449714dd2..03ee7de417 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h @@ -1,277 +1,213 @@ /*=================================================================== 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 QMITKDATASTORAGETREEMODEL_H_ #define QMITKDATASTORAGETREEMODEL_H_ #include #include #include #include #include #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include #include #include -/// \ingroup QmitkModule +class QmitkDataStorageTreeModelInternalItem; + +/** \ingroup QmitkModule + @warning This class causes invalid point exception when used with invalid QModelIndex instances. + The index validation is not sufficient. This may cause unspecific crashes in situation where + this class is used multiple times or with multiple selection models. See https://phabricator.mitk.org/T24348 + for more information. +*/ class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModel : public QAbstractItemModel { Q_OBJECT //# CONSTANTS,TYPEDEFS public: static const std::string COLUMN_NAME; static const std::string COLUMN_TYPE; static const std::string COLUMN_VISIBILITY; //# CTORS,DTOR public: QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop = false, QObject *parent = nullptr); ~QmitkDataStorageTreeModel() override; //# GETTER public: /// /// Get node at a specific model index. /// This function is used to get a node from a QModelIndex /// mitk::DataNode::Pointer GetNode(const QModelIndex &index) const; /// /// Returns a copy of the node-vector that is shown by this model /// virtual QList GetNodeSet() const; /// /// Get the DataStorage. /// const mitk::DataStorage::Pointer GetDataStorage() const; /// /// Get the top placement flag /// bool GetPlaceNewNodesOnTopFlag() { return m_PlaceNewNodesOnTop; } /// /// Set the top placement flag /// void SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop); //# (Re-)implemented from QAbstractItemModel //# Read model Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; //# hierarchical model /// /// called whenever the model or the view needs to create a QModelIndex for a particular /// child item (or a top-level item if parent is an invalid QModelIndex) /// QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; //# editable model bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; static QMimeData *mimeDataFromModelIndexList(const QModelIndexList &indexes); //# End of QAbstractItemModel //# SETTER public: /// /// Sets the DataStorage. The whole model will be resetted. /// void SetDataStorage(mitk::DataStorage *_DataStorage); /// /// Notify that the DataStorage was deleted. The whole model will be resetted. /// void SetDataStorageDeleted(); /// /// Adds a node to this model. /// If a predicate is set (not null) the node will be checked against it.The node has to have a data object (no one /// wants to see empty nodes). /// virtual void AddNode(const mitk::DataNode *node); /// /// Removes a node from this model. Also removes any event listener from the node. /// virtual void RemoveNode(const mitk::DataNode *node); /// /// Sets a node to modfified. Called by the DataStorage /// virtual void SetNodeModified(const mitk::DataNode *node); /// /// \return an index for the given datatreenode in the tree. If the node is not found /// QModelIndex GetIndex(const mitk::DataNode *) const; /// Set whether to allow hierarchy changes by dragging and dropping void SetAllowHierarchyChange(bool allowHierarchyChange); signals: void nodeVisibilityChanged(); //# MISC protected: - /// - /// Helper class to represent a tree structure of DataNodes - /// - class TreeItem - { - public: - /// - /// Constructs a new TreeItem with the given DataNode (must not be 0) - /// - TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent = nullptr); - /// - /// Removes itself as child from its parent-> Does not delete its children - /// \sa Delete() - /// - virtual ~TreeItem(); - /// - /// Find the index of an item - /// - int IndexOfChild(const TreeItem *item) const; - /// - /// \return The child at pos index or 0 if it not exists - /// - TreeItem *GetChild(int index) const; - /// - /// Find the TreeItem containing a special tree node (recursive tree function) - /// - TreeItem *Find(const mitk::DataNode *_DataNode) const; - /// - /// Get the amount of children - /// - int GetChildCount() const; - /// - /// \return the index of this node in its parent list - /// - int GetIndex() const; - /// - /// \return the parent of this tree item - /// - TreeItem *GetParent() const; - /// - /// Return the DataNode associated with this node - /// - mitk::DataNode::Pointer GetDataNode() const; - /// - /// Get all children as vector - /// - std::vector GetChildren() const; - - /// - /// add another item as a child of this (only if not already in that list) - /// - void AddChild(TreeItem *item); - /// - /// remove another item as child from this - /// - void RemoveChild(TreeItem *item); - /// - /// inserts a child at the given position. if pos is not in range - /// the element is added at the end - /// - void InsertChild(TreeItem *item, int index = -1); - /// Sets the parent on the treeitem - void SetParent(TreeItem *_Parent); - /// - /// Deletes the whole tree branch - /// - void Delete(); - - protected: - TreeItem *m_Parent; - std::vector m_Children; - mitk::DataNode::Pointer m_DataNode; - }; + + using TreeItem = QmitkDataStorageTreeModelInternalItem; QList ToTreeItemPtrList(const QMimeData *mimeData); QList ToTreeItemPtrList(const QByteArray &ba); /// /// Adjusts the LayerProperty according to the nodes position /// void AdjustLayerProperty(); /// /// invoked after m_DataStorage or m_Predicate changed /// TreeItem *TreeItemFromIndex(const QModelIndex &index) const; /// /// Gives a ModelIndex for the Tree Item /// QModelIndex IndexFromTreeItem(TreeItem *) const; /// /// Returns the first element in the nodes sources list (if available) or 0 /// mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToVector(TreeItem *parent, std::vector &vec) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToNodeSet(TreeItem *parent, QList &vec) const; /// /// Update Tree Model /// void Update(); //# ATTRIBUTES protected: mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_Predicate; bool m_PlaceNewNodesOnTop; TreeItem *m_Root; /// Flag to block the data storage events if nodes are added/removed by this class. bool m_BlockDataStorageEvents; /// This decides whether or not it is allowed to assign a different parent to a node /// If it is false, it is not possible to change the hierarchy of nodes by dragging /// and dropping. /// If it is true, dragging nodes on another node will replace all of their parents /// with that one. bool m_AllowHierarchyChange; private: void AddNodeInternal(const mitk::DataNode *); void RemoveNodeInternal(const mitk::DataNode *); /// /// Checks if dicom properties patient name, study names and series name exists /// bool DicomPropertiesExists(const mitk::DataNode &) const; unsigned long m_DataStorageDeletedTag; }; #endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h new file mode 100644 index 0000000000..e61d5c8819 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h @@ -0,0 +1,101 @@ +/*=================================================================== + +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 QMITKDATASTORAGETREEMODELINTERNALITEM_H_ +#define QMITKDATASTORAGETREEMODELINTERNALITEM_H_ + +#include + +#include + +#include +#include + + /// + /// Helper class to represent a tree structure of DataNodes + /// + class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModelInternalItem + { + public: + /// + /// Constructs a new QmitkDataStorageTreeModelInternalItem with the given DataNode (must not be 0) + /// + QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent = 0); + /// + /// Removes itself as child from its parent-> Does not delete its children + /// \sa Delete() + /// + virtual ~QmitkDataStorageTreeModelInternalItem(); + /// + /// Find the index of an item + /// + int IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const; + /// + /// \return The child at pos index or 0 if it not exists + /// + QmitkDataStorageTreeModelInternalItem *GetChild(int index) const; + /// + /// Find the QmitkDataStorageTreeModelInternalItem containing a special tree node (recursive tree function) + /// + QmitkDataStorageTreeModelInternalItem *Find(const mitk::DataNode *_DataNode) const; + /// + /// Get the amount of children + /// + int GetChildCount() const; + /// + /// \return the index of this node in its parent list + /// + int GetIndex() const; + /// + /// \return the parent of this tree item + /// + QmitkDataStorageTreeModelInternalItem *GetParent() const; + /// + /// Return the DataNode associated with this node + /// + mitk::DataNode* GetDataNode() const; + /// + /// Get all children as vector + /// + std::vector GetChildren() const; + + /// + /// add another item as a child of this (only if not already in that list) + /// + void AddChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// remove another item as child from this + /// + void RemoveChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// inserts a child at the given position. if pos is not in range + /// the element is added at the end + /// + void InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index = -1); + /// Sets the parent on the QmitkDataStorageTreeModelInternalItem + void SetParent(QmitkDataStorageTreeModelInternalItem *_Parent); + /// + /// Deletes the whole tree branch + /// + void Delete(); + + protected: + QmitkDataStorageTreeModelInternalItem *m_Parent; + std::vector m_Children; + mitk::DataNode::Pointer m_DataNode; + }; + +#endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h new file mode 100644 index 0000000000..d5cfb53ede --- /dev/null +++ b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h @@ -0,0 +1,71 @@ +/*=================================================================== + +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 __I_ABSTRACT_DATA_STORAGE_PROVIDER_H +#define __I_ABSTRACT_DATA_STORAGE_PROVIDER_H + +#include + +#include + +class QmitkAbstractDataStorageInspector; + +namespace mitk +{ + /** + * \ingroup MicroServices_Interfaces + * + * \brief The common interface for all DataStorage inspector providers. + * + * Implementations of this interface must be registered as a service + * to make themselves available via the service registry. + * + * It is recommended to derive new implementations from QmitkDataStorageInspectorProviderBase + * which provide correct service registration semantics. + * + * \sa QmitkDataStorageInspectorProviderBase + */ + struct MITKQTWIDGETS_EXPORT IDataStorageInspectorProvider + { + virtual ~IDataStorageInspectorProvider(); + + /** + * \brief returns an inspector instance represented by the provider. + */ + virtual QmitkAbstractDataStorageInspector* CreateInspector() const = 0; + + /** Return the uniqe ID for the inspector type provided.*/ + virtual std::string GetInspectorID() const = 0; + /** Return the display name (e.g. used in the UI) for the inspector type provided.*/ + virtual std::string GetInspectorDisplayName() const = 0; + /** Returns a description of the inspector type provided.*/ + virtual std::string GetInspectorDescription() const = 0; + + /** + * @brief Service property name for the inspector ID. + * + * The property value must be of type \c std::string. + * + * @return The property name. + */ + static std::string PROP_INSPECTOR_ID(); + }; + +} // namespace mitk + +MITK_DECLARE_SERVICE_INTERFACE(mitk::IDataStorageInspectorProvider, "org.mitk.IDataStorageInspectorProvider") + +#endif /* __I_MODEL_FIT_PROVIDER_H */ diff --git a/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h new file mode 100644 index 0000000000..5b2d361a58 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h @@ -0,0 +1,155 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKMODELVIEWSELECTIONCONNECTOR_H +#define QMITKMODELVIEWSELECTIONCONNECTOR_H + +#include + +// qt widgets module +#include + + // qt +#include + +/** +* @brief The 'QmitkModelViewSelectionConnector' is used to handle the selections of a model-view-pair. +* +* The class accepts a view and a model, which are used to react to selection changes. This class is able to propagate selection changes +* to and receive from its surrounding class. +* +* The model-view-pair can be added as a selection listener to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The model-view-pair can be set as a selection provider. This should be done by using 'SetAsSelectionProvider' with the existing +* selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkModelViewSelectionConnector' offers a public slot and signal that can be used to set / propagate the selected +* nodes in the current view: +* The 'SetCurrentSelection'-slot finds the indices of the given selected nodes in its internal data storage model and +* changes the selection of the internal data storage model accordingly. +* The 'CurrentSelectionChanged'-signal sends a list of selected nodes to its environment. +* The 'CurrentSelectionChanged'-signal is emitted by the 'ChangeModelSelection'-function, which transforms the internal item view's +* selection into a data node list. The 'ChangeModelSelection'-function is called whenever the selection of the item view's +* selection model changes. +*/ +class MITKQTWIDGETS_EXPORT QmitkModelViewSelectionConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkModelViewSelectionConnector(); + /** + * @brief Set the view whose selection model is used to propagate or receive selection changes. Use the view's data model + * to transform selected nodes into model indexes and vice versa. + * + * @pre The view's data model needs to be a 'QmitkAbstractDataStorageModel'. If so, the data model is received from + * the view and stored as a private member. + * The data model must return 'mitk::DataNode::Pointer' objects for model indexes if the role is 'QmitkDataNodeRole'. + * @throw mitk::Exception, if the view is invalid or the view's data model is not a valid 'QmitkAbstractDataStorageModel'. + * + * @param view The view to set. + */ + void SetView(QAbstractItemView* view); + + /** + * @brief Retrieve the currently selected nodes (equals the last CurrentSelectionChanged values). + */ + QList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted by the 'ChangeModelSelection'-function. This happens if the selection model + * of the private member item view has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /** + * @brief Change the selection mode of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible to the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the part of the original selection that was not visible. + * The part of the original selection, that is non-visible are the nodes that do not met the predicate of the + * associated QmitkAbstractDataStorageModel. + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(QList selectedNodes); + +private Q_SLOTS: + /** + * @brief Transform a model selection into a data node list and emit the 'CurrentSelectionChanged'-signal. + * + * The function adds the selected nodes from the original selection that could not be modified, if + * 'm_SelectOnlyVisibleNodes' is false. + * This slot is internally connected to the 'selectionChanged'-signal of the selection model of the private member item view. + * + * @param selected The newly selected items. + * @param deselected The newly deselected items. + */ + void ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected); + +private: + + QmitkAbstractDataStorageModel* m_Model; + QAbstractItemView* m_View; + + bool m_SelectOnlyVisibleNodes; + QList m_NonVisibleSelection; + + /* + * @brief Retrieve the currently selected nodes from the selection model of the private member item view by + * transforming the selection indexes into a data node list. + * + * In order to transform the indices into data nodes, the private data storage model must return + * 'mitk::DataNode::Pointer' objects for model indexes if the role is QmitkDataNodeRole. + */ + QList GetInternalSelectedNodes() const; + /* + * @brief Filter the list of given nodes such that only those nodes are used that are valid + * when using the data storage model's node predicate. + * If no node predicate was set or the data storage model is invalid, the input list + * of given nodes is returned. + */ + QList FilterNodeList(const QList& nodes) const; +}; + +/* +* @brief Return true, if the nodes in the list of two given selections are equal (Sorting is ignored. Any permutation is valid.)*/ +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2); + +#endif // QMITKMODELVIEWSELECTIONCONNECTOR_H diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp new file mode 100644 index 0000000000..d42d6846f8 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp @@ -0,0 +1,83 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkAbstractDataStorageInspector::QmitkAbstractDataStorageInspector(QWidget* parent/* = nullptr*/) + : QWidget(parent) + , m_NodePredicate(nullptr) +{ + m_Connector = std::make_unique(); + + connect(m_Connector.get(), &QmitkModelViewSelectionConnector::CurrentSelectionChanged, this, &QmitkAbstractDataStorageInspector::OnSelectionChanged); +} + +QmitkAbstractDataStorageInspector::~QmitkAbstractDataStorageInspector() +{ +} + +void QmitkAbstractDataStorageInspector::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + this->Initialize(); + } + } +} + +void QmitkAbstractDataStorageInspector::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->Initialize(); + } +} + +mitk::NodePredicateBase* QmitkAbstractDataStorageInspector::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QmitkAbstractDataStorageInspector::NodeList QmitkAbstractDataStorageInspector::GetSelectedNodes() const +{ + return m_Connector->GetSelectedNodes(); +}; + +bool QmitkAbstractDataStorageInspector::GetSelectOnlyVisibleNodes() const +{ + return m_Connector->GetSelectOnlyVisibleNodes(); +}; + +void QmitkAbstractDataStorageInspector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_Connector->SetSelectOnlyVisibleNodes(selectOnlyVisibleNodes); +}; + +void QmitkAbstractDataStorageInspector::SetCurrentSelection(NodeList selectedNodes) +{ + m_Connector->SetCurrentSelection(selectedNodes); +}; + +void QmitkAbstractDataStorageInspector::OnSelectionChanged(NodeList selectedNodes) +{ + emit CurrentSelectionChanged(selectedNodes); +}; diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp new file mode 100644 index 0000000000..9afb4d48f6 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp @@ -0,0 +1,115 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + // nothing here +} + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + SetDataStorage(dataStorage); +} + +QmitkAbstractDataStorageModel::~QmitkAbstractDataStorageModel() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } +} + +void QmitkAbstractDataStorageModel::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage == dataStorage) + { + return; + } + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from old data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // add Listener for the data storage itself + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkAbstractDataStorageModel::SetDataStorageDeleted); + m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); + + // add listener for new data storage + dataStorage->AddNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + // update model if the data storage has been changed + DataStorageChanged(); +} + +void QmitkAbstractDataStorageModel::SetDataStorageDeleted() +{ + this->SetDataStorage(nullptr); +} + +void QmitkAbstractDataStorageModel::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate == nodePredicate) + { + return; + } + + m_NodePredicate = nodePredicate; + // update model if the node predicate has been changed + NodePredicateChanged(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp new file mode 100644 index 0000000000..6f3a9db5ad --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp @@ -0,0 +1,172 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" +#include "QmitkNodeDescriptorManager.h" + +QmitkDataStorageDefaultListModel::QmitkDataStorageDefaultListModel(QObject *parent) : QmitkAbstractDataStorageModel(parent) +{ +} + +void QmitkDataStorageDefaultListModel::DataStorageChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeAdded(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + // nothing here, since the "'NodeChanged'-event is currently sent far too often + //UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +QModelIndex QmitkDataStorageDefaultListModel::index(int row, int column, const QModelIndex &parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageDefaultListModel::parent(const QModelIndex &/*child*/) const +{ + return QModelIndex(); +} + +int QmitkDataStorageDefaultListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return m_DataNodes.size(); +} + +int QmitkDataStorageDefaultListModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return 1; +} + +QVariant QmitkDataStorageDefaultListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + if(index.row() < 0 || index.row() >= static_cast(m_DataNodes.size())) + { + return QVariant(); + } + + mitk::DataNode::Pointer dataNode = m_DataNodes.at(index.row()); + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + nodeName = "unnamed"; + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +QVariant QmitkDataStorageDefaultListModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +{ + return QVariant(tr("Nodes")); +} + +Qt::ItemFlags QmitkDataStorageDefaultListModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + return Qt::NoItemFlags; +} + +void QmitkDataStorageDefaultListModel::UpdateModelData() +{ + mitk::DataStorage::SetOfObjects::ConstPointer dataNodes; + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + if (m_NodePredicate.IsNotNull()) + { + dataNodes = dataStorage->GetSubset(m_NodePredicate); + } + else + { + dataNodes = dataStorage->GetAll(); + } + } + + // update the model, so that it will be filled with the nodes of the new data storage + beginResetModel(); + m_DataNodes.clear(); + + // add all (filtered) nodes to the vector of nodes + if (dataNodes != nullptr) + { + for (auto& node : *dataNodes) + { + m_DataNodes.push_back(node); + } + } + endResetModel(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp new file mode 100644 index 0000000000..188c4d1029 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +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 "usModuleContext.h" +#include "usGetModuleContext.h" + +#include "mitkLogMacros.h" +#include "QmitkDataStorageInspectorGenerator.h" + +mitk::IDataStorageInspectorProvider* QmitkDataStorageInspectorGenerator::GetProvider(const IDType& id) +{ + mitk::IDataStorageInspectorProvider* result = nullptr; + + std::string filter = "(" + mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + "=" + id + ")"; + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(filter); + + if (!providerRegisters.empty()) + { + if (providerRegisters.size() > 1) + { + MITK_WARN << "Multiple provider for class id'" << id << "' found. Using just one."; + } + result = us::GetModuleContext()->GetService(providerRegisters.front()); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::ProviderMapType QmitkDataStorageInspectorGenerator::GetProviders() +{ + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(); + + ProviderMapType result; + + for (auto regs : providerRegisters) + { + auto provider = us::GetModuleContext()->GetService(regs); + result.insert(std::make_pair(provider->GetInspectorID(), provider)); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::QmitkDataStorageInspectorGenerator() += default; + +QmitkDataStorageInspectorGenerator::~QmitkDataStorageInspectorGenerator() += default; \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp new file mode 100644 index 0000000000..a5d3182d1f --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkDataStorageListInspector::QmitkDataStorageListInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + + m_StorageModel = new QmitkDataStorageDefaultListModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageListInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageListInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageListInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); +} + +void QmitkDataStorageListInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageListInspector::SelectionMode QmitkDataStorageListInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui new file mode 100644 index 0000000000..abce896fce --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageListInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp new file mode 100644 index 0000000000..0189f5df4d --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp @@ -0,0 +1,370 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkDataStorageSimpleTreeModel::QmitkDataStorageSimpleTreeModel(QObject *parent) + : QmitkAbstractDataStorageModel(parent), m_Root(nullptr) +{ + ResetTree(); +} + +QmitkDataStorageSimpleTreeModel::~QmitkDataStorageSimpleTreeModel() +{ + m_Root->Delete(); + m_Root = nullptr; +}; + +void QmitkDataStorageSimpleTreeModel::ResetTree() +{ + mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); + rootDataNode->SetName("Data Storage"); + m_Root = new TreeItem(rootDataNode, 0); +} + +void QmitkDataStorageSimpleTreeModel::DataStorageChanged() +{ + if (m_Root) + { + m_Root->Delete(); + } + + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodePredicateChanged() +{ + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodeAdded(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || + m_Root->Find(node) != nullptr) + return; + + this->AddNodeInternal(node); +} + +void QmitkDataStorageSimpleTreeModel::NodeChanged(const mitk::DataNode *node) +{ + TreeItem *treeItem = m_Root->Find(node); + if (treeItem) + { + TreeItem *parentTreeItem = treeItem->GetParent(); + // as the root node should not be removed one should always have a parent item + if (!parentTreeItem) + return; + QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); + + // now emit the dataChanged signal + emit dataChanged(index, index); + } +} + +void QmitkDataStorageSimpleTreeModel::NodeRemoved(const mitk::DataNode *node) +{ + if (node == nullptr || !m_Root) + return; + + TreeItem *treeItem = m_Root->Find(node); + if (!treeItem) + return; // return because there is no treeitem containing this node + + TreeItem *parentTreeItem = treeItem->GetParent(); + QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); + + // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) + this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); + + // remove node + std::vector children = treeItem->GetChildren(); + m_TreeItems.remove(treeItem); + delete treeItem; //delete in tree + + if (!children.empty()) + { + //if not empty we have to rebuild the whole representation, + //because the children could be now top level, or at another + //source/parent. + this->UpdateModelData(); + } +} + +QModelIndex QmitkDataStorageSimpleTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + TreeItem *parentItem; + + if (!parent.isValid() || parent.model() != this) + parentItem = m_Root; + else + parentItem = static_cast(parent.internalPointer()); + + if (parentItem) + { + TreeItem *childItem = parentItem->GetChild(row); + if (childItem) + return createIndex(row, column, childItem); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::parent(const QModelIndex &child) const +{ + if (!child.isValid() || !m_Root || child.model() != this) + return QModelIndex(); + + TreeItem *childItem = this->TreeItemFromIndex(child); + + if (!childItem) + return QModelIndex(); + + TreeItem *parentItem = childItem->GetParent(); + + if (parentItem == m_Root) + return QModelIndex(); + + return this->createIndex(parentItem->GetIndex(), 0, parentItem); +} + +QmitkDataStorageSimpleTreeModel::TreeItem *QmitkDataStorageSimpleTreeModel::TreeItemFromIndex( + const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto item = static_cast(index.internalPointer()); + auto finding = std::find(std::begin(m_TreeItems), std::end(m_TreeItems), item); + if (finding == std::end(m_TreeItems)) + { + return nullptr; + } + return item; + } + else + return m_Root; +} + +int QmitkDataStorageSimpleTreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); + if (parentTreeItem) + return parentTreeItem->GetChildCount(); + else + return 0; +} + +int QmitkDataStorageSimpleTreeModel::columnCount(const QModelIndex &/*parent*/) const +{ + return 1; +} + +QVariant QmitkDataStorageSimpleTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return QVariant(); + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + { + nodeName = "unnamed"; + } + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +bool QmitkDataStorageSimpleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.model() != this) + return false; + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return false; + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + if (!dataNode) + return false; + + if (role == Qt::EditRole && !value.toString().isEmpty()) + { + dataNode->SetName(value.toString().toStdString().c_str()); + } + else if (role == Qt::CheckStateRole) + { + // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. + // Therefore the checkstate is being estimated again here. + + QVariant qcheckstate = index.data(Qt::CheckStateRole); + int checkstate = qcheckstate.toInt(); + bool isVisible = bool(checkstate); + dataNode->SetVisibility(!isVisible); + } + // inform listeners about changes + emit dataChanged(index, index); + return true; +} + +QVariant QmitkDataStorageSimpleTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) + return QString::fromStdString(m_Root->GetDataNode()->GetName()); + + return QVariant(); +} + +Qt::ItemFlags QmitkDataStorageSimpleTreeModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return Qt::NoItemFlags; + + const auto dataNode = treeItem->GetDataNode(); + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + else + { + return Qt::NoItemFlags; + } + + } + + return Qt::NoItemFlags; +} + +mitk::DataNode *QmitkDataStorageSimpleTreeModel::GetParentNode(const mitk::DataNode *node) const +{ + mitk::DataNode *dataNode = nullptr; + + mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); + + if (_Sources->Size() > 0) + dataNode = _Sources->front(); + + return dataNode; +} + +void QmitkDataStorageSimpleTreeModel::AddNodeInternal(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != 0) + return; + + // find out if we have a root node + TreeItem *parentTreeItem = m_Root; + QModelIndex index; + mitk::DataNode *parentDataNode = this->GetParentNode(node); + + if (parentDataNode) // no top level data node + { + parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item + if (!parentTreeItem) + { + this->NodeAdded(parentDataNode); + parentTreeItem = m_Root->Find(parentDataNode); + if (!parentTreeItem) + return; + } + + // get the index of this parent with the help of the grand parent + index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); + } + + int firstRowWithASiblingBelow = 0; + int nodeLayer = -1; + node->GetIntProperty("layer", nodeLayer); + for (TreeItem *siblingTreeItem : parentTreeItem->GetChildren()) + { + int siblingLayer = -1; + if (mitk::DataNode *siblingNode = siblingTreeItem->GetDataNode()) + { + siblingNode->GetIntProperty("layer", siblingLayer); + } + if (nodeLayer > siblingLayer) + { + break; + } + ++firstRowWithASiblingBelow; + } + beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); + auto newNode = new TreeItem(const_cast(node)); + parentTreeItem->InsertChild(newNode, firstRowWithASiblingBelow); + m_TreeItems.push_back(newNode); + + endInsertRows(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::IndexFromTreeItem(TreeItem *item) const +{ + if (item == m_Root) + return QModelIndex(); + else + return this->createIndex(item->GetIndex(), 0, item); +} + +void QmitkDataStorageSimpleTreeModel::UpdateModelData() +{ + if (!m_DataStorage.IsExpired()) + { + auto nodeset = m_DataStorage.Lock()->GetAll(); + if (m_NodePredicate != nullptr) + { + nodeset = m_DataStorage.Lock()->GetSubset(m_NodePredicate); + } + + for (const auto& node : *nodeset) + { + this->AddNodeInternal(node); + } + } +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp new file mode 100644 index 0000000000..c8bb5c952b --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp @@ -0,0 +1,65 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +QmitkDataStorageTreeInspector::QmitkDataStorageTreeInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + m_Controls.view->setHeaderHidden(true); + m_Controls.view->setTextElideMode(Qt::ElideMiddle); + + m_StorageModel = new QmitkDataStorageSimpleTreeModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageTreeInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageTreeInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageTreeInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); + + m_Controls.view->expandAll(); +} + +void QmitkDataStorageTreeInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageTreeInspector::SelectionMode QmitkDataStorageTreeInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui new file mode 100644 index 0000000000..4517c402e4 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageTreeInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index c27f72a607..d83c8d96cd 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,1005 +1,884 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "QmitkDataStorageTreeModel.h" +#include "QmitkDataStorageTreeModelInternalItem.h" #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include #include QmitkDataStorageTreeModel::QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop, QObject *parent) : QAbstractItemModel(parent), m_DataStorage(nullptr), m_PlaceNewNodesOnTop(_PlaceNewNodesOnTop), m_Root(nullptr), m_BlockDataStorageEvents(false), m_AllowHierarchyChange(false) { this->SetDataStorage(_DataStorage); } QmitkDataStorageTreeModel::~QmitkDataStorageTreeModel() { // set data storage to 0 = remove all listeners this->SetDataStorage(nullptr); m_Root->Delete(); m_Root = nullptr; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::GetNode(const QModelIndex &index) const { return this->TreeItemFromIndex(index)->GetDataNode(); } const mitk::DataStorage::Pointer QmitkDataStorageTreeModel::GetDataStorage() const { return m_DataStorage.Lock(); } QModelIndex QmitkDataStorageTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid()) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } int QmitkDataStorageTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); return parentTreeItem->GetChildCount(); } Qt::ItemFlags QmitkDataStorageTreeModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsDropEnabled; } } int QmitkDataStorageTreeModel::columnCount(const QModelIndex & /* parent = QModelIndex() */) const { return 1; } QModelIndex QmitkDataStorageTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(index); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItemFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); else return m_Root; } Qt::DropActions QmitkDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } bool QmitkDataStorageTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) { return true; } // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if (data->hasFormat("application/x-qabstractitemmodeldatalist")) { returnValue = true; // First we extract a Qlist of TreeItem* pointers. QList listOfItemsToDrop = ToTreeItemPtrList(data); if (listOfItemsToDrop.empty()) { return false; } // Retrieve the TreeItem* where we are dropping stuff, and its parent. TreeItem *dropItem = this->TreeItemFromIndex(parent); TreeItem *parentItem = dropItem->GetParent(); // If item was dropped onto empty space, we select the root node if (dropItem == m_Root) { parentItem = m_Root; } // Dragging and Dropping is only allowed within the same parent, so use the first item in list to validate. // (otherwise, you could have a derived image such as a segmentation, and assign it to another image). // NOTE: We are assuming the input list is valid... i.e. when it was dragged, all the items had the same parent. // Determine whether or not the drag and drop operation is a valid one. // Examples of invalid operations include: // - dragging nodes with different parents // - dragging nodes from one parent to another parent, if m_AllowHierarchyChange is false // - dragging a node on one of its child nodes (only relevant if m_AllowHierarchyChange is true) bool isValidDragAndDropOperation(true); // different parents { TreeItem *firstParent = listOfItemsToDrop[0]->GetParent(); QList::iterator diIter; for (diIter = listOfItemsToDrop.begin() + 1; diIter != listOfItemsToDrop.end(); diIter++) { if (firstParent != (*diIter)->GetParent()) { isValidDragAndDropOperation = false; break; } } } // dragging from one parent to another if ((!m_AllowHierarchyChange) && isValidDragAndDropOperation) { if (row == -1) // drag onto a node { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == parentItem; } else // drag between nodes { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == dropItem; } } // dragging on a child node of one the dragged nodes { QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *tempItem = dropItem; while (tempItem != m_Root) { tempItem = tempItem->GetParent(); if (tempItem == *diIter) { isValidDragAndDropOperation = false; } } } } if (!isValidDragAndDropOperation) return isValidDragAndDropOperation; if (listOfItemsToDrop[0] != dropItem && isValidDragAndDropOperation) { // Retrieve the index of where we are dropping stuff. QModelIndex parentModelIndex = this->IndexFromTreeItem(parentItem); int dragIndex = 0; // Iterate through the list of TreeItem (which may be at non-consecutive indexes). QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *itemToDrop = *diIter; // if the item is dragged down we have to compensate its final position for the // fact it is deleted lateron, this only applies if it is dragged within the same level if ((itemToDrop->GetIndex() < row) && (itemToDrop->GetParent() == dropItem)) { dragIndex = 1; } // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. this->beginRemoveRows( this->IndexFromTreeItem(itemToDrop->GetParent()), itemToDrop->GetIndex(), itemToDrop->GetIndex()); itemToDrop->GetParent()->RemoveChild(itemToDrop); this->endRemoveRows(); } // row = -1 dropped on an item, row != -1 dropped in between two items // Select the target index position, or put it at the end of the list. int dropIndex = 0; if (row != -1) { if (dragIndex == 0) dropIndex = std::min(row, parentItem->GetChildCount() - 1); else dropIndex = std::min(row - 1, parentItem->GetChildCount() - 1); } else { dropIndex = dropItem->GetIndex(); } QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); if ((row == -1 && dropItemModelIndex.row() == -1) || dropItemModelIndex.row() > parentItem->GetChildCount()) dropIndex = parentItem->GetChildCount() - 1; // Now insert items again at the drop item position if (m_AllowHierarchyChange) { this->beginInsertRows(dropItemModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } else { this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { // dropped on node, behaviour depends on preference setting if (m_AllowHierarchyChange) { auto dataStorage = m_DataStorage.Lock(); m_BlockDataStorageEvents = true; mitk::DataNode *droppedNode = (*diIter)->GetDataNode(); mitk::DataNode *dropOntoNode = dropItem->GetDataNode(); dataStorage->Remove(droppedNode); dataStorage->Add(droppedNode, dropOntoNode); m_BlockDataStorageEvents = false; dropItem->InsertChild((*diIter), dropIndex); } else { if (row == -1) // drag onto a node { parentItem->InsertChild((*diIter), dropIndex); } else // drag between nodes { dropItem->InsertChild((*diIter), dropIndex); } } dropIndex++; } this->endInsertRows(); // Change Layers to match. this->AdjustLayerProperty(); } } else if (data->hasFormat("application/x-mitk-datanodes")) { returnValue = true; int numberOfNodesDropped = 0; QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); mitk::DataNode *node = nullptr; foreach (node, dataNodeList) { if (node && !m_DataStorage.IsExpired() && !m_DataStorage.Lock()->Exists(node)) { m_DataStorage.Lock()->Add(node); mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); numberOfNodesDropped++; } } } // Only do a rendering update, if we actually dropped anything. if (numberOfNodesDropped > 0) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return returnValue; } QStringList QmitkDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << "application/x-qabstractitemmodeldatalist"; types << "application/x-mitk-datanodes"; return types; } QMimeData *QmitkDataStorageTreeModel::mimeData(const QModelIndexList &indexes) const { return mimeDataFromModelIndexList(indexes); } QMimeData *QmitkDataStorageTreeModel::mimeDataFromModelIndexList(const QModelIndexList &indexes) { QMimeData *ret = new QMimeData; QString treeItemAddresses(""); QString dataNodeAddresses(""); QByteArray baTreeItemPtrs; QByteArray baDataNodePtrs; QDataStream dsTreeItemPtrs(&baTreeItemPtrs, QIODevice::WriteOnly); QDataStream dsDataNodePtrs(&baDataNodePtrs, QIODevice::WriteOnly); for (int i = 0; i < indexes.size(); i++) { TreeItem *treeItem = static_cast(indexes.at(i).internalPointer()); dsTreeItemPtrs << reinterpret_cast(treeItem); - dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode().GetPointer()); + dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode()); // --------------- deprecated ----------------- unsigned long long treeItemAddress = reinterpret_cast(treeItem); - unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode().GetPointer()); + unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode()); QTextStream(&treeItemAddresses) << treeItemAddress; QTextStream(&dataNodeAddresses) << dataNodeAddress; if (i != indexes.size() - 1) { QTextStream(&treeItemAddresses) << ","; QTextStream(&dataNodeAddresses) << ","; } // -------------- end deprecated ------------- } // ------------------ deprecated ----------------- ret->setData("application/x-qabstractitemmodeldatalist", QByteArray(treeItemAddresses.toLatin1())); ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toLatin1())); // --------------- end deprecated ----------------- ret->setData(QmitkMimeTypes::DataStorageTreeItemPtrs, baTreeItemPtrs); ret->setData(QmitkMimeTypes::DataNodePtrs, baDataNodePtrs); return ret; } QVariant QmitkDataStorageTreeModel::data(const QModelIndex &index, int role) const { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); // get name of treeItem (may also be edited) QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == Qt::CheckStateRole) { return dataNode->IsVisible(nullptr); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageTreeModel::DicomPropertiesExists(const mitk::DataNode &node) const { bool propertiesExists = false; mitk::BaseProperty *seriesDescription_deprecated = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (node.GetProperty("dicom.patient.PatientsName")); mitk::BaseProperty *seriesDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); if (patientsName != nullptr && studyDescription != nullptr && seriesDescription != nullptr) { if ((!patientsName->GetValueAsString().empty()) && (!studyDescription->GetValueAsString().empty()) && (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } /** Code coveres the deprecated property naming for backwards compatibility */ if (patientsName_deprecated != nullptr && studyDescription_deprecated != nullptr && seriesDescription_deprecated != nullptr) { if ((!patientsName_deprecated->GetValueAsString().empty()) && (!studyDescription_deprecated->GetValueAsString().empty()) && (!seriesDescription_deprecated->GetValueAsString().empty())) { propertiesExists = true; } } return propertiesExists; } QVariant QmitkDataStorageTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } void QmitkDataStorageTreeModel::SetDataStorage(mitk::DataStorage *_DataStorage) { if (m_DataStorage != _DataStorage) // dont take the same again { if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listeners for the nodes dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); } // take over the new data storage m_DataStorage = _DataStorage; // delete the old root (if necessary, create new) if (m_Root) m_Root->Delete(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Manager"); m_Root = new TreeItem(rootDataNode, nullptr); this->beginResetModel(); this->endResetModel(); if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkDataStorageTreeModel::SetDataStorageDeleted); m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); // add listeners for the nodes dataStorage->AddNodeEvent.AddListener(mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = dataStorage->GetSubset(m_Predicate); // finally add all nodes to the model this->Update(); } } } void QmitkDataStorageTreeModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkDataStorageTreeModel::AddNodeInternal(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->AddNode(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } // add node if (m_PlaceNewNodesOnTop) { // emit beginInsertRows event beginInsertRows(index, 0, 0); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), 0); } else { int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem* siblingTreeItem: parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode* siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), firstRowWithASiblingBelow); } // emit endInsertRows event endInsertRows(); if(m_PlaceNewNodesOnTop) { this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::AddNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; this->AddNodeInternal(node); } void QmitkDataStorageTreeModel::SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop) { m_PlaceNewNodesOnTop = _PlaceNewNodesOnTop; } void QmitkDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode *node) { if (!m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); delete treeItem; // emit endRemoveRows event endRemoveRows(); // move all children of deleted node into its parent for (std::vector::iterator it = children.begin(); it != children.end(); it++) { // emit beginInsertRows event beginInsertRows(parentIndex, parentTreeItem->GetChildCount(), parentTreeItem->GetChildCount()); // add nodes again parentTreeItem->AddChild(*it); // emit endInsertRows event endInsertRows(); } this->AdjustLayerProperty(); } void QmitkDataStorageTreeModel::RemoveNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents) return; this->RemoveNodeInternal(node); } void QmitkDataStorageTreeModel::SetNodeModified(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } mitk::DataNode *QmitkDataStorageTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } bool QmitkDataStorageTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetStringProperty("name", value.toString().toStdString().c_str()); mitk::PlanarFigure *planarFigure = dynamic_cast(dataNode->GetData()); if (planarFigure != nullptr) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); emit nodeVisibilityChanged(); } // inform listeners about changes emit dataChanged(index, index); return true; } bool QmitkDataStorageTreeModel::setHeaderData(int /*section*/, Qt::Orientation /*orientation*/, const QVariant & /* value */, int /*role = Qt::EditRole*/) { return false; } void QmitkDataStorageTreeModel::AdjustLayerProperty() { /// transform the tree into an array and set the layer property descending std::vector vec; this->TreeToVector(m_Root, vec); int i = vec.size() - 1; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { mitk::DataNode::Pointer dataNode = (*it)->GetDataNode(); bool fixedLayer = false; if (!(dataNode->GetBoolProperty("fixedLayer", fixedLayer) && fixedLayer)) dataNode->SetIntProperty("layer", i); --i; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataStorageTreeModel::TreeToVector(TreeItem *parent, std::vector &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); this->TreeToVector(current, vec); vec.push_back(current); } } QModelIndex QmitkDataStorageTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } QList QmitkDataStorageTreeModel::GetNodeSet() const { QList res; if (m_Root) this->TreeToNodeSet(m_Root, res); return res; } void QmitkDataStorageTreeModel::TreeToNodeSet(TreeItem *parent, QList &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); vec.push_back(current->GetDataNode()); this->TreeToNodeSet(current, vec); } } QModelIndex QmitkDataStorageTreeModel::GetIndex(const mitk::DataNode *node) const { if (m_Root) { TreeItem *item = m_Root->Find(node); if (item) return this->IndexFromTreeItem(item); } return QModelIndex(); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QMimeData *mimeData) { if (mimeData == nullptr || !mimeData->hasFormat(QmitkMimeTypes::DataStorageTreeItemPtrs)) { return QList(); } return ToTreeItemPtrList(mimeData->data(QmitkMimeTypes::DataStorageTreeItemPtrs)); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QByteArray &ba) { QList result; QDataStream ds(ba); while (!ds.atEnd()) { quintptr treeItemPtr; ds >> treeItemPtr; result.push_back(reinterpret_cast(treeItemPtr)); } return result; } -QmitkDataStorageTreeModel::TreeItem::TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent) - : m_Parent(_Parent), m_DataNode(_DataNode) -{ - if (m_Parent) - m_Parent->AddChild(this); -} - -QmitkDataStorageTreeModel::TreeItem::~TreeItem() -{ - if (m_Parent) - m_Parent->RemoveChild(this); -} - -void QmitkDataStorageTreeModel::TreeItem::Delete() -{ - while (m_Children.size() > 0) - delete m_Children.back(); - - delete this; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::Find(const mitk::DataNode *_DataNode) const -{ - QmitkDataStorageTreeModel::TreeItem *item = nullptr; - if (_DataNode) - { - if (m_DataNode == _DataNode) - item = const_cast(this); - else - { - for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) - { - if (item) - break; - item = (*it)->Find(_DataNode); - } - } - } - return item; -} - -int QmitkDataStorageTreeModel::TreeItem::IndexOfChild(const TreeItem *item) const -{ - std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); - return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetChild(int index) const -{ - return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : nullptr; -} - -void QmitkDataStorageTreeModel::TreeItem::AddChild(TreeItem *item) -{ - this->InsertChild(item); -} - -void QmitkDataStorageTreeModel::TreeItem::RemoveChild(TreeItem *item) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it != m_Children.end()) - { - m_Children.erase(it); - item->SetParent(nullptr); - } -} - -int QmitkDataStorageTreeModel::TreeItem::GetChildCount() const -{ - return m_Children.size(); -} - -int QmitkDataStorageTreeModel::TreeItem::GetIndex() const -{ - if (m_Parent) - return m_Parent->IndexOfChild(this); - - return 0; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetParent() const -{ - return m_Parent; -} - -mitk::DataNode::Pointer QmitkDataStorageTreeModel::TreeItem::GetDataNode() const -{ - return m_DataNode; -} - -void QmitkDataStorageTreeModel::TreeItem::InsertChild(TreeItem *item, int index) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it == m_Children.end()) - { - if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) - { - it = m_Children.begin(); - std::advance(it, index); - m_Children.insert(it, item); - } - else - m_Children.push_back(item); - - // add parent if necessary - if (item->GetParent() != this) - item->SetParent(this); - } -} - -std::vector QmitkDataStorageTreeModel::TreeItem::GetChildren() const -{ - return m_Children; -} - -void QmitkDataStorageTreeModel::TreeItem::SetParent(TreeItem *_Parent) -{ - m_Parent = _Parent; - if (m_Parent) - m_Parent->AddChild(this); -} - void QmitkDataStorageTreeModel::Update() { if (!m_DataStorage.IsExpired()) { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = m_DataStorage.Lock()->GetAll(); /// Regardless the value of this preference, the new nodes must not be inserted /// at the top now, but at the position according to their layer. bool newNodesWereToBePlacedOnTop = m_PlaceNewNodesOnTop; m_PlaceNewNodesOnTop = false; for (const auto& node: *_NodeSet) { this->AddNodeInternal(node); } m_PlaceNewNodesOnTop = newNodesWereToBePlacedOnTop; /// Adjust the layers to ensure that derived nodes are above their sources. this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::SetAllowHierarchyChange(bool allowHierarchyChange) { m_AllowHierarchyChange = allowHierarchyChange; } diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp new file mode 100644 index 0000000000..ae7741b899 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp @@ -0,0 +1,144 @@ +/*=================================================================== + +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 "QmitkDataStorageTreeModelInternalItem.h" + +#include "QmitkNodeDescriptorManager.h" +#include +#include +#include + +QmitkDataStorageTreeModelInternalItem::QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent) + : m_Parent(_Parent), m_DataNode(_DataNode) +{ + if (m_Parent) + m_Parent->AddChild(this); +} + +QmitkDataStorageTreeModelInternalItem::~QmitkDataStorageTreeModelInternalItem() +{ + if (m_Parent) + m_Parent->RemoveChild(this); +} + +void QmitkDataStorageTreeModelInternalItem::Delete() +{ + while (m_Children.size() > 0) + delete m_Children.back(); + + delete this; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::Find(const mitk::DataNode *_DataNode) const +{ + QmitkDataStorageTreeModelInternalItem *item = nullptr; + if (_DataNode) + { + if (m_DataNode == _DataNode) + item = const_cast(this); + else + { + for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) + { + if (item) + break; + item = (*it)->Find(_DataNode); + } + } + } + return item; +} + +int QmitkDataStorageTreeModelInternalItem::IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const +{ + std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); + return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetChild(int index) const +{ + return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : 0; +} + +void QmitkDataStorageTreeModelInternalItem::AddChild(QmitkDataStorageTreeModelInternalItem *item) +{ + this->InsertChild(item); +} + +void QmitkDataStorageTreeModelInternalItem::RemoveChild(QmitkDataStorageTreeModelInternalItem *item) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it != m_Children.end()) + { + m_Children.erase(it); + item->SetParent(0); + } +} + +int QmitkDataStorageTreeModelInternalItem::GetChildCount() const +{ + return m_Children.size(); +} + +int QmitkDataStorageTreeModelInternalItem::GetIndex() const +{ + if (m_Parent) + return m_Parent->IndexOfChild(this); + + return 0; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetParent() const +{ + return m_Parent; +} + +mitk::DataNode* QmitkDataStorageTreeModelInternalItem::GetDataNode() const +{ + return m_DataNode; +} + +void QmitkDataStorageTreeModelInternalItem::InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it == m_Children.end()) + { + if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) + { + it = m_Children.begin(); + std::advance(it, index); + m_Children.insert(it, item); + } + else + m_Children.push_back(item); + + // add parent if necessary + if (item->GetParent() != this) + item->SetParent(this); + } +} + +std::vector QmitkDataStorageTreeModelInternalItem::GetChildren() const +{ + return m_Children; +} + +void QmitkDataStorageTreeModelInternalItem::SetParent(QmitkDataStorageTreeModelInternalItem *_Parent) +{ + m_Parent = _Parent; + if (m_Parent) + m_Parent->AddChild(this); +} diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp similarity index 55% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp index b332e9eca7..a78f82850c 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp @@ -1,32 +1,29 @@ /*=================================================================== 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include "QmitkIDataStorageInspectorProvider.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +namespace mitk { - auto pixels = new unsigned long[100]; - void *data = pixels; + IDataStorageInspectorProvider::~IDataStorageInspectorProvider() {} - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; + std::string mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + { + static std::string s = "org.mitk.IDataStorageInspectorProvider.inspectorid"; + return s; + } - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp new file mode 100644 index 0000000000..b582b9e240 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp @@ -0,0 +1,189 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkModelViewSelectionConnector.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkModelViewSelectionConnector::QmitkModelViewSelectionConnector() + : m_Model(nullptr) + , m_View(nullptr) + , m_SelectOnlyVisibleNodes(false) +{ + // nothing here +} + +void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view) +{ + if (nullptr != m_View) + { + disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); + } + + // reset model-view pair and check for valid function argument + m_View = nullptr; + if (nullptr == view) + { + mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'."; + } + + auto storageModel = dynamic_cast(view->model()); + + if (storageModel == nullptr) + { + mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view."; + } + + // a valid item view and a valid data model was found + m_View = view; + m_Model = storageModel; + connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); +} + +void QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +} + +void QmitkModelViewSelectionConnector::SetCurrentSelection(QList selectedNodes) +{ + if (nullptr == m_Model || nullptr == m_View) + { + return; + } + + // filter input nodes and return the modified input node list + QList filteredNodes = FilterNodeList(selectedNodes); + + bool equal = EqualNodeSelections(this->GetInternalSelectedNodes(), filteredNodes); + if (equal) + { + return; + } + + if (!m_SelectOnlyVisibleNodes) + { + // store the unmodified selection + m_NonVisibleSelection = selectedNodes; + // remove the nodes in the original selection that are already contained in the filtered input node list + // this will keep the selection of the original nodes that are not presented by the current view unmodified, but allows to change the selection of the filtered nodes + // later, the nodes of the 'm_NonVisibleSelection' member have to be added again to the list of selected (filtered) nodes, if a selection is sent from the current view (see 'ModelSelectionChanged') + auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); }; + m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end()); + } + + // create new selection by retrieving the corresponding indices of the (filtered) nodes + QItemSelection newCurrentSelection; + for (const auto& node : filteredNodes) + { + QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue(node), 1, Qt::MatchRecursive); + if (!matched.empty()) + { + newCurrentSelection.select(matched.front(), matched.front()); + } + } + + m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); +} + +void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) +{ + emit CurrentSelectionChanged(GetSelectedNodes()); +} + +bool QmitkModelViewSelectionConnector::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +} + +QList QmitkModelViewSelectionConnector::GetSelectedNodes() const +{ + auto nodes = GetInternalSelectedNodes(); + + if (!m_SelectOnlyVisibleNodes) + { + // add the non-visible nodes from the original selection + nodes.append(m_NonVisibleSelection); + } + + return nodes; +} + +QList QmitkModelViewSelectionConnector::GetInternalSelectedNodes() const +{ + if (nullptr == m_Model || nullptr == m_View) + { + return QList(); + } + + QList nodes; + QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes(); + for (const auto& index : selectedIndexes) + { + QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole); + if (qvariantDataNode.canConvert()) + { + nodes.push_back(qvariantDataNode.value()); + } + } + return nodes; +} + +QList QmitkModelViewSelectionConnector::FilterNodeList(const QList& nodes) const +{ + if (nodes.isEmpty()) + { + return QList(); + } + + if (nullptr == m_Model) + { + return nodes; + } + + mitk::NodePredicateBase* nodePredicate = m_Model->GetNodePredicate(); + if (nullptr == nodePredicate) + { + // no filter set + return nodes; + } + + QList result; + for (const auto& node : nodes) + { + if (true == nodePredicate->CheckNode(node)) + { + result.push_back(node); + } + } + + return result; +} + +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2) +{ + if (selection1.size() == selection2.size()) + { + // lambda to compare node pointer inside both lists + auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; }; + return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda); + } + + return false; +} diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp new file mode 100644 index 0000000000..8763ca1435 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp @@ -0,0 +1,38 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkQtWidgetsActivator.h" + +// Micro Services +#include +#include + +// Qmitk +#include "QmitkDataStorageInspectorProviderBase.h" +#include "QmitkDataStorageListInspector.h" +#include "QmitkDataStorageTreeInspector.h" + +void MitkQtWidgetsActivator::Load(us::ModuleContext * /*context*/) +{ + m_TreeInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.")); + m_ListInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageTreeInspector", "Rendering tree", "Displays the filtered content of the data storage as the current rendering tree. \n(Equals the old data manager view)")); +} + +void MitkQtWidgetsActivator::Unload(us::ModuleContext *) +{ +} + +US_EXPORT_MODULE_ACTIVATOR(MitkQtWidgetsActivator) \ No newline at end of file diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.h b/Modules/QtWidgets/src/mitkQtWidgetsActivator.h new file mode 100644 index 0000000000..5536b275d9 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.h @@ -0,0 +1,46 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKQTWIDGETSACTIVATOR_H_ +#define MITKQTWIDGETSACTIVATOR_H_ + +// Micro Services +#include +#include +#include +#include + +#include + +#include "QmitkIDataStorageInspectorProvider.h" + +/* + * This is the module activator for the "QtWidgets" module. + */ +class MitkQtWidgetsActivator : public us::ModuleActivator +{ +public: + void Load(us::ModuleContext *context) override; + void Unload(us::ModuleContext *) override; + +private: + std::unique_ptr m_TreeInspector; + std::unique_ptr m_ListInspector; + + us::ModuleContext *m_Context; +}; + +#endif // MITKCOREACTIVATOR_H_ diff --git a/Modules/QtWidgetsExt/resource/arrow-down.svg b/Modules/QtWidgetsExt/resource/arrow-down.svg index 6ff3a3a53c..e90c9fe748 100644 --- a/Modules/QtWidgetsExt/resource/arrow-down.svg +++ b/Modules/QtWidgetsExt/resource/arrow-down.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/arrow-up.svg b/Modules/QtWidgetsExt/resource/arrow-up.svg index 322b7932b8..99ccfb82e3 100644 --- a/Modules/QtWidgetsExt/resource/arrow-up.svg +++ b/Modules/QtWidgetsExt/resource/arrow-up.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/eraser.svg b/Modules/QtWidgetsExt/resource/eraser.svg index 725d88fed0..1a777baef7 100644 --- a/Modules/QtWidgetsExt/resource/eraser.svg +++ b/Modules/QtWidgetsExt/resource/eraser.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/folder-open.svg b/Modules/QtWidgetsExt/resource/folder-open.svg index 12990d0ae8..d0f8ed7ebb 100644 --- a/Modules/QtWidgetsExt/resource/folder-open.svg +++ b/Modules/QtWidgetsExt/resource/folder-open.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/plus-xyz.svg b/Modules/QtWidgetsExt/resource/plus-xyz.svg index 303346fa4d..4da0fa0f79 100644 --- a/Modules/QtWidgetsExt/resource/plus-xyz.svg +++ b/Modules/QtWidgetsExt/resource/plus-xyz.svg @@ -1,82 +1,82 @@ image/svg+xml diff --git a/Modules/QtWidgetsExt/resource/plus.svg b/Modules/QtWidgetsExt/resource/plus.svg index c180bc77f4..d19839734e 100644 --- a/Modules/QtWidgetsExt/resource/plus.svg +++ b/Modules/QtWidgetsExt/resource/plus.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/save.svg b/Modules/QtWidgetsExt/resource/save.svg index e396a59486..d12d2aab74 100644 --- a/Modules/QtWidgetsExt/resource/save.svg +++ b/Modules/QtWidgetsExt/resource/save.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp index c336ba8c3a..94a632b937 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.cpp +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.cpp @@ -1,400 +1,402 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include "mitkImageReadAccessor.h" #include +#include "opencv2/imgproc.hpp" + mitk::ToFCompositeFilter::ToFCompositeFilter() : m_SegmentationMask(nullptr), m_ImageWidth(0), m_ImageHeight(0), m_ImageSize(0), m_IplDistanceImage(nullptr), m_IplOutputImage(nullptr), m_ItkInputImage(nullptr), m_ApplyTemporalMedianFilter(false), m_ApplyAverageFilter(false), m_ApplyMedianFilter(false), m_ApplyThresholdFilter(false), m_ApplyMaskSegmentation(false), m_ApplyBilateralFilter(false), m_DataBuffer(nullptr), m_DataBufferCurrentIndex(0), m_DataBufferMaxSize(0), m_TemporalMedianFilterNumOfFrames(10), m_ThresholdFilterMin(1), m_ThresholdFilterMax(7000), m_BilateralFilterDomainSigma(2), m_BilateralFilterRangeSigma(60), m_BilateralFilterKernelRadius(0) { } mitk::ToFCompositeFilter::~ToFCompositeFilter() { cvReleaseImage(&(this->m_IplDistanceImage)); cvReleaseImage(&(this->m_IplOutputImage)); if (m_DataBuffer!=nullptr) { delete [] m_DataBuffer; } } void mitk::ToFCompositeFilter::SetInput( const InputImageType* distanceImage ) { this->SetInput(0, distanceImage); } void mitk::ToFCompositeFilter::SetInput( unsigned int idx, const InputImageType* distanceImage ) { if ((distanceImage == nullptr) && (idx == this->GetNumberOfInputs() - 1)) // if the last input is set to nullptr, reduce the number of inputs by one { this->SetNumberOfIndexedInputs(this->GetNumberOfInputs() - 1); } else { if (idx==0) //create IPL image holding distance data { if (!distanceImage->IsEmpty()) { this->m_ImageWidth = distanceImage->GetDimension(0); this->m_ImageHeight = distanceImage->GetDimension(1); this->m_ImageSize = this->m_ImageWidth * this->m_ImageHeight * sizeof(float); if (this->m_IplDistanceImage != nullptr) { cvReleaseImage(&(this->m_IplDistanceImage)); } ImageReadAccessor distImgAcc(distanceImage, distanceImage->GetSliceData(0,0,0)); float* distanceFloatData = (float*) distImgAcc.GetData(); this->m_IplDistanceImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); if (this->m_IplOutputImage != nullptr) { cvReleaseImage(&(this->m_IplOutputImage)); } this->m_IplOutputImage = cvCreateImage(cvSize(this->m_ImageWidth, this->m_ImageHeight), IPL_DEPTH_32F, 1); CreateItkImage(this->m_ItkInputImage); } } this->ProcessObject::SetNthInput(idx, const_cast(distanceImage)); // Process object is not const-correct so the const_cast is required here } this->CreateOutputsForAllInputs(); } mitk::Image* mitk::ToFCompositeFilter::GetInput() { return this->GetInput(0); } mitk::Image* mitk::ToFCompositeFilter::GetInput( unsigned int idx ) { if (this->GetNumberOfInputs() < 1) return nullptr; //TODO: geeignete exception werfen return static_cast< mitk::Image*>(this->ProcessObject::GetInput(idx)); } void mitk::ToFCompositeFilter::GenerateData() { // copy input 1...n to output 1...n for (unsigned int idx=0; idxGetNumberOfOutputs(); idx++) { mitk::Image::Pointer outputImage = this->GetOutput(idx); mitk::Image::Pointer inputImage = this->GetInput(idx); if (outputImage.IsNotNull()&&inputImage.IsNotNull()) { ImageReadAccessor inputAcc(inputImage, inputImage->GetSliceData()); outputImage->CopyInformation(inputImage); outputImage->Initialize(inputImage->GetPixelType(),inputImage->GetDimension(),inputImage->GetDimensions()); outputImage->SetSlice(inputAcc.GetData()); } } //mitk::Image::Pointer outputDistanceImage = this->GetOutput(); ImageReadAccessor outputAcc(this->GetOutput(), this->GetOutput()->GetSliceData(0, 0, 0) ); float* outputDistanceFloatData = (float*) outputAcc.GetData(); //mitk::Image::Pointer inputDistanceImage = this->GetInput(); ImageReadAccessor inputAcc(this->GetInput(), this->GetInput()->GetSliceData(0, 0, 0) ); // copy initial distance image to ipl image float* distanceFloatData = (float*)inputAcc.GetData(); memcpy(this->m_IplDistanceImage->imageData, (void*)distanceFloatData, this->m_ImageSize); if (m_ApplyThresholdFilter||m_ApplyMaskSegmentation) { ProcessSegmentation(this->m_IplDistanceImage); } if (this->m_ApplyTemporalMedianFilter||this->m_ApplyAverageFilter) { ProcessStreamedQuickSelectMedianImageFilter(this->m_IplDistanceImage); } if (this->m_ApplyMedianFilter) { ProcessCVMedianFilter(this->m_IplDistanceImage, this->m_IplOutputImage); memcpy( this->m_IplDistanceImage->imageData, this->m_IplOutputImage->imageData, this->m_ImageSize ); } if (this->m_ApplyBilateralFilter) { float* itkFloatData = this->m_ItkInputImage->GetBufferPointer(); memcpy(itkFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); ItkImageType2D::Pointer itkOutputImage = ProcessItkBilateralFilter(this->m_ItkInputImage); memcpy( this->m_IplDistanceImage->imageData, itkOutputImage->GetBufferPointer(), this->m_ImageSize ); //ProcessCVBilateralFilter(this->m_IplDistanceImage, this->m_OutputIplImage, domainSigma, rangeSigma, kernelRadius); //memcpy( distanceFloatData, this->m_OutputIplImage->imageData, distanceImageSize ); } memcpy( outputDistanceFloatData, this->m_IplDistanceImage->imageData, this->m_ImageSize ); } void mitk::ToFCompositeFilter::CreateOutputsForAllInputs() { this->SetNumberOfIndexedOutputs(this->GetNumberOfInputs()); // create outputs for all inputs for (unsigned int idx = 0; idx < this->GetNumberOfIndexedInputs(); ++idx) { if (this->GetOutput(idx) == nullptr) { DataObjectPointer newOutput = this->MakeOutput(idx); this->SetNthOutput(idx, newOutput); } } this->Modified(); } void mitk::ToFCompositeFilter::GenerateOutputInformation() { mitk::Image::ConstPointer input = this->GetInput(); mitk::Image::Pointer output = this->GetOutput(); if (output->IsInitialized()) return; itkDebugMacro(<<"GenerateOutputInformation()"); output->Initialize(input->GetPixelType(), *input->GetTimeGeometry()); output->SetPropertyList(input->GetPropertyList()->Clone()); } void mitk::ToFCompositeFilter::ProcessSegmentation(IplImage* inputIplImage) { char* segmentationMask; if (m_SegmentationMask.IsNotNull()) { ImageReadAccessor segMaskAcc(m_SegmentationMask, m_SegmentationMask->GetSliceData(0,0,0)); segmentationMask = (char*)segMaskAcc.GetData(); } else { segmentationMask = nullptr; } float *f = (float*)inputIplImage->imageData; for(int i=0; im_ImageWidth*this->m_ImageHeight; i++) { if (this->m_ApplyThresholdFilter) { if (f[i]<=m_ThresholdFilterMin) { f[i] = 0.0; } else if (f[i]>=m_ThresholdFilterMax) { f[i] = 0.0; } } if (this->m_ApplyMaskSegmentation) { if (segmentationMask) { if (segmentationMask[i]==0) { f[i] = 0.0; } } } } } ItkImageType2D::Pointer mitk::ToFCompositeFilter::ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage) { ItkImageType2D::Pointer outputItkImage; BilateralFilterType::Pointer bilateralFilter = BilateralFilterType::New(); bilateralFilter->SetInput(inputItkImage); bilateralFilter->SetDomainSigma(m_BilateralFilterDomainSigma); bilateralFilter->SetRangeSigma(m_BilateralFilterRangeSigma); //bilateralFilter->SetRadius(m_BilateralFilterKernelRadius); outputItkImage = bilateralFilter->GetOutput(); outputItkImage->Update(); return outputItkImage; } void mitk::ToFCompositeFilter::ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage) { int diameter = m_BilateralFilterKernelRadius; double sigmaColor = m_BilateralFilterRangeSigma; double sigmaSpace = m_BilateralFilterDomainSigma; cvSmooth(inputIplImage, outputIplImage, CV_BILATERAL, diameter, 0, sigmaColor, sigmaSpace); } void mitk::ToFCompositeFilter::ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius) { cvSmooth(inputIplImage, outputIplImage, CV_MEDIAN, radius, 0, 0, 0); } void mitk::ToFCompositeFilter::ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage) { float* data = (float*)inputIplImage->imageData; int imageSize = inputIplImage->width * inputIplImage->height; float* tmpArray; if (this->m_TemporalMedianFilterNumOfFrames == 0) { return; } if (m_TemporalMedianFilterNumOfFrames != this->m_DataBufferMaxSize) // reset { //delete current buffer for( int i=0; im_DataBufferMaxSize; i++ ) { delete[] this->m_DataBuffer[i]; } if (this->m_DataBuffer != nullptr) { delete[] this->m_DataBuffer; } this->m_DataBufferMaxSize = m_TemporalMedianFilterNumOfFrames; // create new buffer with current size this->m_DataBuffer = new float*[this->m_DataBufferMaxSize]; for(int i=0; im_DataBufferMaxSize; i++) { this->m_DataBuffer[i] = nullptr; } this->m_DataBufferCurrentIndex = 0; } int currentBufferSize = this->m_DataBufferMaxSize; tmpArray = new float[this->m_DataBufferMaxSize]; // copy data to buffer if (this->m_DataBuffer[this->m_DataBufferCurrentIndex] == nullptr) { this->m_DataBuffer[this->m_DataBufferCurrentIndex] = new float[imageSize]; currentBufferSize = this->m_DataBufferCurrentIndex + 1; } for(int j=0; jm_DataBuffer[this->m_DataBufferCurrentIndex][j] = data[j]; } float tmpValue = 0.0f; for(int i=0; im_DataBuffer[j][i]; } data[i] = tmpValue/currentBufferSize; } else if (m_ApplyTemporalMedianFilter) { for(int j=0; jm_DataBuffer[j][i]; } data[i] = quick_select(tmpArray, currentBufferSize); } } this->m_DataBufferCurrentIndex = (this->m_DataBufferCurrentIndex + 1) % this->m_DataBufferMaxSize; delete[] tmpArray; } #define ELEM_SWAP(a,b) { register float t=(a);(a)=(b);(b)=t; } float mitk::ToFCompositeFilter::quick_select(float arr[], int n) { int low = 0; int high = n-1; int median = (low + high)/2; int middle = 0; int ll = 0; int hh = 0; for (;;) { if (high <= low) /* One element only */ return arr[median] ; if (high == low + 1) { /* Two elements only */ if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; return arr[median] ; } /* Find median of low, middle and high items; swap into position low */ middle = (low + high) / 2; if (arr[middle] > arr[high]) ELEM_SWAP(arr[middle], arr[high]) ; if (arr[low] > arr[high]) ELEM_SWAP(arr[low], arr[high]) ; if (arr[middle] > arr[low]) ELEM_SWAP(arr[middle], arr[low]) ; /* Swap low item (now in position middle) into position (low+1) */ ELEM_SWAP(arr[middle], arr[low+1]) ; /* Nibble from each end towards middle, swapping items when stuck */ ll = low + 1; hh = high; for (;;) { do ll++; while (arr[low] > arr[ll]) ; do hh--; while (arr[hh] > arr[low]) ; if (hh < ll) break; ELEM_SWAP(arr[ll], arr[hh]) ; } /* Swap middle item (in position low) back into correct position */ ELEM_SWAP(arr[low], arr[hh]) ; /* Re-set active partition */ if (hh <= median) low = ll; if (hh >= median) high = hh - 1; } } #undef ELEM_SWAP void mitk::ToFCompositeFilter::SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames) { this->m_TemporalMedianFilterNumOfFrames = tmporalMedianFilterNumOfFrames; } void mitk::ToFCompositeFilter::SetThresholdFilterParameter(int min, int max) { if (min > max) { min = max; } this->m_ThresholdFilterMin = min; this->m_ThresholdFilterMax = max; } void mitk::ToFCompositeFilter::SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius = 0) { this->m_BilateralFilterDomainSigma = domainSigma; this->m_BilateralFilterRangeSigma = rangeSigma; this->m_BilateralFilterKernelRadius = kernelRadius; } void mitk::ToFCompositeFilter::CreateItkImage(ItkImageType2D::Pointer &itkInputImage) { itkInputImage = ItkImageType2D::New(); ItkImageType2D::IndexType startIndex; startIndex[0] = 0; // first index on X startIndex[1] = 0; // first index on Y ItkImageType2D::SizeType size; size[0] = this->m_ImageWidth; // size along X size[1] = this->m_ImageHeight; // size along Y ItkImageType2D::RegionType region; region.SetSize( size ); region.SetIndex( startIndex ); itkInputImage->SetRegions( region ); itkInputImage->Allocate(); } diff --git a/Modules/ToFProcessing/mitkToFCompositeFilter.h b/Modules/ToFProcessing/mitkToFCompositeFilter.h index e520b96280..cbdc1686cb 100644 --- a/Modules/ToFProcessing/mitkToFCompositeFilter.h +++ b/Modules/ToFProcessing/mitkToFCompositeFilter.h @@ -1,201 +1,201 @@ /*=================================================================== 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 __mitkToFCompositeFilter_h #define __mitkToFCompositeFilter_h #include #include "mitkImageToImageFilter.h" #include -#include #include +#include "opencv2/core.hpp" typedef itk::Image ItkImageType2D; typedef itk::Image ItkImageType3D; typedef itk::BilateralImageFilter BilateralFilterType; namespace mitk { /** * @brief Applies a common filter-pipeline to the first input of this filter * * This class intends to allow quick preprocessing of (ToF) range data. Input 0 of this filter, holding the range image, * is processed using the following image processing filters: * - threshold filter * - mask segmentation * - temporal median filter * - spatial median filter * - bilateral filter * * @ingroup ToFProcessing */ class MITKTOFPROCESSING_EXPORT ToFCompositeFilter : public ImageToImageFilter { public: mitkClassMacro( ToFCompositeFilter , ImageToImageFilter ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkSetMacro(SegmentationMask,mitk::Image::Pointer); itkSetMacro(ApplyTemporalMedianFilter,bool); itkGetConstMacro(ApplyTemporalMedianFilter,bool); itkSetMacro(ApplyAverageFilter,bool); itkGetConstMacro(ApplyAverageFilter,bool); itkSetMacro(ApplyMedianFilter,bool); itkGetConstMacro(ApplyMedianFilter,bool); itkSetMacro(ApplyThresholdFilter,bool); itkGetConstMacro(ApplyThresholdFilter,bool); itkSetMacro(ApplyMaskSegmentation,bool); itkGetConstMacro(ApplyMaskSegmentation,bool); itkSetMacro(ApplyBilateralFilter,bool); itkGetConstMacro(ApplyBilateralFilter,bool); using itk::ProcessObject::SetInput; /*! \brief sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ void SetInput( const InputImageType* distanceImage) override; /*! \brief sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera */ void SetInput(unsigned int idx, const InputImageType* distanceImage) override; /*! \brief returns the input of this filter */ Image* GetInput(); /*! \brief returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); /*! \brief Sets the parameter of the temporal median filter \param tmporalMedianFilterNumOfFrames number of frames to be considered for calulating the temporal median */ void SetTemporalMedianFilterParameter(int tmporalMedianFilterNumOfFrames); /*! \brief Sets the parameters (lower, upper threshold) of the threshold filter \param min lower threshold of the threshold filter \param max upper threshold of the threshold filter */ void SetThresholdFilterParameter(int min, int max); /*! \brief Sets the parameters (domain sigma, range sigma, kernel radius) of the bilateral filter \param domainSigma Parameter controlling the smoothing effect of the bilateral filter. Default value: 2 \param rangeSigma Parameter controlling the edge preserving effect of the bilateral filter. Default value: 60 \param kernelRadius radius of the filter mask of the bilateral filter */ void SetBilateralFilterParameter(double domainSigma, double rangeSigma, int kernelRadius); protected: /*! \brief standard constructor */ ToFCompositeFilter(); /*! \brief standard destructor */ ~ToFCompositeFilter() override; void GenerateOutputInformation() override; /*! \brief method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ void GenerateData() override; /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); /*! \brief Applies a mask and/or threshold segmentation to the input image. All pixels with values outside the mask, below the lower threshold (min) and above the upper threshold (max) are assigned the pixel value 0 */ void ProcessSegmentation(IplImage* inputIplImage); /*! \brief Applies the ITK bilateral filter to the input image See http://www.itk.org/Doxygen320/html/classitk_1_1BilateralImageFilter.html for more details. */ ItkImageType2D::Pointer ProcessItkBilateralFilter(ItkImageType2D::Pointer inputItkImage); /*! \brief Applies the OpenCV bilateral filter to the input image. See http://opencv.willowgarage.com/documentation/c/image_filtering.html#smooth for more details */ void ProcessCVBilateralFilter(IplImage* inputIplImage, IplImage* outputIplImage); /*! \brief Applies the OpenCV median filter to the input image. See http://opencv.willowgarage.com/documentation/c/image_filtering.html#smooth for more details */ void ProcessCVMedianFilter(IplImage* inputIplImage, IplImage* outputIplImage, int radius = 3); /*! \brief Performs temporal median filter on an image given the number of frames to be considered */ void ProcessStreamedQuickSelectMedianImageFilter(IplImage* inputIplImage); /*! \brief Quickselect algorithm * This Quickselect routine is based on the algorithm described in * "Numerical recipes in C", Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5 * This code by Nicolas Devillard - 1998. Public domain. */ float quick_select(float arr[], int n); /*! \brief Initialize and allocate a 2D ITK image of dimension m_ImageWidth*m_ImageHeight */ void CreateItkImage(ItkImageType2D::Pointer &itkInputImage); mitk::Image::Pointer m_SegmentationMask; ///< mask image used for segmenting the image int m_ImageWidth; ///< x-dimension of the image int m_ImageHeight; ///< y-dimension of the image int m_ImageSize; ///< size of the image in bytes IplImage* m_IplDistanceImage; ///< OpenCV-representation of the distance image IplImage* m_IplOutputImage; ///< OpenCV-representation of the output image ItkImageType2D::Pointer m_ItkInputImage; ///< ITK representation of the distance image bool m_ApplyTemporalMedianFilter; ///< Flag indicating if the temporal median filter is currently active for processing the distance image bool m_ApplyAverageFilter; ///< Flag indicating if the average filter is currently active for processing the distance image bool m_ApplyMedianFilter; ///< Flag indicating if the spatial median filter is currently active for processing the distance image bool m_ApplyThresholdFilter; ///< Flag indicating if the threshold filter is currently active for processing the distance image bool m_ApplyMaskSegmentation; ///< Flag indicating if a mask segmentation is performed bool m_ApplyBilateralFilter; ///< Flag indicating if the bilateral filter is currently active for processing the distance image float** m_DataBuffer; ///< Buffer used for calculating the pixel-wise median over the last n (m_TemporalMedianFilterNumOfFrames) number of frames int m_DataBufferCurrentIndex; ///< Current index in the buffer of the temporal median filter int m_DataBufferMaxSize; ///< Maximal size for the buffer of the temporal median filter (m_DataBuffer) int m_TemporalMedianFilterNumOfFrames; ///< Number of frames to be used in the calculation of the temporal median int m_ThresholdFilterMin; ///< Lower threshold of the threshold filter. Pixels with values below will be assigned value 0 when applying the threshold filter int m_ThresholdFilterMax; ///< Lower threshold of the threshold filter. Pixels with values above will be assigned value 0 when applying the threshold filter double m_BilateralFilterDomainSigma; ///< Parameter of the bilateral filter controlling the smoothing effect of the filter. Default value: 2 double m_BilateralFilterRangeSigma; ///< Parameter of the bilateral filter controlling the edge preserving effect of the filter. Default value: 60 int m_BilateralFilterKernelRadius; ///< Kernel radius of the bilateral filter mask }; } //END mitk namespace #endif diff --git a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h index 5ef5de41d2..74ef246548 100644 --- a/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h +++ b/Modules/ToFProcessing/mitkToFDistanceImageToSurfaceFilter.h @@ -1,196 +1,195 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __mitkToFDistanceImageToSurfaceFilter_h #define __mitkToFDistanceImageToSurfaceFilter_h #include #include #include #include #include #include "mitkCameraIntrinsics.h" #include -#include #include #include namespace mitk { /** * @brief Converts a Time-of-Flight (ToF) distance image to a 3D surface using the pinhole camera model for coordinate computation. * The intrinsic parameters of the camera (FocalLength, PrincipalPoint, InterPixelDistance) are set via SetCameraIntrinsics(). The * measured distance for each pixel corresponds to the distance between the object point and the corresponding image point on the * image plane. * * The coordinate conversion follows the model of a common pinhole camera where the origin of the camera * coordinate system (world coordinates) is at the pinhole * \image html ../Modules/ToFProcessing/Documentation/PinholeCameraModel.png * The definition of the image plane and its coordinate systems (pixel and mm) is depicted in the following image * \image html ../Modules/ToFProcessing/Documentation/ImagePlane.png * * @ingroup SurfaceFilters * @ingroup ToFProcessing */ class MITKTOFPROCESSING_EXPORT ToFDistanceImageToSurfaceFilter : public SurfaceSource { public: mitkClassMacro( ToFDistanceImageToSurfaceFilter , SurfaceSource ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkSetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkGetMacro(CameraIntrinsics, mitk::CameraIntrinsics::Pointer); itkSetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkGetMacro(InterPixelDistance,ToFProcessingCommon::ToFPoint2D); itkSetMacro(TextureIndex,int); /** * @brief SetTriangulationThreshold Sets a triangulation threshold in order * to remove unusually huge faces from the surface. If this value is set, * the filter will check whether the distance between two neighboring vertices * exceeds the triangulation threshold. If yes, there vertices will not be * triangulated (connected with lines). The vertices will still be added to * the surface, but only as single point (if they have no other neighbors). * @param triangulationThreshold The triangulationThreshold in mm. (not mm*mm!) * @note vtkMath::Distance2BetweenPoints returns the squared distance * between two points and hence we square m_TriangulationThreshold in * order to save run-time. */ void SetTriangulationThreshold( double triangulationThreshold ); itkGetMacro(TriangulationThreshold, double); itkSetMacro(VertexIdList, vtkSmartPointer); itkGetMacro(VertexIdList, vtkSmartPointer); itkSetMacro(GenerateTriangularMesh,bool); itkGetMacro(GenerateTriangularMesh,bool); /** * @brief The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. */ enum ReconstructionModeType{ WithOutInterPixelDistance = 1, WithInterPixelDistance = 2, Kinect = 3}; itkSetEnumMacro(ReconstructionMode,ReconstructionModeType); itkGetEnumMacro(ReconstructionMode,ReconstructionModeType); /*! \brief Set scalar image used as texture of the surface. \param iplScalarImage OpenCV image for texturing */ void SetScalarImage(IplImage* iplScalarImage); /*! \brief Set scalar image used as texture of the surface. \return OpenCV image for texturing */ IplImage* GetScalarImage(); /*! \brief Set width of the scalar image used for texturing the surface \param width width (x-dimension) of the texture image */ void SetTextureImageWidth(int width); /*! \brief Set height of the scalar image used for texturing the surface \param height height (y-dimension) of the texture image */ void SetTextureImageHeight(int height); using itk::ProcessObject::SetInput; /*! \brief Sets the input of this filter \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage); /*! \brief Sets the input of this filter and the intrinsic parameters \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput( Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \brief Sets the input of this filter at idx \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera */ virtual void SetInput(unsigned int idx, Image* distanceImage); /*! \brief Sets the input of this filter at idx and the intrinsic parameters \param idx number of the current input \param distanceImage input is the distance image of e.g. a ToF camera \param cameraIntrinsics This is the camera model which holds parameters like focal length, pixel size, etc. which are needed for the reconstruction of the surface. */ virtual void SetInput( unsigned int idx, Image* distanceImage, mitk::CameraIntrinsics::Pointer cameraIntrinsics ); /*! \brief Returns the input of this filter */ Image* GetInput(); /*! \brief Returns the input with id idx of this filter */ Image* GetInput(unsigned int idx); protected: /*! \brief Standard constructor */ ToFDistanceImageToSurfaceFilter(); /*! \brief Standard destructor */ ~ToFDistanceImageToSurfaceFilter() override; void GenerateOutputInformation() override; /*! \brief Method generating the output of this filter. Called in the updated process of the pipeline. This method generates the output of the ToFSurfaceSource: The generated surface of the 3d points */ void GenerateData() override; /** * \brief Create an output for each input * * This Method sets the number of outputs to the number of inputs * and creates missing outputs objects. * \warning any additional outputs that exist before the method is called are deleted */ void CreateOutputsForAllInputs(); IplImage* m_IplScalarImage; ///< Scalar image used for surface texturing mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< Specifies the intrinsic parameters int m_TextureImageWidth; ///< Width (x-dimension) of the texture image int m_TextureImageHeight; ///< Height (y-dimension) of the texture image ToFProcessingCommon::ToFPoint2D m_InterPixelDistance; ///< distance in mm between two adjacent pixels on the ToF camera chip int m_TextureIndex; ///< Index of the input used as texture image when no scalar image was set via SetIplScalarImage(). 0 = Distance, 1 = Amplitude, 2 = Intensity bool m_GenerateTriangularMesh; ReconstructionModeType m_ReconstructionMode; ///< The ReconstructionModeType enum: Defines the reconstruction mode, if using no interpixeldistances and focal lenghts in pixel units or interpixeldistances and focal length in mm. The Kinect option defines a special reconstruction mode for the kinect. vtkSmartPointer m_VertexIdList; ///< Make a vtkIdList to save the ID's of the polyData corresponding to the image pixel ID's. This can be accessed after generate data to obtain the mapping. double m_TriangulationThreshold; }; } //END mitk namespace #endif diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp index 6a24e17155..2077361fa9 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp @@ -1,283 +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. ===================================================================*/ #include #include #include #include #include const std::string QmitkToFCompositeFilterWidget::VIEW_ID = "org.mitk.views.qmitktofcompositefilterwidget"; QmitkToFCompositeFilterWidget::QmitkToFCompositeFilterWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { this->m_ToFCompositeFilter = nullptr; m_Controls = nullptr; CreateQtPartControl(this); } QmitkToFCompositeFilterWidget::~QmitkToFCompositeFilterWidget() { } void QmitkToFCompositeFilterWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFCompositeFilterWidgetControls; m_Controls->setupUi(parent); int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); m_Controls->m_ThresholdFilterRangeSlider->setMinimum(min); m_Controls->m_ThresholdFilterRangeSlider->setMaximum(max); m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(min); m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(max); this->CreateConnections(); this->OnShowAdvancedOptionsCheckboxChecked(false); } } void QmitkToFCompositeFilterWidget::CreateConnections() { if ( m_Controls ) { connect(m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int))); connect(m_Controls->m_BilateralFilterDomainSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterDomainSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterRangeSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterRangeSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterKernelRadiusSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnBilateralFilterKernelRadiusSpinBoxValueChanged(int))); connect(m_Controls->m_ThresholdFilterMinValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMinValueChanged(int))); connect(m_Controls->m_ThresholdFilterMaxValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMaxValueChanged(int))); connect( (QObject*)(m_Controls->m_TemporalMedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTemporalMedianFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_AverageFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnAverageFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_ThresholdFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnThresholdFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->maskSegmentationCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMaskSegmentationCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_BilateralFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnBilateralFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_MedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMedianFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptionsCheckboxChecked(bool)) ); - connect(m_Controls->m_ThresholdFilterRangeSlider, SIGNAL(spanChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); + connect(m_Controls->m_ThresholdFilterRangeSlider, SIGNAL(valuesChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); //reset button connect(m_Controls->m_ThresholdFilterRangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetThresholdFilterRangeSlider())); } } void QmitkToFCompositeFilterWidget::SetToFCompositeFilter(mitk::ToFCompositeFilter* toFCompositeFilter) { this->m_ToFCompositeFilter = toFCompositeFilter; } mitk::ToFCompositeFilter* QmitkToFCompositeFilterWidget::GetToFCompositeFilter() { if (this->m_ToFCompositeFilter.IsNull()) { this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); } return this->m_ToFCompositeFilter; } void QmitkToFCompositeFilterWidget::SetDataStorage(mitk::DataStorage::Pointer dataStorage) { m_DataStorage = dataStorage; m_Controls->maskImageComboBox->SetDataStorage(dataStorage); m_Controls->maskImageComboBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateDataType::New("Image"),mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)))); } void QmitkToFCompositeFilterWidget::UpdateFilterParameter() { OnTemporalMedianFilterCheckBoxChecked(m_Controls->m_TemporalMedianFilterCheckBox->isChecked()); OnAverageFilterCheckBoxChecked(m_Controls->m_AverageFilterCheckBox->isChecked()); OnMedianFilterCheckBoxChecked(m_Controls->m_MedianFilterCheckBox->isChecked()); OnThresholdFilterCheckBoxChecked(m_Controls->m_ThresholdFilterCheckBox->isChecked()); OnBilateralFilterCheckBoxChecked(m_Controls->m_BilateralFilterCheckBox->isChecked()); } void QmitkToFCompositeFilterWidget::SetWidgetConfiguration(bool threshold, bool mask, bool tempMedian, bool tempAverage, bool median, bool bilateral ) { m_Controls->m_ThresholdFilterCheckBox->setChecked(threshold); m_Controls->maskSegmentationCheckBox->setChecked(mask); m_Controls->m_TemporalMedianFilterCheckBox->setChecked(tempMedian); m_Controls->m_AverageFilterCheckBox->setChecked(tempAverage); m_Controls->m_MedianFilterCheckBox->setChecked(median); m_Controls->m_BilateralFilterCheckBox->setChecked(bilateral); } void QmitkToFCompositeFilterWidget::SetStandardParametersBilateralFilter(double domainSigma, double rangeSigma, int kernelRadius) { m_Controls->m_BilateralFilterDomainSigmaSpinBox->setValue(domainSigma); m_Controls->m_BilateralFilterRangeSigmaSpinBox->setValue(rangeSigma); m_Controls->m_BilateralFilterKernelRadiusSpinBox->setValue(kernelRadius); } void QmitkToFCompositeFilterWidget::SetStandardParametersThresholdFilter(int min, int max) { m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(min); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(max); } void QmitkToFCompositeFilterWidget::SetStandardParameterTemporalAveraging(int nImages) { m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox->setValue(nImages); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(checked); // disable average filter if temporal median filter is enabled if (checked) { m_Controls->m_AverageFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyAverageFilter(false); } } void QmitkToFCompositeFilterWidget::OnAverageFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyAverageFilter(checked); // disable temporal median filter if average filter is enabled if (checked) { m_Controls->m_TemporalMedianFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(false); } } void QmitkToFCompositeFilterWidget::OnShowAdvancedOptionsCheckboxChecked(bool checked) { this->m_Controls->m_AverageFilterCheckBox->setVisible(checked); this->m_Controls->m_BilateralFilterCheckBox->setVisible(checked); this->m_Controls->m_BilateralFilterDomainSigmaSpinBox->setVisible(checked); this->m_Controls->m_BilateralFilterKernelRadiusSpinBox->setVisible(checked); this->m_Controls->m_BilateralFilterRangeSigmaSpinBox->setVisible(checked); this->m_Controls->m_MedianFilterCheckBox->setVisible(checked); this->m_Controls->m_TemporalMedianFilterCheckBox->setVisible(checked); this->m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterCheckBox->setVisible(checked); this->m_Controls->m_ThresholdFilterMaxValueSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterMinValueSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterRangeSlider->setVisible(checked); this->m_Controls->m_ThresholdFilterRangeSliderReset->setVisible(checked); this->m_Controls->label_3->setVisible(checked); this->m_Controls->label_4->setVisible(checked); this->m_Controls->label_12->setVisible(checked); this->m_Controls->maskImageComboBox->setVisible(checked); this->m_Controls->maskSegmentationCheckBox->setVisible(checked); } void QmitkToFCompositeFilterWidget::OnThresholdFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyThresholdFilter(checked); } void QmitkToFCompositeFilterWidget::OnMaskSegmentationCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyMaskSegmentation(checked); if (checked) { mitk::DataNode::Pointer maskImageNode = m_Controls->maskImageComboBox->GetSelectedNode(); if (maskImageNode.IsNotNull()) { mitk::Image::Pointer maskImage = dynamic_cast(maskImageNode->GetData()); this->m_ToFCompositeFilter->SetSegmentationMask(maskImage); } } } void QmitkToFCompositeFilterWidget::OnMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyMedianFilter(checked); } void QmitkToFCompositeFilterWidget::OnBilateralFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyBilateralFilter(checked); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int value) { this->m_ToFCompositeFilter->SetTemporalMedianFilterParameter(value); } void QmitkToFCompositeFilterWidget::OnBilateralFilterDomainSigmaSpinBoxValueChanged(double) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterRangeSigmaSpinBoxValueChanged(double) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterKernelRadiusSpinBoxValueChanged(int) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMinValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMaxValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::SetThresholdFilterParameter() { int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); this->m_ToFCompositeFilter->SetThresholdFilterParameter(min, max); } void QmitkToFCompositeFilterWidget::SetBilateralFilterParameter() { double domainSigma = m_Controls->m_BilateralFilterDomainSigmaSpinBox->value(); double rangeSigma = m_Controls->m_BilateralFilterRangeSigmaSpinBox->value(); int kernelRadius = m_Controls->m_BilateralFilterKernelRadiusSpinBox->value(); this->m_ToFCompositeFilter->SetBilateralFilterParameter(domainSigma, rangeSigma, kernelRadius); } void QmitkToFCompositeFilterWidget::OnSpanChanged(int, int) { int lowerVal = m_Controls->m_ThresholdFilterRangeSlider->minimumValue(); int upperVal = m_Controls->m_ThresholdFilterRangeSlider->maximumValue(); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lowerVal); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upperVal); } void QmitkToFCompositeFilterWidget::OnResetThresholdFilterRangeSlider() { int lower = 1; int upper = 7000; m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(lower); m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(upper); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lower); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upper); } diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui index 81ff4de855..49cf34efda 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui @@ -1,244 +1,247 @@ QmitkToFCompositeFilterWidgetControls 0 0 467 210 0 0 QmitkToFCompositeFilter 11 ToF Preprocessing Show Advanced Options Threshold Filter 7000 0 QFrame::StyledPanel QFrame::Raised 0 - + + 0 + + + 0 + + + 0 + + 0 modify actual seen window by dragging left and right slider. Qt::Horizontal - + 0 0 - - - 48 - 16777215 - - Resets range to histogram minimum and maximum. Reset 7000 7000 Mask segmentation true Median Filter (t) Average Filter 100 10 true Median Filter Bilateral Filter σ_d: 2.000000000000000 σ_r: 60.000000000000000 radius: ctkRangeSlider - QWidget + QSlider
ctkRangeSlider.h
QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui index 6b35d713fc..fcca8f0608 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui @@ -1,175 +1,196 @@ QmitkToFConnectionWidgetControls2 0 0 579 229 + + + 0 + 0 + + 0 0 QmitkToFConnection - - - - - - - - - - + + + + 0 + 0 + + + 0 0 0 100 16777215 100 false 0 0 200 80 16777215 80 10 Connect to camera Connect :/images/powerRed.png :/images/powerGreen.png:/images/powerRed.png 30 30 true 11 ToF camera connection - - - - Qt::Vertical + + + + + 0 + 0 + - - - 20 - 40 - + + + + + + + 0 + 0 + - + + + + + + + 0 + 0 + + + QmitkToFPMDParameterWidget QWidget
QmitkToFPMDParameterWidget.h
1
QmitkToFMESAParameterWidget QWidget
QmitkToFMESAParameterWidget.h
1
QmitkKinectParameterWidget QWidget
QmitkKinectParameterWidget.h
1
QmitkServiceListWidget QWidget
QmitkServiceListWidget.h
1
QmitkStructureSensorParameterWidget QWidget
QmitkStructureSensorParameterWidget.h
1
diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp index 8275fa8aca..ad033b8a4f 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp @@ -1,442 +1,533 @@ /*=================================================================== 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 "QmitkToFPointSetWidget.h" +#include #include #include const std::string QmitkToFPointSetWidget::VIEW_ID = "org.mitk.views.qmitktofpointsetwidget"; -QmitkToFPointSetWidget::QmitkToFPointSetWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) +QmitkToFPointSetWidget::QmitkToFPointSetWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) , m_DataStorage(nullptr) , m_DistanceImage(nullptr) , m_CameraIntrinsics(nullptr) -, m_VtkTextActor(nullptr) -, m_ForegroundRenderer1(nullptr) -, m_ForegroundRenderer2(nullptr) -, m_ForegroundRenderer3(nullptr) -, m_RenderWindow1(nullptr) -, m_RenderWindow2(nullptr) -, m_RenderWindow3(nullptr) +, m_TextAnnotationAxial(nullptr) +, m_TextAnnotationSagittal(nullptr) +, m_TextAnnotationCoronal(nullptr) +, m_TextAnnotation3D(nullptr) +, m_RendererAxial(nullptr) +, m_RendererSagittal(nullptr) +, m_RendererCoronal(nullptr) +, m_Renderer3D(nullptr) , m_MeasurementPointSet2D(nullptr) , m_MeasurementPointSet3DNode(nullptr) , m_PointSet2D(nullptr) , m_PointSet3DNode(nullptr) , m_PointSetInteractor(nullptr) , m_MeasurementPointSetInteractor(nullptr) , m_MeasurementPointSetChangedObserverTag(0) , m_PointSetChangedObserverTag(0) , m_WindowHeight(0) { m_Controls = nullptr; CreateQtPartControl(this); } QmitkToFPointSetWidget::~QmitkToFPointSetWidget() { this->CleanUpWidget(); } void QmitkToFPointSetWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFPointSetWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFPointSetWidget::CreateConnections() { - if ( m_Controls ) + if (m_Controls) { - connect( (QObject*)(m_Controls->measureButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnMeasurement()) ); - connect( (QObject*)(m_Controls->pointSetButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnPointSet()) ); + connect((QObject*)(m_Controls->measureButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnMeasurement())); + connect((QObject*)(m_Controls->pointSetButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnPointSet())); } } void QmitkToFPointSetWidget::InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics) { // initialize members m_CameraIntrinsics = cameraIntrinsics; m_DataStorage = dataStorage; - // m_RenderWindowPart = renderWindowPart; - m_RenderWindow1 = renderWindowHashMap.value("axial")->GetRenderWindow(); - m_RenderWindow2 = renderWindowHashMap.value("sagittal")->GetRenderWindow(); - m_RenderWindow3 = renderWindowHashMap.value("coronal")->GetRenderWindow(); - m_RenderWindow4 = renderWindowHashMap.value("3d")->GetRenderWindow(); - if ((m_RenderWindow1 != nullptr) && (m_RenderWindow2 != nullptr) && (m_RenderWindow3 != nullptr) && (m_RenderWindow4 != nullptr) && (dataStorage.IsNotNull())) + // Get renderers of render windows + m_RendererAxial = renderWindowHashMap.value("axial")->GetRenderer(); + m_RendererSagittal = renderWindowHashMap.value("sagittal")->GetRenderer(); + m_RendererCoronal = renderWindowHashMap.value("coronal")->GetRenderer(); + m_Renderer3D = renderWindowHashMap.value("3d")->GetRenderer(); + if ((m_RendererAxial.IsNotNull()) && (m_RendererSagittal.IsNotNull()) && (m_RendererCoronal.IsNotNull()) && (m_Renderer3D.IsNotNull()) && (dataStorage.IsNotNull())) { // enable buttons m_Controls->pointSetButton->setEnabled(true); m_Controls->measureButton->setEnabled(true); - // initialize overlays - this->m_VtkTextActor = vtkSmartPointer::New(); - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); - m_WindowHeight = renderWindowHashMap.value("axial")->GetRenderer()->GetSizeY(); - this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); - this->m_VtkTextActor->GetTextProperty()->SetFontSize(16); - // this->m_VtkTextActor->GetTextProperty()->SetColor(1,0,0); - this->m_VtkTextActor->GetTextProperty()->BoldOn(); - this->m_VtkTextActor->SetVisibility(0); - if (m_ForegroundRenderer1==nullptr) - { - this->m_ForegroundRenderer1 = vtkSmartPointer::New(); - this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); - } - if (m_ForegroundRenderer2==nullptr) - { - this->m_ForegroundRenderer2 = vtkSmartPointer::New(); - this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); - } - if (m_ForegroundRenderer3==nullptr) - { - this->m_ForegroundRenderer3 =vtkSmartPointer::New(); - this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); - } - mitk::DataNode::Pointer measurementPointSet2DNode = dataStorage->GetNamedNode("Measurement PointSet 2D") ; - if(dataStorage->Exists(measurementPointSet2DNode)) + // initialize axial text annotation + m_TextAnnotationAxial = mitk::TextAnnotation2D::New(); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetFontSize(16); + m_TextAnnotationAxial->SetColor(1, 0, 0); + m_TextAnnotationAxial->SetOpacity(1); + m_WindowHeight = m_RendererAxial->GetSizeY(); + mitk::Point2D axialAnnotationPosition; + axialAnnotationPosition[0] = 10; + axialAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationAxial->SetPosition2D(axialAnnotationPosition); + m_TextAnnotationAxial->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationAxial, m_RendererAxial); + // initialize sagittal text annotation + m_TextAnnotationSagittal = mitk::TextAnnotation2D::New(); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetFontSize(16); + m_TextAnnotationSagittal->SetColor(1, 0, 0); + m_TextAnnotationSagittal->SetOpacity(1); + m_WindowHeight = m_RendererSagittal->GetSizeY(); + mitk::Point2D sagittalAnnotationPosition; + sagittalAnnotationPosition[0] = 10; + sagittalAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationSagittal->SetPosition2D(sagittalAnnotationPosition); + m_TextAnnotationSagittal->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationSagittal, m_RendererSagittal); + // initialize coronal text annotation + m_TextAnnotationCoronal = mitk::TextAnnotation2D::New(); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetFontSize(16); + m_TextAnnotationCoronal->SetColor(1, 0, 0); + m_TextAnnotationCoronal->SetOpacity(1); + m_WindowHeight = m_RendererCoronal->GetSizeY(); + mitk::Point2D coronalAnnotationPosition; + coronalAnnotationPosition[0] = 10; + coronalAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationCoronal->SetPosition2D(coronalAnnotationPosition); + m_TextAnnotationCoronal->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationCoronal, m_RendererCoronal); + // initialize 3D text annotation + m_TextAnnotation3D = mitk::TextAnnotation2D::New(); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetFontSize(16); + m_TextAnnotation3D->SetColor(1, 0, 0); + m_TextAnnotation3D->SetOpacity(1); + m_WindowHeight = m_Renderer3D->GetSizeY(); + mitk::Point2D annotationPosition3D; + annotationPosition3D[0] = 10; + annotationPosition3D[0] = m_WindowHeight - 30; + m_TextAnnotation3D->SetPosition2D(annotationPosition3D); + m_TextAnnotation3D->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation3D, m_Renderer3D); + + //mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation, renderWindowHashMap.value("axial")->GetRenderer()); + //mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation, renderWindowHashMap.value("coronal")->GetRenderer()); + + //// initialize overlays + //this->m_VtkTextActor = vtkSmartPointer::New(); + //this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + //m_WindowHeight = renderWindowHashMap.value("axial")->GetRenderer()->GetSizeY(); + ////this->m_VtkTextActor->SetDisplayPosition(10, m_WindowHeight - 30); + //this->m_VtkTextActor->SetDisplayPosition(50, 50); + //this->m_VtkTextActor->GetTextProperty()->SetFontSize(16); + ////this->m_VtkTextActor->GetTextProperty()->SetColor(1, 0, 0); + //this->m_VtkTextActor->GetTextProperty()->BoldOn(); + //this->m_VtkTextActor->SetVisibility(1); + //if (m_ForegroundRenderer1==nullptr) + //{ + // this->m_ForegroundRenderer1 = vtkSmartPointer::New(); + // this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); + //} + //if (m_ForegroundRenderer2==nullptr) + //{ + // this->m_ForegroundRenderer2 = vtkSmartPointer::New(); + // this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); + //} + //if (m_ForegroundRenderer3==nullptr) + //{ + // this->m_ForegroundRenderer3 =vtkSmartPointer::New(); + // this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); + //} + + mitk::DataNode::Pointer measurementPointSet2DNode = dataStorage->GetNamedNode("Measurement PointSet 2D"); + if (dataStorage->Exists(measurementPointSet2DNode)) { dataStorage->Remove(measurementPointSet2DNode); } // initialize 2D measurement point set m_MeasurementPointSet2D = mitk::PointSet::New(); measurementPointSet2DNode = mitk::DataNode::New(); measurementPointSet2DNode->SetName("Measurement PointSet 2D"); - measurementPointSet2DNode->SetBoolProperty("helper object",true); - measurementPointSet2DNode->SetBoolProperty("show contour",true); + measurementPointSet2DNode->SetBoolProperty("helper object", true); + measurementPointSet2DNode->SetBoolProperty("show contour", true); measurementPointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); measurementPointSet2DNode->SetData(m_MeasurementPointSet2D); dataStorage->Add(measurementPointSet2DNode); m_MeasurementPointSetInteractor = mitk::PointSetDataInteractor::New(); m_MeasurementPointSetInteractor->LoadStateMachine("PointSet.xml"); m_MeasurementPointSetInteractor->SetEventConfig("PointSetConfig.xml"); m_MeasurementPointSetInteractor->SetDataNode(measurementPointSet2DNode); m_MeasurementPointSetInteractor->SetMaxPoints(2); // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer measurementPointSetChangedCommand; measurementPointSetChangedCommand = itk::SimpleMemberCommand::New(); measurementPointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); m_MeasurementPointSetChangedObserverTag = m_MeasurementPointSet2D->AddObserver(itk::ModifiedEvent(), measurementPointSetChangedCommand); // initialize 3D measurement PointSet m_MeasurementPointSet3DNode = dataStorage->GetNamedNode("Measurement PointSet 3D"); - if(dataStorage->Exists(m_MeasurementPointSet3DNode)) + if (dataStorage->Exists(m_MeasurementPointSet3DNode)) { dataStorage->Remove(m_MeasurementPointSet3DNode); } m_MeasurementPointSet3DNode = mitk::DataNode::New(); m_MeasurementPointSet3DNode->SetName("Measurement PointSet 3D"); - m_MeasurementPointSet3DNode->SetBoolProperty("helper object",true); - m_MeasurementPointSet3DNode->SetBoolProperty("show contour",true); - m_MeasurementPointSet3DNode->SetFloatProperty("pointsize",5.0f); + m_MeasurementPointSet3DNode->SetBoolProperty("helper object", true); + m_MeasurementPointSet3DNode->SetBoolProperty("show contour", true); + m_MeasurementPointSet3DNode->SetFloatProperty("pointsize", 5.0f); mitk::PointSet::Pointer measurementPointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); dataStorage->Add(m_MeasurementPointSet3DNode); // initialize PointSets - mitk::DataNode::Pointer pointSet2DNode = dataStorage->GetNamedNode("ToF PointSet 2D") ; - if(dataStorage->Exists(pointSet2DNode)) + mitk::DataNode::Pointer pointSet2DNode = dataStorage->GetNamedNode("ToF PointSet 2D"); + if (dataStorage->Exists(pointSet2DNode)) { dataStorage->Remove(pointSet2DNode); } m_PointSet2D = mitk::PointSet::New(); pointSet2DNode = mitk::DataNode::New(); pointSet2DNode->SetName("ToF PointSet 2D"); pointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); pointSet2DNode->SetData(m_PointSet2D); dataStorage->Add(pointSet2DNode); m_PointSetInteractor = mitk::PointSetDataInteractor::New(); m_PointSetInteractor->LoadStateMachine("PointSet.xml"); m_PointSetInteractor->SetEventConfig("PointSetConfig.xml"); m_PointSetInteractor->SetDataNode(pointSet2DNode); // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer pointSetChangedCommand; pointSetChangedCommand = itk::SimpleMemberCommand::New(); pointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::PointSetChanged); m_PointSetChangedObserverTag = m_PointSet2D->AddObserver(itk::ModifiedEvent(), pointSetChangedCommand); // initialize 3D point set mitk::DataNode::Pointer pointSet3DNode = dataStorage->GetNamedNode("ToF PointSet 3D"); - if(dataStorage->Exists(pointSet3DNode)) + if (dataStorage->Exists(pointSet3DNode)) { dataStorage->Remove(pointSet3DNode); } m_PointSet3DNode = mitk::DataNode::New(); m_PointSet3DNode->SetName("ToF PointSet 3D"); - m_PointSet3DNode->SetFloatProperty("pointsize",5.0f); + m_PointSet3DNode->SetFloatProperty("pointsize", 5.0f); mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_PointSet3DNode->SetData(pointSet3D); dataStorage->Add(m_PointSet3DNode); } } void QmitkToFPointSetWidget::CleanUpWidget() { // toggle button state if (m_Controls->measureButton->isChecked()) { m_Controls->measureButton->setChecked(false); this->OnMeasurement(); } if (m_Controls->pointSetButton->isChecked()) { m_Controls->pointSetButton->setChecked(false); this->OnPointSet(); } // remove observer if (m_MeasurementPointSet2D.IsNotNull()) { m_MeasurementPointSet2D->RemoveObserver(m_MeasurementPointSetChangedObserverTag); } if (m_PointSet2D.IsNotNull()) { m_PointSet2D->RemoveObserver(m_PointSetChangedObserverTag); } -// if (m_DistanceImage.IsNotNull()) -// { -// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); -// } - // remove foreground renderer - if (m_ForegroundRenderer1&&m_RenderWindow1) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); - } - m_ForegroundRenderer1 = nullptr; - } - if (m_ForegroundRenderer2&&m_RenderWindow2) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); - } - m_ForegroundRenderer2 = nullptr; - } - if (m_ForegroundRenderer3&&m_RenderWindow3) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); - } - m_ForegroundRenderer3 = nullptr; - } + // if (m_DistanceImage.IsNotNull()) + // { + // m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); + // } + //// remove foreground renderer + //if (m_ForegroundRenderer1&&m_RenderWindow1) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); + // } + // m_ForegroundRenderer1 = nullptr; + //} + //if (m_ForegroundRenderer2&&m_RenderWindow2) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); + // } + // m_ForegroundRenderer2 = nullptr; + //} + //if (m_ForegroundRenderer3&&m_RenderWindow3) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); + // } + // m_ForegroundRenderer3 = nullptr; + //} if (mitk::RenderingManager::GetInstance()) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkToFPointSetWidget::SetDistanceImage(mitk::Image::Pointer distanceImage) { -// // remove existing observer -// if (m_DistanceImage.IsNotNull()) -// { -// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); -// } + // // remove existing observer + // if (m_DistanceImage.IsNotNull()) + // { + // m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); + // } m_DistanceImage = distanceImage; -// // create observer for m_DistanceImage -// itk::SimpleMemberCommand::Pointer distanceImageChangedCommand; -// distanceImageChangedCommand = itk::SimpleMemberCommand::New(); -// distanceImageChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); -// m_DistanceImageChangedObserverTag = m_DistanceImage->AddObserver(itk::ModifiedEvent(), distanceImageChangedCommand); + // // create observer for m_DistanceImage + // itk::SimpleMemberCommand::Pointer distanceImageChangedCommand; + // distanceImageChangedCommand = itk::SimpleMemberCommand::New(); + // distanceImageChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); + // m_DistanceImageChangedObserverTag = m_DistanceImage->AddObserver(itk::ModifiedEvent(), distanceImageChangedCommand); } void QmitkToFPointSetWidget::SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics) { m_CameraIntrinsics = cameraIntrinsics; } void QmitkToFPointSetWidget::OnMeasurement() { // always show 2D PointSet in foreground mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("Measurement PointSet 2D"); if (pointSetNode.IsNotNull()) { - pointSetNode->SetIntProperty("layer",100); + pointSetNode->SetIntProperty("layer", 100); } if (m_Controls->measureButton->isChecked()) { // disable point set interaction if (m_Controls->pointSetButton->isChecked()) { m_Controls->pointSetButton->setChecked(false); // remove interactor m_PointSetInteractor->EnableInteraction(false); } // show overlays - m_VtkTextActor->SetVisibility(1); - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetVisibility(true); + m_TextAnnotationSagittal->SetVisibility(true); + m_TextAnnotationCoronal->SetVisibility(true); + m_TextAnnotation3D->SetVisibility(true); // enable interactor m_MeasurementPointSetInteractor->EnableInteraction(true); // initial update of measurement this->MeasurementPointSetChanged(); } else { // hide overlays - m_VtkTextActor->SetVisibility(0); + m_TextAnnotationAxial->SetVisibility(false); + m_TextAnnotationSagittal->SetVisibility(false); + m_TextAnnotationCoronal->SetVisibility(false); + m_TextAnnotation3D->SetVisibility(false); // disable interactor m_MeasurementPointSetInteractor->EnableInteraction(false); } } void QmitkToFPointSetWidget::OnPointSet() { // always show 2D PointSet in foreground mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("ToF PointSet 2D"); if (pointSetNode.IsNotNull()) { - pointSetNode->SetIntProperty("layer",100); + pointSetNode->SetIntProperty("layer", 100); } if (m_Controls->pointSetButton->isChecked()) { // disable measurement if (m_Controls->measureButton->isChecked()) { m_Controls->measureButton->setChecked(false); // remove interactor m_MeasurementPointSetInteractor->EnableInteraction(false); } // show overlays - m_VtkTextActor->SetVisibility(1); - this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationAxial->SetVisibility(true); + m_TextAnnotationSagittal->SetVisibility(true); + m_TextAnnotationCoronal->SetVisibility(true); + m_TextAnnotation3D->SetVisibility(true); // enable interactor m_PointSetInteractor->EnableInteraction(true); // initial update of PointSet this->PointSetChanged(); } else { // hide overlays - m_VtkTextActor->SetVisibility(0); + m_TextAnnotationAxial->SetVisibility(false); + m_TextAnnotationSagittal->SetVisibility(false); + m_TextAnnotationCoronal->SetVisibility(false); + m_TextAnnotation3D->SetVisibility(false); // disable interactor m_PointSetInteractor->EnableInteraction(false); } } void QmitkToFPointSetWidget::MeasurementPointSetChanged() { - // replace text actor - this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); - if (m_MeasurementPointSet2D->GetSize()==2) + if (m_MeasurementPointSet2D->GetSize() == 2) { // check if points are inside the image range int imageSizeX = m_DistanceImage->GetDimensions()[0]; int imageSizeY = m_DistanceImage->GetDimensions()[1]; mitk::Point3D point1 = m_MeasurementPointSet2D->GetPoint(0); mitk::Point3D point2 = m_MeasurementPointSet2D->GetPoint(1); - if ((point1[0]>=0.0f)&&(point1[0]=0)&&(point1[1]=0.0f)&&(point2[0]=0)&&(point2[1]= 0.0f) && (point1[0] < imageSizeX) && (point1[1] >= 0) && (point1[1] < imageSizeY) && + (point2[0] >= 0.0f) && (point2[0] < imageSizeX) && (point2[1] >= 0) && (point2[1] < imageSizeY)) { // create PointSet filter mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); if (m_CameraIntrinsics.IsNotNull()) { toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); } toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); toFDistanceImageToPointSetFilter->SetSubset(m_MeasurementPointSet2D); toFDistanceImageToPointSetFilter->Update(); mitk::PointSet::Pointer measurementPointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); // calculate distance between points - if (measurementPointSet3D->GetSize()==2) + if (measurementPointSet3D->GetSize() == 2) { mitk::Point3D point1 = measurementPointSet3D->GetPoint(0); mitk::Point3D point2 = measurementPointSet3D->GetPoint(1); float distance = point1.EuclideanDistanceTo(point2); std::stringstream stream; - stream<m_VtkTextActor->SetInput(stream.str().c_str()); + stream << distance << " mm"; + m_TextAnnotationAxial->SetText(stream.str().c_str()); + m_TextAnnotationSagittal->SetText(stream.str().c_str()); + m_TextAnnotationCoronal->SetText(stream.str().c_str()); + m_TextAnnotation3D->SetText(stream.str().c_str()); + //this->m_VtkTextActor->SetInput(stream.str().c_str()); } else { - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); } } else { - this->m_VtkTextActor->SetInput("Measurement outside image range."); + this->m_TextAnnotationAxial->SetText("Measurement outside image range."); + this->m_TextAnnotationSagittal->SetText("Measurement outside image range."); + this->m_TextAnnotationCoronal->SetText("Measurement outside image range."); + this->m_TextAnnotation3D->SetText("Measurement outside image range."); } } else { // initialize 3D pointset empty mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(pointSet3D); } } void QmitkToFPointSetWidget::PointSetChanged() { if (m_DistanceImage.IsNotNull()) { - int imageSizeX = m_DistanceImage->GetDimensions()[0]; - int imageSizeY = m_DistanceImage->GetDimensions()[1]; - int pointSetValid = 1; - for (int i=0; iGetSize(); i++) - { - mitk::Point3D currentPoint = m_PointSet2D->GetPoint(i); - if ((currentPoint[0]>=0.0f)&&(currentPoint[0]=0)&&(currentPoint[1]GetDimensions()[0]; + int imageSizeY = m_DistanceImage->GetDimensions()[1]; + int pointSetValid = 1; + for (int i = 0; i < m_PointSet2D->GetSize(); i++) { - pointSetValid*=0; + mitk::Point3D currentPoint = m_PointSet2D->GetPoint(i); + if ((currentPoint[0] >= 0.0f) && (currentPoint[0] < imageSizeX) && (currentPoint[1] >= 0) && (currentPoint[1] < imageSizeY)) + { + pointSetValid *= 1; + } + else + { + pointSetValid *= 0; + } } - } - if (m_PointSet2D->GetSize()>0) - { - if (pointSetValid) + if (m_PointSet2D->GetSize() > 0) { - // create PointSet filter - mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); - if (m_CameraIntrinsics.IsNotNull()) + if (pointSetValid) { - toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); + // create PointSet filter + mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); + if (m_CameraIntrinsics.IsNotNull()) + { + toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); + } + toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); + toFDistanceImageToPointSetFilter->SetSubset(m_PointSet2D); + toFDistanceImageToPointSetFilter->Update(); + mitk::PointSet::Pointer pointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); + m_PointSet3DNode->SetData(pointSet3D); + this->m_TextAnnotation3D->SetText("Choose points with SHIFT+Click"); } - toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); - toFDistanceImageToPointSetFilter->SetSubset(m_PointSet2D); - toFDistanceImageToPointSetFilter->Update(); - mitk::PointSet::Pointer pointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); - m_PointSet3DNode->SetData(pointSet3D); - this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); } + else + { + this->m_TextAnnotation3D->SetText("Point set outside image range."); + } + } else { - this->m_VtkTextActor->SetInput("Point set outside image range."); + // initialize 3D pointset empty + mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); + m_PointSet3DNode->SetData(pointSet3D); } } - else - { - // initialize 3D pointset empty - mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); - m_PointSet3DNode->SetData(pointSet3D); - } - } } diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h index 0b79b6ff13..1dd799368f 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h @@ -1,147 +1,148 @@ /*=================================================================== 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 _QmitkToFPointSetWidget_H_INCLUDED #define _QmitkToFPointSetWidget_H_INCLUDED #include #include "ui_QmitkToFPointSetWidgetControls.h" //mitk headers #include #include #include #include #include +#include #include //Qmitk headers #include // vtk includes #include #include #include /** * @brief Widget allowing interaction with point sets for measurement and PointSet definition * * The widget allows to * 1. Measure the distance between two points in 3D ToF space by clicking the points in the 2D slices * 2. Defining a ToF PointSet both in 2D and 3D. CameraIntrinsics are used for calculation between 2D and 3D * * NOTE: * You have to make sure that the widget is initialized at a position in the plugin using it, where the distance * image is available. CleanUp has to be called to make sure that all observers and renderers are removed correctly. * * @ingroup ToFUI */ class MITKTOFUI_EXPORT QmitkToFPointSetWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkToFPointSetWidget(QWidget* p = nullptr, Qt::WindowFlags f1 = nullptr); ~QmitkToFPointSetWidget() override; /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); /*! \brief initializes the widget. Observers to the change events of the point sets are created, text actors are activated to be rendered into the foreground of the render window. \param stdMultiWidget QmitkStdMultiWidget used for painting overlays for measurement \param dataStorage DataStorage to add PointSets \param distanceImage range image used to calculate 3D PointSet from 2D index */ void InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics=nullptr); /*! \brief cleans up the widget when it's functionality is not used anymore. Removes observers and deletes foreground renderer */ void CleanUpWidget(); /*! \brief set the image holding the distance information used for measuring */ void SetDistanceImage(mitk::Image::Pointer distanceImage); /*! \brief Set intrinsic parameters of the used device */ void SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics); signals: protected slots: /*! \brief Activates the interactor for the measurement point set */ void OnMeasurement(); /*! \brief Activates the interactor for the point set */ void OnPointSet(); protected: /*! \brief function called when the 2D measurement PointSet has changed */ void MeasurementPointSetChanged(); /*! \brief function called when the 2D PointSet has changed */ void PointSetChanged(); Ui::QmitkToFPointSetWidgetControls* m_Controls; ///< member holding the UI elements of this widget mitk::DataStorage::Pointer m_DataStorage; ///< member holding the set DataStorage mitk::Image::Pointer m_DistanceImage; ///< image holding the range data of the ToF camera mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< intrinsic parameters of the camera - vtkSmartPointer m_VtkTextActor; ///< actor containing the text of the overlay - vtkSmartPointer m_ForegroundRenderer1; ///< renderer responsible for text rendering in the foreground of widget 1 - vtkSmartPointer m_ForegroundRenderer2; ///< renderer responsible for text rendering in the foreground of widget 2 - vtkSmartPointer m_ForegroundRenderer3; ///< renderer responsible for text rendering in the foreground of widget 3 - vtkSmartPointer m_RenderWindow1; ///< vtk render window used for showing overlay in widget 1 - vtkSmartPointer m_RenderWindow2; ///< vtk render window used for showing overlay in widget 2 - vtkSmartPointer m_RenderWindow3; ///< vtk render window used for showing overlay in widget 3 - vtkSmartPointer m_RenderWindow4; ///< vtk render window used for showing overlay in widget 3 + mitk::TextAnnotation2D::Pointer m_TextAnnotationAxial; ///< text annotation used to display measurements in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotationSagittal; ///< text annotation used to display measurement in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotationCoronal; ///< text annotation used to display measurement in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotation3D; ///< text annotation used to display measurement in 3d window + mitk::VtkPropRenderer::Pointer m_RendererAxial; ///< renderer of axial render window + mitk::VtkPropRenderer::Pointer m_RendererSagittal; ///< renderer of sagittal render window + mitk::VtkPropRenderer::Pointer m_RendererCoronal; ///< renderer of coronal render window + mitk::VtkPropRenderer::Pointer m_Renderer3D; ///< renderer of 3D render window mitk::PointSet::Pointer m_MeasurementPointSet2D; ///< PointSet holding the 2D ToF image point selection used for measuring mitk::DataNode::Pointer m_MeasurementPointSet3DNode; ///< DataNode holding the 3D ToF coordinates used for measuring mitk::PointSet::Pointer m_PointSet2D; ///< PointSet holding the 2D ToF image points mitk::DataNode::Pointer m_PointSet3DNode; ///< DataNode holding the 3D ToF coordinates mitk::PointSetDataInteractor::Pointer m_PointSetInteractor; ///< PointSetInteractor used for PointSet definition mitk::PointSetDataInteractor::Pointer m_MeasurementPointSetInteractor; ///< PointSetInteractor used for measurement long m_MeasurementPointSetChangedObserverTag; ///< observer tag for measurement PointSet observer long m_PointSetChangedObserverTag; ///< observer tag for PointSet observer // long m_DistanceImageChangedObserverTag; ///< observer tag for distance image observer int m_WindowHeight; ///< Height of the renderWindow private: }; #endif // _QmitkToFPointSetWidget_H_INCLUDED diff --git a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp index be5f8d7576..818c3e10c3 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp @@ -1,419 +1,419 @@ /*=================================================================== 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 "QmitkToFVisualisationSettingsWidget.h" #include #include #include //QT headers #include #include #include const std::string QmitkToFVisualisationSettingsWidget::VIEW_ID = "org.mitk.views.qmitktofvisualisationsettingswidget"; QmitkToFVisualisationSettingsWidget::QmitkToFVisualisationSettingsWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) , m_Controls(nullptr) , m_RangeSliderMin(0) , m_RangeSliderMax(0) , m_MitkDistanceImageNode(nullptr) , m_MitkAmplitudeImageNode(nullptr) , m_MitkIntensityImageNode(nullptr) , m_Widget1ColorTransferFunction(nullptr) , m_Widget2ColorTransferFunction(nullptr) , m_Widget3ColorTransferFunction(nullptr) , m_Widget1TransferFunctionType(1) , m_Widget2TransferFunctionType(0) , m_Widget3TransferFunctionType(0) { CreateQtPartControl(this); } QmitkToFVisualisationSettingsWidget::~QmitkToFVisualisationSettingsWidget() { } void QmitkToFVisualisationSettingsWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFVisualisationSettingsWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFVisualisationSettingsWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_SelectWidgetCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnWidgetSelected(int)) ); connect( (QObject*)(m_Controls->m_SelectTransferFunctionTypeCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnTransferFunctionTypeSelected(int)) ); connect( (QObject*)(m_Controls->m_TransferFunctionResetButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnTransferFunctionReset()) ); connect(m_Controls->m_XEditColor, SIGNAL(returnPressed()), this, SLOT(OnSetXValueColor())); connect(m_Controls->m_RangeSliderMaxEdit, SIGNAL(returnPressed()), this, SLOT(OnRangeSliderMaxChanged())); connect(m_Controls->m_RangeSliderMinEdit, SIGNAL(returnPressed()), this, SLOT(OnRangeSliderMinChanged())); connect(m_Controls->m_RangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetSlider())); - connect(m_Controls->m_RangeSlider, SIGNAL(spanChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); + connect(m_Controls->m_RangeSlider, SIGNAL(valuesChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); connect(m_Controls->m_AdvancedOptionsCheckbox, SIGNAL(toggled(bool) ),this, SLOT( OnShowAdvancedOptionsCheckboxChecked(bool) )); m_Controls->m_RangeSlider->setMaximum(2048); m_Controls->m_RangeSlider->setMinimum(-2048); m_Controls->m_ColorTransferFunctionCanvas->SetQLineEdits(m_Controls->m_XEditColor, nullptr); m_Controls->m_ColorTransferFunctionCanvas->SetTitle(""/*"Value -> Grayscale/Color"*/); this->OnShowAdvancedOptionsCheckboxChecked(false); } } void QmitkToFVisualisationSettingsWidget::OnSetXValueColor() { m_Controls->m_ColorTransferFunctionCanvas->SetX(m_Controls->m_XEditColor->text().toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkToFVisualisationSettingsWidget::OnRangeSliderMaxChanged() { m_Controls->m_RangeSlider->setMaximum(m_Controls->m_RangeSliderMaxEdit->text().toInt()); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnRangeSliderMinChanged() { m_Controls->m_RangeSlider->setMinimum(m_Controls->m_RangeSliderMinEdit->text().toInt()); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnSpanChanged(int /*lower*/, int /*upper*/) { UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnResetSlider() { m_Controls->m_RangeSlider->setMaximumValue(m_RangeSliderMax); m_Controls->m_RangeSlider->setMinimumValue(m_RangeSliderMin); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::UpdateRanges() { int lower = m_Controls->m_RangeSlider->minimumValue(); int upper = m_Controls->m_RangeSlider->maximumValue(); m_Controls->m_ColorTransferFunctionCanvas->SetMin(lower); m_Controls->m_ColorTransferFunctionCanvas->SetMax(upper); } void QmitkToFVisualisationSettingsWidget::UpdateSurfaceProperty() { if(this->m_MitkSurfaceNode.IsNotNull()) { mitk::TransferFunction::Pointer transferFunction = mitk::TransferFunction::New(); transferFunction->SetColorTransferFunction(this->GetSelectedColorTransferFunction()); this->m_MitkSurfaceNode->SetProperty("Surface.TransferFunction", mitk::TransferFunctionProperty::New(transferFunction)); } } void QmitkToFVisualisationSettingsWidget::Initialize(mitk::DataNode* distanceImageNode, mitk::DataNode* amplitudeImageNode, mitk::DataNode* intensityImageNode, mitk::DataNode* surfaceNode) { this->m_MitkDistanceImageNode = distanceImageNode; this->m_MitkAmplitudeImageNode = amplitudeImageNode; this->m_MitkIntensityImageNode = intensityImageNode; this->m_MitkSurfaceNode = surfaceNode; // Initialize transfer functions for image DataNodes such that: // Widget1 (Distance): color from red (2nd min) to blue (max) // Widget2 (Amplitude): grey value from black (2nd min) to white (max) // Widget3 (Intensity): grey value from black (2nd min) to white (max) if (!m_MitkDistanceImageNode && !m_MitkAmplitudeImageNode && !m_MitkIntensityImageNode) { m_Controls->m_ColorTransferFunctionCanvas->setEnabled(false); } else { m_Controls->m_ColorTransferFunctionCanvas->setEnabled(true); int numberOfImages = 0; if (m_MitkDistanceImageNode) { m_Widget1ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget1TransferFunctionType = 1; m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget1TransferFunctionType); numberOfImages++; } if (m_MitkAmplitudeImageNode) { m_Widget2ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget2TransferFunctionType = 0; numberOfImages++; } if (m_MitkIntensityImageNode) { m_Widget3ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget3TransferFunctionType = 0; numberOfImages++; } m_Controls->m_SelectWidgetCombobox->setMaxCount(numberOfImages); } this->ReinitTransferFunction(0,1); this->ReinitTransferFunction(1,0); this->ReinitTransferFunction(2,0); } void QmitkToFVisualisationSettingsWidget::UpdateCanvas() { m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->GetSelectedColorTransferFunction() ); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnTransferFunctionTypeSelected(int index) { int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); if (currentWidgetIndex == 0) { this->m_Widget1TransferFunctionType = index; } else if (currentWidgetIndex == 1) { this->m_Widget2TransferFunctionType = index; } else if (currentWidgetIndex == 2) { this->m_Widget3TransferFunctionType = index; } else { return; } this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::OnShowAdvancedOptionsCheckboxChecked(bool checked) { this->m_Controls->m_MappingGroupBox->setVisible(checked); this->m_Controls->m_SelectTransferFunctionTypeCombobox->setVisible(checked); this->m_Controls->m_SelectWidgetCombobox->setVisible(checked); this->m_Controls->m_TransferFunctionResetButton->setVisible(checked); } void QmitkToFVisualisationSettingsWidget::OnWidgetSelected(int index) { int currentWidgetIndex = index; double valMin[6]; double valMax[6]; int numPoints; if (currentWidgetIndex == 0) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget1TransferFunctionType); numPoints = this->m_Widget1ColorTransferFunction->GetSize(); this->m_Widget1ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget1ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget1ColorTransferFunction ); } else if (currentWidgetIndex == 1) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget2TransferFunctionType); numPoints = this->m_Widget2ColorTransferFunction->GetSize(); this->m_Widget2ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget2ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget2ColorTransferFunction ); } else if (currentWidgetIndex == 2) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget3TransferFunctionType); numPoints = this->m_Widget3ColorTransferFunction->GetSize(); this->m_Widget3ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget3ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget3ColorTransferFunction ); } else if (currentWidgetIndex == 3) { } else { return; } m_RangeSliderMin = valMin[0]; m_RangeSliderMax = valMax[0]; int border = (m_RangeSliderMax - m_RangeSliderMin) * 0.1; m_Controls->m_RangeSlider->setMinimum(m_RangeSliderMin - border); m_Controls->m_RangeSlider->setMaximum(m_RangeSliderMax + border); m_Controls->m_RangeSliderMinEdit->setText(QString("").setNum(m_RangeSliderMin - border)); m_Controls->m_RangeSliderMaxEdit->setText(QString("").setNum(m_RangeSliderMax + border)); m_Controls->m_RangeSlider->setRange( m_RangeSliderMin, m_RangeSliderMax); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::ResetTransferFunction(vtkColorTransferFunction* colorTransferFunction, int type, double min, double max) { colorTransferFunction->RemoveAllPoints(); if (type == 0) { colorTransferFunction->AddRGBPoint(min, 0, 0, 0); colorTransferFunction->AddRGBPoint(max, 1, 1, 1); } else { if (min>0.01) { colorTransferFunction->AddRGBPoint(0.0, 0, 0, 0); colorTransferFunction->AddRGBPoint(min-0.01, 0, 0, 0); } colorTransferFunction->AddRGBPoint(min, 1, 0, 0); colorTransferFunction->AddRGBPoint(min+(max-min)/2, 1, 1, 0); colorTransferFunction->AddRGBPoint(max, 0, 0, 1); } colorTransferFunction->SetColorSpaceToHSV(); } void QmitkToFVisualisationSettingsWidget::ReinitTransferFunction(int widget, int type) { switch (widget) { case 0: { mitk::Image::Pointer distanceImage = dynamic_cast(m_MitkDistanceImageNode->GetData()); // use second minimum to draw 0 values (that are usually segmented) black m_RangeSliderMin = distanceImage->GetStatistics()->GetScalarValue2ndMin(); m_RangeSliderMax = distanceImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Distance Min: "<m_Widget1ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget1ColorTransferFunction ); mitk::TransferFunction::Pointer tf1 = mitk::TransferFunction::New(); tf1->SetColorTransferFunction( m_Widget1ColorTransferFunction ); m_MitkDistanceImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf1)); break; } case 1: { if (m_MitkAmplitudeImageNode) { mitk::Image::Pointer amplitudeImage = dynamic_cast(m_MitkAmplitudeImageNode->GetData()); if (amplitudeImage.IsNotNull()) { m_RangeSliderMin = amplitudeImage->GetStatistics()->GetScalarValueMin(); m_RangeSliderMax = amplitudeImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Amplitude Min: "<m_Widget2ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget2ColorTransferFunction ); mitk::TransferFunction::Pointer tf2 = mitk::TransferFunction::New(); tf2->SetColorTransferFunction( m_Widget2ColorTransferFunction ); m_MitkAmplitudeImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf2)); } } break; } case 2: { if (m_MitkIntensityImageNode) { mitk::Image::Pointer intensityImage = dynamic_cast(m_MitkIntensityImageNode->GetData()); if (intensityImage.IsNotNull()) { m_RangeSliderMin = intensityImage->GetStatistics()->GetScalarValueMin(); m_RangeSliderMax = intensityImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Intensity Min: "<m_Widget3ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget3ColorTransferFunction ); mitk::TransferFunction::Pointer tf3 = mitk::TransferFunction::New(); tf3->SetColorTransferFunction( m_Widget3ColorTransferFunction ); m_MitkIntensityImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf3)); } } break; } default: break; } this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::OnTransferFunctionReset() { int currentTransferFunctionTypeIndex = m_Controls->m_SelectTransferFunctionTypeCombobox->currentIndex(); int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); this->ReinitTransferFunction(currentWidgetIndex,currentTransferFunctionTypeIndex); int border = (m_RangeSliderMax - m_RangeSliderMin) * 0.1; m_Controls->m_RangeSlider->setMinimum(m_RangeSliderMin - border); m_Controls->m_RangeSlider->setMaximum(m_RangeSliderMax + border); m_Controls->m_RangeSliderMinEdit->setText(QString("").setNum(m_RangeSliderMin - border)); m_Controls->m_RangeSliderMaxEdit->setText(QString("").setNum(m_RangeSliderMax + border)); m_Controls->m_RangeSlider->setRange( m_RangeSliderMin, m_RangeSliderMax); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); this->UpdateSurfaceProperty(); } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget1ColorTransferFunction() { return this->m_Widget1ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget2ColorTransferFunction() { return this->m_Widget2ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget3ColorTransferFunction() { return this->m_Widget3ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetSelectedColorTransferFunction() { int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); if (currentWidgetIndex==0) { return this->m_Widget1ColorTransferFunction; } else if (currentWidgetIndex==1) { return this->m_Widget2ColorTransferFunction; } else if (currentWidgetIndex==2) { return this->m_Widget3ColorTransferFunction; } else { return this->m_Widget3ColorTransferFunction; } } int QmitkToFVisualisationSettingsWidget::GetSelectedImageIndex() { return this->m_Controls->m_SelectWidgetCombobox->currentIndex(); } diff --git a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui index dc1e7ca403..74938d0a7c 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui @@ -1,445 +1,439 @@ QmitkToFVisualisationSettingsWidgetControls 0 0 482 - 230 + 211 0 0 QmitkToFVisualisationSettings - + 11 ToF Visualization - - - - Show advanced options - - - 0 0 200 50 10 0 3 QComboBox::InsertAtBottom QComboBox::AdjustToContents 30 30 true Distance :/images/widget1.png:/images/widget1.png Amplitude :/images/widget2.png:/images/widget2.png Intensity :/images/widget3.png:/images/widget3.png true 0 0 150 50 16777215 50 10 0 3 QComboBox::InsertAtBottom QComboBox::AdjustToContents 100 35 true :/images/grayscale.png:/images/grayscale.png :/images/color.png:/images/color.png 100 50 16777215 50 10 Fit scale + + + + Show advanced options + + + Gray value/color mapping QFrame::StyledPanel QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 - - modify actual seen window by dragging left and right slider. - Qt::Horizontal - + 0 0 - - - 48 - 16777215 - - Resets range to histogram minimum and maximum. Reset - + 1 1 - - - 0 - 28 - - Left-click to select a point or add a new point. Hold left mouse button to move selected point. Click right mouse button to delete a point. Double-click left mouse button to change color of a point. true 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 86 20 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 85 20 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - ctkRangeSlider - QWidget -
ctkRangeSlider.h
-
QmitkColorTransferFunctionCanvas QWidget
QmitkColorTransferFunctionCanvas.h
+ + ctkRangeSlider + QSlider +
ctkRangeSlider.h
+
diff --git a/Modules/US/USFilters/mitkUSImageSource.h b/Modules/US/USFilters/mitkUSImageSource.h index b5a224a20d..2866092a67 100644 --- a/Modules/US/USFilters/mitkUSImageSource.h +++ b/Modules/US/USFilters/mitkUSImageSource.h @@ -1,105 +1,102 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSImageSource_H_HEADER_INCLUDED_ #define MITKUSImageSource_H_HEADER_INCLUDED_ // ITK #include #include // MITK #include #include #include "mitkBasicCombinationOpenCVImageFilter.h" #include "mitkOpenCVToMitkImageFilter.h" #include "mitkImageToOpenCVImageFilter.h" -// OpenCV -#include "cv.h" - namespace mitk { /** * \brief This is an abstract superclass for delivering USImages. * Each subclass must implement the method mitk::USImageSource::GetNextRawImage(). * The public method mitk::USImageSource::GetNextImage() can the be used to * get the next image from the image source. This image will be filtered by * the filter set with mitk::USImageSource::SetImageFilter(). * * \ingroup US */ class MITKUS_EXPORT USImageSource : public itk::Object { public: static const char* IMAGE_PROPERTY_IDENTIFIER; mitkClassMacroItkParent(USImageSource, itk::Object); itkGetMacro(ImageFilter, mitk::BasicCombinationOpenCVImageFilter::Pointer); void PushFilter(AbstractOpenCVImageFilter::Pointer filter); bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter); bool GetIsFilterInThePipeline(AbstractOpenCVImageFilter::Pointer filter); /** * \brief Retrieves the next frame. This will typically be the next frame * in a file or the last cached file in a device. The image is filtered if * a filter was set by mitk::USImageSource::SetImageFilter(). * * \return pointer to the next USImage (filtered if set) */ std::vector GetNextImage(); protected: USImageSource(); ~USImageSource() override; /** * \brief Set the given OpenCV image matrix to the next image received * from the device or file. * * The standard implementation calls the overloaded function with an * mitk::Image and converts this image to OpenCV then. One should reimplement * this method for a better performance if an image filter is set. */ virtual void GetNextRawImage(std::vector&); /** * \brief Set mitk::Image to the next image received from the device or file. * This method must be implemented in every subclass. */ virtual void GetNextRawImage(std::vector&) = 0; /** * \brief Used to convert from OpenCV Images to MITK Images. */ mitk::OpenCVToMitkImageFilter::Pointer m_OpenCVToMitkFilter; /** * \brief Used to convert from MITK Images to OpenCV Images. */ mitk::ImageToOpenCVImageFilter::Pointer m_MitkToOpenCVFilter; private: /** * \brief Filter is executed during mitk::USImageVideoSource::GetNextImage(). */ BasicCombinationOpenCVImageFilter::Pointer m_ImageFilter; int m_CurrentImageId; itk::FastMutexLock::Pointer m_ImageFilterMutex; }; } // namespace mitk #endif /* MITKUSImageSource_H_HEADER_INCLUDED_ */ diff --git a/Modules/US/USFilters/mitkUSImageVideoSource.cpp b/Modules/US/USFilters/mitkUSImageVideoSource.cpp index 0c5597bffb..7db00a5a14 100644 --- a/Modules/US/USFilters/mitkUSImageVideoSource.cpp +++ b/Modules/US/USFilters/mitkUSImageVideoSource.cpp @@ -1,233 +1,230 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK HEADER #include "mitkUSImageVideoSource.h" #include "mitkImage.h" -//OpenCV HEADER -#include -#include - //Other #include +#include mitk::USImageVideoSource::USImageVideoSource() : m_VideoCapture(new cv::VideoCapture()), m_IsVideoReady(false), m_IsGreyscale(false), m_IsCropped(false), m_ResolutionOverrideWidth(0), m_ResolutionOverrideHeight(0), m_ResolutionOverride(false), m_GrayscaleFilter(mitk::ConvertGrayscaleOpenCVImageFilter::New()), m_CropFilter(mitk::CropOpenCVImageFilter::New()) { } mitk::USImageVideoSource::~USImageVideoSource() { m_VideoCapture->release(); delete m_VideoCapture; } void mitk::USImageVideoSource::SetVideoFileInput(std::string path) { m_VideoCapture->open(path.c_str()); // check if we succeeded if(!m_VideoCapture->isOpened()) { m_IsVideoReady = false; } else { m_IsVideoReady = true; } // if Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::SetCameraInput(int deviceID) { m_VideoCapture->open(deviceID); if(!m_VideoCapture->isOpened()) // check if we succeeded m_IsVideoReady = false; else m_IsVideoReady = true; // if Override is enabled, use it if (m_ResolutionOverride) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, this->m_ResolutionOverrideWidth); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, this->m_ResolutionOverrideHeight); } } void mitk::USImageVideoSource::ReleaseInput() { m_VideoCapture->release(); delete m_VideoCapture; m_VideoCapture = new cv::VideoCapture(); } void mitk::USImageVideoSource::SetColorOutput(bool isColor){ if ( ! isColor && ! m_IsGreyscale ) { this->PushFilter(m_GrayscaleFilter.GetPointer()); } else if ( isColor && m_IsGreyscale ) { this->RemoveFilter(m_GrayscaleFilter.GetPointer()); } m_IsGreyscale = !isColor; } int mitk::USImageVideoSource::GetImageHeight() { if (m_VideoCapture) { return m_VideoCapture->get(CV_CAP_PROP_FRAME_HEIGHT); } else { return 0; } } int mitk::USImageVideoSource::GetImageWidth() { if (m_VideoCapture) { return m_VideoCapture->get(CV_CAP_PROP_FRAME_WIDTH); } else { return 0; } } bool mitk::USImageVideoSource::GetIsReady() { if (!m_VideoCapture) { return false; } return m_VideoCapture->isOpened(); } void mitk::USImageVideoSource::SetRegionOfInterest(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY) { m_CropFilter->SetCropRegion(topLeftX, topLeftY, bottomRightX, bottomRightY); if (! m_IsCropped && ! m_CropFilter->GetIsCropRegionEmpty()) { this->PushFilter(m_CropFilter.GetPointer()); m_IsCropped = true; } } void mitk::USImageVideoSource::SetRegionOfInterest(USImageRoi roi) { this->SetRegionOfInterest(roi.topLeftX, roi.topLeftY, roi.bottomRightX, roi.bottomRightY); } void mitk::USImageVideoSource::SetCropping(USImageCropping cropping) { int width = this->GetImageWidth(); int height = this->GetImageHeight(); this->SetRegionOfInterest(cropping.left, cropping.top, width - cropping.right, height - cropping.bottom); } mitk::USImageVideoSource::USImageCropping mitk::USImageVideoSource::GetCropping() { cv::Rect cropRect = m_CropFilter->GetCropRegion(); USImageCropping cropping; cropping.left = cropRect.x; cropping.top = cropRect.y; if ( cropRect.height == 0 ) { cropping.bottom = 0; } else { cropping.bottom = this->GetImageHeight() - (cropRect.y + cropRect.height); } if ( cropRect.width == 0 ) { cropping.right = 0; } else { cropping.right = this->GetImageWidth() - (cropRect.x + cropRect.width); } return cropping; } mitk::USImageVideoSource::USImageRoi mitk::USImageVideoSource::GetRegionOfInterest() { cv::Rect cropRect = m_CropFilter->GetCropRegion(); return USImageRoi(cropRect.x, cropRect.y, cropRect.x + cropRect.width, cropRect.y + cropRect.height); } void mitk::USImageVideoSource::RemoveRegionOfInterest() { this->RemoveFilter(m_CropFilter.GetPointer()); m_IsCropped = false; } void mitk::USImageVideoSource::GetNextRawImage(std::vector& image ) { // loop video if necessary //Commented out because setting and getting of these properties is not supported. Therefore on Linux //you'll always get some Highgui errors from OpenCV /*if (m_VideoCapture->get(CV_CAP_PROP_POS_FRAMES) == m_VideoCapture->get(CV_CAP_PROP_FRAME_COUNT)) { m_VideoCapture->set(CV_CAP_PROP_POS_FRAMES, 0); }*/ if (image.size() != 1) image.resize(1); // retrieve image *m_VideoCapture >> image[0]; // get a new frame from camera } void mitk::USImageVideoSource::GetNextRawImage(std::vector& image ) { if (image.size() != 1) image.resize(1); std::vector cv_img; this->GetNextRawImage(cv_img); // convert to MITK-Image IplImage ipl_img = cv_img[0]; this->m_OpenCVToMitkFilter->SetOpenCVImage(&ipl_img); this->m_OpenCVToMitkFilter->Update(); // OpenCVToMitkImageFilter returns a standard mitk::image. We then transform it into an USImage image[0] = this->m_OpenCVToMitkFilter->GetOutput(); // clean up cv_img[0].release(); } void mitk::USImageVideoSource::OverrideResolution(int width, int height) { this->m_ResolutionOverrideHeight = height; this->m_ResolutionOverrideWidth = width; if (m_VideoCapture != nullptr) { m_VideoCapture->set(CV_CAP_PROP_FRAME_WIDTH, width); m_VideoCapture->set(CV_CAP_PROP_FRAME_HEIGHT, height); } } diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 8e80410b82..05ea8dcffc 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,692 +1,712 @@ /*=================================================================== 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 "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), + m_FreezeBarrier(nullptr), + m_FreezeMutex(), + m_MultiThreader(itk::MultiThreader::New()), + m_ImageMutex(itk::FastMutexLock::New()), + m_ThreadID(-1), + m_ImageVector(), + m_Spacing(), + m_IGTLServer(nullptr), + m_IGTLMessageProvider(nullptr), + m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), + m_ServiceProperties(), + m_ServiceRegistration(), m_Manufacturer(manufacturer), m_Name(model), + m_Comment(), m_SpawnAcquireThread(true), - m_MultiThreader(itk::MultiThreader::New()), - m_ImageMutex(itk::FastMutexLock::New()), - m_ThreadID(-1), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), - m_IsFreezed(false), - m_DeviceState(State_NoState), - m_SpawnAcquireThread(true), + m_FreezeBarrier(nullptr), + m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), + m_ImageVector(), + m_Spacing(), + m_IGTLServer(nullptr), + m_IGTLMessageProvider(nullptr), + m_ImageToIGTLMsgFilter(nullptr), + m_IsFreezed(false), + m_DeviceState(State_NoState), + m_NumberOfOutputs(1), + m_ServiceProperties(), + m_ServiceRegistration(), + m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs - this->SetNumberOfIndexedOutputs(1); + this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return nullptr; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return nullptr; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return nullptr; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return nullptr; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); m_ImageToIGTLMsgFilter->ConnectTo(this); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot freeze or unfreeze if device is not active."; return; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { /* if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") << "Cannot get freeze state if the hardware interface is not ready. " "Returning false..."; return false; }*/ return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { std::vector image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImageVector(image); m_ImageMutex->Unlock(); } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::SetSpacing(double xSpacing, double ySpacing) { m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; if( m_ImageVector.size() > 0 ) { for( size_t index = 0; index < m_ImageVector.size(); ++index ) { auto& image = m_ImageVector[index]; if( image.IsNotNull() && image->IsInitialized() ) { image->GetGeometry()->SetSpacing(m_Spacing); } } this->Modified(); } MITK_INFO << "Spacing: " << m_Spacing; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); for (unsigned int i = 0; i < m_ImageVector.size() && i < this->GetNumberOfIndexedOutputs(); ++i) { auto& image = m_ImageVector[i]; if (image.IsNull() || !image->IsInitialized()) { // skip image } else { mitk::Image::Pointer output = this->GetOutput(i); if (!output->IsInitialized() || output->GetDimension(0) != image->GetDimension(0) || output->GetDimension(1) != image->GetDimension(1) || output->GetDimension(2) != image->GetDimension(2) || output->GetPixelType() != image->GetPixelType()) { output->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); } // copy contents of the given image into the member variable mitk::ImageReadAccessor inputReadAccessor(image); output->SetImportVolume(inputReadAccessor.GetData()); output->SetGeometry(image->GetGeometry()); } } m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index b54f67c583..095f3fbf1b 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,490 +1,489 @@ /*=================================================================== 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 MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include #include "mitkUSImageSource.h" // MitkIGTL #include "mitkIGTLMessageProvider.h" #include "mitkIGTLServer.h" #include "mitkIGTLDeviceSource.h" #include "mitkImageToIGTLMessageFilter.h" // MITK #include #include #include // ITK #include #include // Microservices #include #include #include // DEPRECATED #include "mitkUSImageMetadata.h" namespace itk { template class SmartPointer; } namespace mitk { class USAbstractControlInterface; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that USDevices will be removed from micro servive when their * destructor is called. Registering into micro service is done when * mitk::USDevice::Initialize() is called. * * \ingroup US */ class MITKUS_EXPORT USDevice : public mitk::ImageSource { public: enum DeviceStates { State_NoState, State_Initialized, State_Connected, State_Activated }; mitkClassMacro(USDevice, mitk::ImageSource); itkSetMacro(SpawnAcquireThread, bool); itkGetMacro(SpawnAcquireThread, bool); struct USImageCropArea { int cropLeft; int cropRight; int cropBottom; int cropTop; }; /** * \brief These constants are used in conjunction with Microservices. * The constants aren't defined as static member attributes to avoid the * "static initialization order fiasco", which would occur when objects of * this class are used in module activators (for restoring stored device, * for example). */ struct PropertyKeys { const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices const std::string US_PROPKEY_MANUFACTURER; const std::string US_PROPKEY_NAME; const std::string US_PROPKEY_COMMENT; const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device const std::string US_PROPKEY_ISCONNECTED; // Whether this device is connected or not. const std::string US_PROPKEY_ISACTIVE; // Whether this device is active or not. const std::string US_PROPKEY_CLASS; // Class Name of this Object const std::string US_PROPKEY_PROBES_SELECTED; const std::string US_PROPKEY_BMODE_FREQUENCY; const std::string US_PROPKEY_BMODE_POWER; const std::string US_PROPKEY_BMODE_DEPTH; const std::string US_PROPKEY_BMODE_GAIN; const std::string US_PROPKEY_BMODE_REJECTION; const std::string US_PROPKEY_BMODE_DYNAMIC_RANGE; PropertyKeys() : US_INTERFACE_NAME("org.mitk.services.UltrasoundDevice"), US_PROPKEY_MANUFACTURER(US_INTERFACE_NAME + ".manufacturer"), US_PROPKEY_NAME(US_INTERFACE_NAME + ".name"), US_PROPKEY_COMMENT(US_INTERFACE_NAME + ".comment"), US_PROPKEY_LABEL(US_INTERFACE_NAME + ".label"), US_PROPKEY_ISCONNECTED(US_INTERFACE_NAME + ".isConnected"), US_PROPKEY_ISACTIVE(US_INTERFACE_NAME + ".isActive"), US_PROPKEY_CLASS(US_INTERFACE_NAME + ".class"), US_PROPKEY_PROBES_SELECTED(US_INTERFACE_NAME + ".probes.selected"), US_PROPKEY_BMODE_FREQUENCY(US_INTERFACE_NAME + ".bmode.frequency"), US_PROPKEY_BMODE_POWER(US_INTERFACE_NAME + ".bmode.power"), US_PROPKEY_BMODE_DEPTH(US_INTERFACE_NAME + ".bmode.depth"), US_PROPKEY_BMODE_GAIN(US_INTERFACE_NAME + ".bmode.gain"), US_PROPKEY_BMODE_REJECTION(US_INTERFACE_NAME + ".bmode.rejection"), US_PROPKEY_BMODE_DYNAMIC_RANGE(US_INTERFACE_NAME + ".bmode.dynamicRange") {} }; /** * \brief Event for being notified about changes of the micro service properties. * This event can be used if no micro service context is available. */ mitkNewMessage2Macro(PropertyChanged, const std::string&, const std::string&) - /** - * \return keys for the microservice properties of ultrasound devices - */ - static mitk::USDevice::PropertyKeys GetPropertyKeys(); + /** + * \return keys for the microservice properties of ultrasound devices + */ + static mitk::USDevice::PropertyKeys GetPropertyKeys(); /** * \brief Default getter for the custom control interface. * Has to be implemented in a subclass if a custom control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Default getter for the b mode control interface. * Has to be implemented in a subclass if a b mode control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceBMode(); /** * \brief Default getter for the probes control interface. * Has to be implemented in a subclass if a probes control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceProbes(); /** * \brief Default getter for the doppler control interface. * Has to be implemented in a subclass if a doppler control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceDoppler(); /** * \brief Changes device state to mitk::USDevice::State_Initialized. * During initialization the virtual method * mitk::USDevice::OnInitialization will be called. If this method * returns false the initialization process will be canceled. Otherwise * the mitk::USDevice is registered in a micro service. */ bool Initialize(); /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); void ConnectAsynchron(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. * After the activation process, the device will start to produce images. * This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. * After the deactivation process, the device will no longer produce * images, but still be connected. */ void Deactivate(); /** * \brief Can toggle if ultrasound image is currently updated or freezed. * * \param freeze true to stop updating the ultrasound image, false to start updating again */ virtual void SetIsFreezed(bool freeze); /** * \return true if device is currently freezed (no image update is done), false otherwise */ virtual bool GetIsFreezed(); void PushFilter(AbstractOpenCVImageFilter::Pointer filter); void PushFilterIfNotPushedBefore(AbstractOpenCVImageFilter::Pointer filter); bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter); /** * @brief To be called when the used probe changed. Will update the service properties * @param probename of the now used probe */ void ProbeChanged(std::string probename); /** * @brief To be called when the scanning depth of the probe changed. Will update the service properties * @param depth that is now used */ void DepthChanged(double depth); /** * \brief Given property is updated in the device micro service. * This method is mainly for being used by the control interface * superclasses. You do not need to call it by yoursefs in your * concrete control interface classes. */ void UpdateServiceProperty(std::string key, std::string value); void UpdateServiceProperty(std::string key, double value); void UpdateServiceProperty(std::string key, bool value); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device object is created and initialized, false otherwise. */ bool GetIsInitialized(); /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ mitk::USDevice::USImageCropArea GetCropArea(); /* @return Returns the size of the m_ImageVector of the ultrasound device.*/ unsigned int GetSizeOfImageVector(); /** @return Returns the current image source of this device. */ virtual USImageSource::Pointer GetUSImageSource() = 0; /** \brief Deprecated -> use GetManufacturer() instead */ DEPRECATED(std::string GetDeviceManufacturer()); /** \brief Deprecated -> use GetName() instead */ DEPRECATED(std::string GetDeviceModel()); /** \brief Deprecated -> use GetCommend() instead */ DEPRECATED(std::string GetDeviceComment()); itkGetMacro(Manufacturer, std::string); itkGetMacro(Name, std::string); itkGetMacro(Comment, std::string); void SetManufacturer(std::string manufacturer); void SetName(std::string name); void SetComment(std::string comment); itkGetMacro(DeviceState, DeviceStates) - itkGetMacro(ServiceProperties, us::ServiceProperties) + itkGetMacro(ServiceProperties, us::ServiceProperties) - void GrabImage(); + void GrabImage(); virtual void SetSpacing(double xSpacing, double ySpacing); protected: // Threading-Related itk::ConditionVariable::Pointer m_FreezeBarrier; itk::SimpleMutexLock m_FreezeMutex; itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the image source int m_ThreadID; ///< ID of the started thread virtual void SetImageVector(std::vector vec) { if (this->m_ImageVector != vec) { this->m_ImageVector = vec; this->Modified(); } } static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); static ITK_THREAD_RETURN_TYPE ConnectThread(void* pInfoStruct); std::vector m_ImageVector; - //mitk::Image::Pointer m_OutputImage; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; /** * \brief Registers an OpenIGTLink device as a microservice so that we can send the images of * this device via the network. */ void ProvideViaOIGTL(); /** * \brief Deregisters the microservices for OpenIGTLink. */ void DisableOIGTL(); mitk::IGTLServer::Pointer m_IGTLServer; mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_ImageToIGTLMsgFilter; bool m_IsFreezed; DeviceStates m_DeviceState; /* @brief defines the area that should be cropped from the US image */ USImageCropArea m_CropArea; /** * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ us::ServiceProperties ConstructServiceProperties(); /** * \brief Remove this device from the micro service. */ void UnregisterOnService(); /** * \brief Is called during the initialization process. * Override this method in a subclass to handle the actual initialization. * If it returns false, the initialization process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnInitialization() = 0; /** * \brief Is called during the connection process. * Override this method in a subclass to handle the actual connection. * If it returns false, the connection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. * Override this method in a subclass to handle the actual disconnection. * If it returns false, the disconnection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. * After this method is finished, the device should be generating images. * If it returns false, the activation process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. * After a call to this method the device should still be connected, * but not producing images anymore. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDeactivation() = 0; /** * \brief Called when mitk::USDevice::SetIsFreezed() is called. * Subclasses can overwrite this method to do additional actions. Default * implementation does noting. */ virtual void OnFreeze(bool) { } /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! * \deprecated Use USDevice(std::string manufacturer, std::string model) instead. */ USDevice(mitk::USImageMetadata::Pointer metadata); ~USDevice() override; /** * \brief Grabs the next frame from the Video input. * This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() override; std::string GetServicePropertyLabel(); unsigned int m_NumberOfOutputs; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; private: std::string m_Manufacturer; std::string m_Name; std::string m_Comment; bool m_SpawnAcquireThread; bool m_UnregisteringStarted; }; } // namespace mitk // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif // MITKUSDevice_H_HEADER_INCLUDED_ diff --git a/Modules/US/USModel/mitkUSDevicePersistence.cpp b/Modules/US/USModel/mitkUSDevicePersistence.cpp index 48b901a8db..00920465ea 100644 --- a/Modules/US/USModel/mitkUSDevicePersistence.cpp +++ b/Modules/US/USModel/mitkUSDevicePersistence.cpp @@ -1,333 +1,343 @@ /*=================================================================== 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 "mitkUSDevicePersistence.h" //Microservices #include #include #include #include #include mitk::USDevicePersistence::USDevicePersistence() : m_devices("MITK US", "Device Settings") { } void mitk::USDevicePersistence::StoreCurrentDevices() { us::ModuleContext* thisContext = us::GetModuleContext(); std::vector > services = thisContext->GetServiceReferences(); MITK_INFO << "Trying to save " << services.size() << " US devices."; int numberOfSavedDevices = 0; for (std::vector >::iterator it = services.begin(); it != services.end(); ++it) { mitk::USDevice::Pointer currentDevice = thisContext->GetService(*it); //check if it is a USVideoDevice if (currentDevice->GetDeviceClass() == "org.mitk.modules.us.USVideoDevice") { mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(currentDevice.GetPointer()); QString identifier = "device" + QString::number(numberOfSavedDevices); m_devices.setValue(identifier, USVideoDeviceToString(currentVideoDevice)); numberOfSavedDevices++; } else { MITK_WARN << "Saving of US devices of the type " << currentDevice->GetDeviceClass() << " is not supported at the moment. Skipping device."; } } m_devices.setValue("numberOfSavedDevices", numberOfSavedDevices); MITK_INFO << "Successfully saved " << numberOfSavedDevices << " US devices."; } std::vector mitk::USDevicePersistence::RestoreLastDevices() { std::vector devices; int numberOfSavedDevices = m_devices.value("numberOfSavedDevices").toInt(); for (int i = 0; i < numberOfSavedDevices; i++) { // Try each device. If an exception occurs: Ignore device and notify user try { QString currentString = m_devices.value("device" + QString::number(i)).toString(); mitk::USDevice::Pointer currentDevice = dynamic_cast(StringToUSVideoDevice(currentString).GetPointer()); //currentDevice->Initialize(); devices.push_back(currentDevice.GetPointer()); } catch (...) { MITK_ERROR << "Error occured while loading a USVideoDevice from persistence. Device assumed corrupt, will be deleted."; //QMessageBox::warning(nullptr, "Could not load device" ,"A stored ultrasound device is corrupted and could not be loaded. The device will be deleted."); } } MITK_INFO << "Restoring " << numberOfSavedDevices << " US devices."; return devices; } QString mitk::USDevicePersistence::USVideoDeviceToString(mitk::USVideoDevice::Pointer d) { QString manufacturer = d->GetManufacturer().c_str(); QString model = d->GetName().c_str(); QString comment = d->GetComment().c_str(); int source = d->GetDeviceID(); std::string file = d->GetFilePath(); if (!d->GetIsSourceFile()) file = "none"; //if GetIsSourceFile is true, the device plays back a file mitk::USImageVideoSource::Pointer imageSource = dynamic_cast(d->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } int greyscale = imageSource->GetIsGreyscale(); int resOverride = imageSource->GetResolutionOverride(); int resWidth = imageSource->GetResolutionOverrideWidth(); int resHight = imageSource->GetResolutionOverrideHeight(); - mitk::USImageVideoSource::USImageRoi roi = imageSource->GetRegionOfInterest(); - QString probes = ""; //ACV$100%1%1%0$120%2%2%0$140%2%2%5!BDW$90%1%1%2$100%1%1%8!CSV$50%1%2%3$60%2%2%5 char probesSeperator = '!'; std::vector allProbesOfDevice = d->GetAllProbes(); if (allProbesOfDevice.size() > 0) { for (std::vector::iterator it = allProbesOfDevice.begin(); it != allProbesOfDevice.end(); it++) { if (it == allProbesOfDevice.begin()) { // if it is the first element there is no need for the probes seperator probes = probes + USProbeToString(*it); } else { probes = probes + probesSeperator + USProbeToString(*it); } } } char seperator = '|'; QString returnValue = manufacturer + seperator + model + seperator + comment + seperator + QString::number(source) + seperator + file.c_str() + seperator + QString::number(greyscale) + seperator + QString::number(resOverride) + seperator + QString::number(resWidth) + seperator + QString::number(resHight) + seperator - + QString::number(roi.topLeftX) + seperator - + QString::number(roi.topLeftY) + seperator - + QString::number(roi.bottomRightX) + seperator - + QString::number(roi.bottomRightY) + seperator + probes ; MITK_INFO << "Output String: " << returnValue.toStdString(); return returnValue; } QString mitk::USDevicePersistence::USProbeToString(mitk::USProbe::Pointer p) { - QString probe = p->GetName().c_str(); + QString probe = QString::fromStdString(p->GetName()); + QString croppingSeparator = QString(","); + probe = probe + croppingSeparator + QString::number(p->GetProbeCropping().top) + + croppingSeparator + QString::number(p->GetProbeCropping().right) + + croppingSeparator + QString::number(p->GetProbeCropping().bottom) + + croppingSeparator + QString::number(p->GetProbeCropping().left) + + croppingSeparator; + char depthSeperator = '$'; char spacingSeperator = '%'; std::map depthsAndSpacing = p->GetDepthsAndSpacing(); if (depthsAndSpacing.size() > 0) { for (std::map::iterator it = depthsAndSpacing.begin(); it != depthsAndSpacing.end(); it++){ probe = probe + depthSeperator + QString::number(it->first) + spacingSeperator + QString::number(it->second[0]) + spacingSeperator + QString::number(it->second[1]) + spacingSeperator + QString::number(it->second[2]); } } return probe; } mitk::USVideoDevice::Pointer mitk::USDevicePersistence::StringToUSVideoDevice(QString s) { MITK_INFO << "Input String: " << s.toStdString(); std::vector data; std::string seperators = "|"; std::string text = s.toStdString(); split(text, seperators, data); - if (data.size() != 14) + if (data.size() != 10) { MITK_ERROR << "Cannot parse US device! (Size: " << data.size() << ")"; return mitk::USVideoDevice::New("INVALID", "INVALID", "INVALID"); } std::string manufacturer = data.at(0); std::string model = data.at(1); std::string comment = data.at(2); int source = (QString(data.at(3).c_str())).toInt(); std::string file = data.at(4); bool greyscale = (QString(data.at(5).c_str())).toInt(); bool resOverride = (QString(data.at(6).c_str())).toInt(); int resWidth = (QString(data.at(7).c_str())).toInt(); int resHight = (QString(data.at(8).c_str())).toInt(); - mitk::USImageVideoSource::USImageRoi cropArea; - cropArea.topLeftX = (QString(data.at(9).c_str())).toInt(); - cropArea.topLeftY = (QString(data.at(10).c_str())).toInt(); - cropArea.bottomRightX = (QString(data.at(11).c_str())).toInt(); - cropArea.bottomRightY = (QString(data.at(12).c_str())).toInt(); // Create Device mitk::USVideoDevice::Pointer returnValue; if (file == "none") { returnValue = mitk::USVideoDevice::New(source, manufacturer, model); returnValue->SetComment(comment); } else { returnValue = mitk::USVideoDevice::New(file, manufacturer, model); returnValue->SetComment(comment); } mitk::USImageVideoSource::Pointer imageSource = dynamic_cast(returnValue->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!greyscale); // If Resolution override is activated, apply it if (resOverride) { imageSource->OverrideResolution(resWidth, resHight); imageSource->SetResolutionOverride(true); } - // Set Crop Area - imageSource->SetRegionOfInterest(cropArea); - std::string probes = data.at(13); + std::string probes = data.at(9); std::string probesSeperator = "!"; std::vector probesVector; split(probes, probesSeperator, probesVector); for (std::vector::iterator it = probesVector.begin(); it != probesVector.end(); it++) { mitk::USProbe::Pointer probe = StringToUSProbe(*it); returnValue->AddNewProbe(probe); } return returnValue; } mitk::USProbe::Pointer mitk::USDevicePersistence::StringToUSProbe(std::string s) { mitk::USProbe::Pointer probe = mitk::USProbe::New(); + std::string croppingSeparator = ","; std::string spacingSeperator = "%"; std::string depthSeperator = "$"; + std::vector probeCropping; + split(s, croppingSeparator, probeCropping); + std::vector depthsWithSpacings; split(s, depthSeperator, depthsWithSpacings); + //The first entry of the probeCropping vector is the name of the ultrasound probe: + std::string probeName = probeCropping.at(0); + probe->SetName(probeName); + //The entries 1, 2, 3 and 4 of the probeCropping vector are the cropping top, + // right, bottom and left: + if( probeCropping.size() >= 6 ) + { + QString top = QString::fromStdString(probeCropping.at(1)); + QString right = QString::fromStdString(probeCropping.at(2)); + QString bottom = QString::fromStdString(probeCropping.at(3)); + QString left = QString::fromStdString(probeCropping.at(4)); + probe->SetProbeCropping(top.toUInt(), bottom.toUInt(), left.toUInt(), right.toUInt()); + } + for (std::vector::iterator it = depthsWithSpacings.begin(); it != depthsWithSpacings.end(); it++) { - if (it == depthsWithSpacings.begin()) //first element is the name of the probe - { - probe->SetName(*it); - } - else //other elements are the scanning depths of the probe and the spacing + //The first element is the name of the probe and the cropping entries. + //other elements are the scanning depths of the probe and the spacing + if (it != depthsWithSpacings.begin()) { std::vector spacings; split(*it, spacingSeperator, spacings); mitk::Vector3D spacing; double x; double y; double z; int depth; try { x = spacingToDouble(spacings.at(1)); y = spacingToDouble(spacings.at(2)); z = spacingToDouble(spacings.at(3)); } catch (const mitk::Exception& e) { MITK_ERROR << e.GetDescription() << "Spacing of " << probe->GetName() << " at depth " << spacings.at(0) << " will be set to default value 1,1,0."; x = 1; y = 1; z = 1; } spacing[0] = x; spacing[1] = y; spacing[2] = z; try { depth = depthToInt(spacings.at(0)); } catch (const mitk::Exception& e) { MITK_ERROR << probe->GetName() << ": " << e.GetDescription(); continue; } probe->SetDepthAndSpacing(depth, spacing); } } return probe; } void mitk::USDevicePersistence::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop + 1); } } double mitk::USDevicePersistence::spacingToDouble(std::string s) { std::istringstream i(s); double x; if (!(i >> x)) { //something went wrong because the string contains characters which can not be convertet into double mitkThrow() << "An error occured while trying to recover the spacing."; } return x; } int mitk::USDevicePersistence::depthToInt(std::string s) { std::istringstream i(s); int x; if (!(i >> x)) { //something went wrong because the string contains characters which can not be convertet into int mitkThrow() << "An error occured while trying to recover the scanning depth. " << s << " is not a valid scanning depth. "; } return x; } diff --git a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp index bf6ab39efc..72183efc48 100644 --- a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp +++ b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.cpp @@ -1,116 +1,139 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkUSVideoDeviceCustomControls.h" mitk::USVideoDeviceCustomControls::USVideoDeviceCustomControls(itk::SmartPointer device) : mitk::USAbstractControlInterface(device.GetPointer()), m_IsActive(false) { m_ImageSource = dynamic_cast(m_Device->GetUSImageSource().GetPointer()); } mitk::USVideoDeviceCustomControls::~USVideoDeviceCustomControls() { } void mitk::USVideoDeviceCustomControls::SetIsActive(bool isActive) { m_IsActive = isActive; } bool mitk::USVideoDeviceCustomControls::GetIsActive() { return m_IsActive; } void mitk::USVideoDeviceCustomControls::SetCropArea(mitk::USImageVideoSource::USImageCropping newArea) { MITK_INFO << "Set Crop Area L:" << newArea.left << " R:" << newArea.right << " T:" << newArea.top << " B:" << newArea.bottom; if (m_ImageSource.IsNotNull()) { // if area is empty, remove region if ((newArea.bottom == 0) && (newArea.top == 0) && (newArea.left == 0) && (newArea.right == 0)) { m_ImageSource->RemoveRegionOfInterest(); } else { m_ImageSource->SetCropping(newArea); } } else { MITK_WARN << "Cannot set crop are, source is not initialized!"; } } void mitk::USVideoDeviceCustomControls::SetNewDepth(double depth) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); if (device.IsNotNull()) { if( device->GetCurrentProbe().IsNotNull() ) { device->GetCurrentProbe()->SetCurrentDepth(depth); MITK_INFO << "SetCurrentDepth of currentProbe: " << depth; } } m_Device->DepthChanged(depth); } void mitk::USVideoDeviceCustomControls::SetNewProbeIdentifier(std::string probename) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); if( device.IsNotNull() ) { device->SetCurrentProbe(probename); } m_Device->ProbeChanged(probename); } -mitk::USImageVideoSource::USImageCropping mitk::USVideoDeviceCustomControls::GetCropArea() +mitk::USProbe::USProbeCropping mitk::USVideoDeviceCustomControls::GetCropArea() { // just return the crop area set at the image source - return m_ImageSource->GetCropping(); + mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); + if (device.IsNotNull()) + { + mitk::USProbe::Pointer probe = device->GetCurrentProbe(); + if (probe.IsNotNull()) + { + return probe->GetProbeCropping(); + } + } + mitk::USProbe::USProbeCropping defaultCropping; + return defaultCropping; +} + +void mitk::USVideoDeviceCustomControls::UpdateProbeCropping(mitk::USImageVideoSource::USImageCropping cropping) +{ + mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); + if (device.IsNotNull()) + { + mitk::USProbe::Pointer probe = device->GetCurrentProbe(); + if( probe.IsNotNull() ) + { + probe->SetProbeCropping(cropping.top, cropping.bottom, cropping.left, cropping.right); + } + } } std::vector mitk::USVideoDeviceCustomControls::GetProbes() { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); return device->GetAllProbes(); } std::vector mitk::USVideoDeviceCustomControls::GetDepthsForProbe(std::string name) { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); mitk::USProbe::Pointer probe = device->GetProbeByName(name); std::map depthsAndSpacings = probe->GetDepthsAndSpacing(); std::vector depths; for (std::map::iterator it = depthsAndSpacings.begin(); it != depthsAndSpacings.end(); it++) { depths.push_back((it->first)); } return depths; } void mitk::USVideoDeviceCustomControls::SetDefaultProbeAsCurrentProbe() { mitk::USVideoDevice::Pointer device = dynamic_cast(m_Device.GetPointer()); device->SetDefaultProbeAsCurrentProbe(); } diff --git a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h index ce90da24b1..70b342011e 100644 --- a/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h +++ b/Modules/US/USModel/mitkUSVideoDeviceCustomControls.h @@ -1,101 +1,107 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ #define MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ #include "mitkUSAbstractControlInterface.h" #include "mitkUSImageVideoSource.h" #include "mitkUSVideoDevice.h" #include namespace mitk { /** * \brief Custom controls for mitk::USVideoDevice. * Controls image cropping of the corresponding mitk::USImageVideoSource. */ class MITKUS_EXPORT USVideoDeviceCustomControls : public USAbstractControlInterface { public: mitkClassMacro(USVideoDeviceCustomControls, USAbstractControlInterface); mitkNewMacro1Param(Self, itk::SmartPointer); /** * Activate or deactivate the custom controls. This is just for handling * widget visibility in a GUI for example. Cropping will not be deactivated * if this method is called with false. Use * mitk::USVideoDeviceCustomControls::SetCropArea() with an empty are * instead. */ void SetIsActive(bool isActive) override; /** * \return if this custom controls are currently activated */ bool GetIsActive() override; /** * \brief Sets the area that will be cropped from the US image. * Set [0,0,0,0] to disable it, which is also default. */ void SetCropArea(USImageVideoSource::USImageCropping newArea); /** - * \return area currently set for image cropping + * \return area currently set for image cropping defined by the actual current probe. */ - mitk::USImageVideoSource::USImageCropping GetCropArea(); + mitk::USProbe::USProbeCropping GetCropArea(); + + /** + * \brief Updates the cropping of the current probe given by the crop area of the + * USImageVideoSource. + */ + void UpdateProbeCropping( mitk::USImageVideoSource::USImageCropping cropping ); /** * \brief Sets a new depth value to the current probe. */ void SetNewDepth(double depth); /** * \ brief Sets new probe identifier */ void SetNewProbeIdentifier(std::string probename); /** *\brief Get all the probes for the current device */ std::vector GetProbes(); /** * \brief Get the scanning dephts of the given probe */ std::vector GetDepthsForProbe(std::string name); /** * \brief Sets the first existing probe or the default probe of a USVideoDevice * as the current probe of the USVideoDevice. */ void SetDefaultProbeAsCurrentProbe(); protected: /** * Class needs an mitk::USImageVideoSource object for beeing constructed. * This object will be manipulated by the custom controls methods. */ USVideoDeviceCustomControls(itk::SmartPointer device); ~USVideoDeviceCustomControls() override; bool m_IsActive; USImageVideoSource::Pointer m_ImageSource; }; } // namespace mitk #endif // MITKUSVideoDeviceCustomControls_H_HEADER_INCLUDED_ \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.cpp index de86ddea54..e4a7e569b4 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.cpp @@ -1,124 +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. ===================================================================*/ #include "QmitkUSControlsBModeWidget.h" #include "ui_QmitkUSControlsBModeWidget.h" QmitkUSControlsBModeWidget::QmitkUSControlsBModeWidget(mitk::USControlInterfaceBMode::Pointer controlInterface, QWidget *parent) : QWidget(parent), ui(new Ui::QmitkUSControlsBModeWidget), m_ControlInterface(controlInterface) { ui->setupUi(this); if ( ! m_ControlInterface ) { this->setDisabled(true); /*ui->scanningDepthComboBox->setEnabled(false); ui->scanningGainSlider->setEnabled(false); ui->scanningRejectionSlider->setEnabled(false);*/ return; } if ( ! m_ControlInterface->GetIsActive() ) { m_ControlInterface->SetIsActive(true); } // get possible scanning depth values and set combo box values according to them std::vector scanningDepths = m_ControlInterface->GetScanningDepthValues(); double curDepthValue = m_ControlInterface->GetScanningDepth(); for (auto it = scanningDepths.begin(); it != scanningDepths.end(); it++) { ui->scanningDepthComboBox->addItem(QString::number(*it, 'f', 2)); // set current index to last inserted element if this element is equal // to the current depth value got from the interface if (curDepthValue == *it) ui->scanningDepthComboBox->setCurrentIndex(ui->scanningDepthComboBox->count()-1); } // get possible scanning frequency values and set combo box values according to them std::vector scanningFrequencies = m_ControlInterface->GetScanningFrequencyValues(); double curFrequencyValue = m_ControlInterface->GetScanningFrequency(); for (auto it = scanningFrequencies.begin(); it != scanningFrequencies.end(); it++) { ui->scanningFrequencyComboBox->addItem(QString::number(*it, 'f', 2) + QString(" MHz")); // set current index to last inserted element if this element is equal // to the current depth value got from the interface if (curFrequencyValue == *it) ui->scanningFrequencyComboBox->setCurrentIndex(ui->scanningFrequencyComboBox->count()-1); } - + ui->scanningPowerSlider->setMinimum(m_ControlInterface->GetScanningPowerMin()); ui->scanningPowerSlider->setMaximum(m_ControlInterface->GetScanningPowerMax()); ui->scanningPowerSlider->setTickInterval(m_ControlInterface->GetScanningPowerTick()); ui->scanningPowerSlider->setValue(m_ControlInterface->GetScanningPower()); ui->scanningGainSlider->setMinimum(m_ControlInterface->GetScanningGainMin()); ui->scanningGainSlider->setMaximum(m_ControlInterface->GetScanningGainMax()); ui->scanningGainSlider->setTickInterval(m_ControlInterface->GetScanningGainTick()); ui->scanningGainSlider->setValue(m_ControlInterface->GetScanningGain()); ui->scanningRejectionSlider->setMinimum(m_ControlInterface->GetScanningRejectionMin()); ui->scanningRejectionSlider->setMaximum(m_ControlInterface->GetScanningRejectionMax()); ui->scanningRejectionSlider->setTickInterval(m_ControlInterface->GetScanningRejectionTick()); ui->scanningRejectionSlider->setValue(m_ControlInterface->GetScanningRejection()); ui->scanningDynamicRangeSlider->setMinimum(m_ControlInterface->GetScanningDynamicRangeMin()); ui->scanningDynamicRangeSlider->setMaximum(m_ControlInterface->GetScanningDynamicRangeMax()); ui->scanningDynamicRangeSlider->setTickInterval(m_ControlInterface->GetScanningDynamicRangeTick()); ui->scanningDynamicRangeSlider->setValue(m_ControlInterface->GetScanningDynamicRange()); connect( ui->scanningFrequencyComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFrequencyControlIndexChanged(int)) ); connect( ui->scanningDepthComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnDepthControlActivated(int)) ); connect( ui->scanningPowerSlider, SIGNAL(valueChanged(int)), this, SLOT(OnPowerControlValueChanged(int)) ); connect( ui->scanningGainSlider, SIGNAL(valueChanged(int)), this, SLOT(OnGainControlValueChanged(int)) ); connect( ui->scanningRejectionSlider, SIGNAL(valueChanged(int)), this, SLOT(OnRejectionControlValueChanged(int)) ); connect( ui->scanningDynamicRangeSlider, SIGNAL(valueChanged(int)), this, SLOT(OnDynamicRangeControlValueChanged(int)) ); } QmitkUSControlsBModeWidget::~QmitkUSControlsBModeWidget() { delete ui; } // slots void QmitkUSControlsBModeWidget::OnFrequencyControlIndexChanged(int) { QString currentText = ui->scanningFrequencyComboBox->currentText(); m_ControlInterface->SetScanningFrequency((currentText.left(currentText.size()-5)).toDouble()); } void QmitkUSControlsBModeWidget::OnDepthControlActivated(int) { m_ControlInterface->SetScanningDepth(ui->scanningDepthComboBox->currentText().toDouble()); } void QmitkUSControlsBModeWidget::OnPowerControlValueChanged(int value) { m_ControlInterface->SetScanningPower(static_cast(value)); + ui->scanningPowerLabel_value->setText(QString::number(value) +"%"); + } void QmitkUSControlsBModeWidget::OnGainControlValueChanged(int value) { m_ControlInterface->SetScanningGain(static_cast(value)); + ui->scanningGainLabel_value->setText(QString::number(value) + "%"); } void QmitkUSControlsBModeWidget::OnRejectionControlValueChanged(int value) { m_ControlInterface->SetScanningRejection(static_cast(value)); + ui->scanningRejectionLabel_value->setText(QString::number(value)); } void QmitkUSControlsBModeWidget::OnDynamicRangeControlValueChanged(int value) { m_ControlInterface->SetScanningDynamicRange(static_cast(value)); + ui->scanningDynamicRangeLabel_value->setText(QString::number(value) + "dB"); } \ No newline at end of file diff --git a/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.ui b/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.ui index 5de348c171..fdeae33882 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.ui +++ b/Modules/USUI/Qmitk/QmitkUSControlsBModeWidget.ui @@ -1,593 +1,689 @@ QmitkUSControlsBModeWidget 0 0 372 394 Form - - + + Depth Control - + - :/USUI/zoom-out.png:/USUI/zoom-out.png 0 0 + :/USUI/zoom-in.png:/USUI/zoom-in.png - + Frequency Control - + - :/USUI/zoom-out.png:/USUI/zoom-out.png + :/USUI/zoom-in.png:/USUI/zoom-in.png - - - - Power Control - - + + + + + + Power Control : + + + + + + + 100 % + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + 0 15 true Qt::Horizontal false false QSlider::NoTicks - + 16777215 10 6 0% 16777215 10 Qt::Horizontal 40 20 16777215 10 6 100% - - - - Gain Control - - + + + + + + Gain Control : + + + + + + + 100 % + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + 0 15 Qt::Horizontal QSlider::NoTicks - + 16777215 10 6 0% 16777215 10 Qt::Horizontal 40 20 16777215 10 6 100% - - - - Dynamic Range Control - - + + + + + + Dynamic Range Control : + + + + + + + 80 dB + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + 0 15 Qt::Horizontal QSlider::NoTicks - + 16777215 10 6 20 dB 16777215 10 Qt::Horizontal 40 20 16777215 10 6 80 dB - - - - Rejection Control - - + + + + + + Rejection Control : + + + + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - + 0 15 Qt::Horizontal QSlider::NoTicks - + 16777215 10 6 0 16777215 10 Qt::Horizontal 40 20 16777215 10 6 32 - + Qt::Vertical 20 40 QmitkComboBoxStepThrough QComboBox
QmitkComboBoxStepThrough.h
SignalReachedBegin(bool) SignalReachedEnd(bool) OnSetPreviousIndex() OnSetNextIndex()
scanningDepthNext clicked() scanningDepthComboBox OnSetNextIndex() 197 36 107 35 scanningDepthPrev clicked() scanningDepthComboBox OnSetPreviousIndex() 17 36 107 35 scanningDepthComboBox SignalReachedBegin(bool) scanningDepthPrev setDisabled(bool) 107 35 17 36 scanningDepthComboBox SignalReachedEnd(bool) scanningDepthNext setDisabled(bool) 107 35 197 36 scanningFrequencyNext clicked() scanningFrequencyComboBox OnSetNextIndex() 50 39 136 39 scanningFrequencyPrev clicked() scanningFrequencyComboBox OnSetPreviousIndex() 21 39 136 39 scanningFrequencyComboBox SignalReachedBegin(bool) scanningFrequencyPrev setDisabled(bool) 136 39 21 39 scanningFrequencyComboBox SignalReachedEnd(bool) scanningFrequencyNext setDisabled(bool) 136 39 50 39
diff --git a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp index 6785955e4a..132923bbc3 100644 --- a/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSControlsCustomVideoDeviceWidget.cpp @@ -1,172 +1,181 @@ /*=================================================================== 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 "QmitkUSControlsCustomVideoDeviceWidget.h" #include "ui_QmitkUSControlsCustomVideoDeviceWidget.h" #include #include QmitkUSControlsCustomVideoDeviceWidget::QmitkUSControlsCustomVideoDeviceWidget() : ui(new Ui::QmitkUSControlsCustomVideoDeviceWidget) { } QmitkUSControlsCustomVideoDeviceWidget::QmitkUSControlsCustomVideoDeviceWidget(QWidget *parent) : QmitkUSAbstractCustomWidget(parent), ui(new Ui::QmitkUSControlsCustomVideoDeviceWidget) { m_Cropping.left = 0; m_Cropping.top = 0; m_Cropping.right = 0; m_Cropping.bottom = 0; } QmitkUSControlsCustomVideoDeviceWidget::~QmitkUSControlsCustomVideoDeviceWidget() { delete ui; } std::string QmitkUSControlsCustomVideoDeviceWidget::GetDeviceClass() const { return mitk::USVideoDevice::GetDeviceClassStatic(); } QmitkUSAbstractCustomWidget* QmitkUSControlsCustomVideoDeviceWidget::Clone(QWidget* parent) const { QmitkUSAbstractCustomWidget* clonedWidget = new QmitkUSControlsCustomVideoDeviceWidget(parent); clonedWidget->SetDevice(this->GetDevice()); return clonedWidget; } void QmitkUSControlsCustomVideoDeviceWidget::OnDeviceSet() { m_ControlInterface = dynamic_cast (this->GetDevice()->GetControlInterfaceCustom().GetPointer()); if (m_ControlInterface.IsNotNull()) { - mitk::USImageVideoSource::USImageCropping cropping = m_ControlInterface->GetCropArea(); - ui->crop_left->setValue(cropping.left); - ui->crop_right->setValue(cropping.right); - ui->crop_bot->setValue(cropping.bottom); - ui->crop_top->setValue(cropping.top); - //get all probes and put their names into a combobox std::vector probes = m_ControlInterface->GetProbes(); for (std::vector::iterator it = probes.begin(); it != probes.end(); it++) { std::string probeName = (*it)->GetName(); ui->m_ProbeIdentifier->addItem(QString::fromUtf8(probeName.data(), probeName.size())); } m_ControlInterface->SetDefaultProbeAsCurrentProbe(); SetDepthsForProbe( ui->m_ProbeIdentifier->currentText().toStdString() ); m_ControlInterface->SetNewDepth( ui->m_UsDepth->currentText().toDouble() ); connect(ui->m_UsDepth, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnDepthChanged())); connect(ui->m_ProbeIdentifier, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnProbeChanged())); + // Call GetCropArea after the current ultrasound probe was set as default probe: + mitk::USProbe::USProbeCropping cropping = m_ControlInterface->GetCropArea(); + ui->crop_left->setValue(cropping.left); + ui->crop_right->setValue(cropping.right); + ui->crop_bot->setValue(cropping.bottom); + ui->crop_top->setValue(cropping.top); + } else { MITK_WARN("QmitkUSAbstractCustomWidget")("QmitkUSControlsCustomVideoDeviceWidget") << "Did not get a custom video device control interface."; } ui->crop_left->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_right->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_bot->setEnabled(m_ControlInterface.IsNotNull()); ui->crop_top->setEnabled(m_ControlInterface.IsNotNull()); } void QmitkUSControlsCustomVideoDeviceWidget::Initialize() { ui->setupUi(this); connect(ui->crop_left, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_right, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_top, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); connect(ui->crop_bot, SIGNAL(valueChanged(int)), this, SLOT(OnCropAreaChanged())); } void QmitkUSControlsCustomVideoDeviceWidget::OnCropAreaChanged() { if (m_ControlInterface.IsNull()) { return; } mitk::USImageVideoSource::USImageCropping cropping; cropping.left = ui->crop_left->value(); cropping.top = ui->crop_top->value(); cropping.right = ui->crop_right->value(); cropping.bottom = ui->crop_bot->value(); try { m_ControlInterface->SetCropArea(cropping); + m_ControlInterface->UpdateProbeCropping(cropping); m_Cropping = cropping; } catch (mitk::Exception e) { m_ControlInterface->SetCropArea(m_Cropping); // reset to last valid crop + m_ControlInterface->UpdateProbeCropping(m_Cropping); //reset values BlockSignalAndSetValue(ui->crop_left, m_Cropping.left); BlockSignalAndSetValue(ui->crop_right, m_Cropping.right); BlockSignalAndSetValue(ui->crop_top, m_Cropping.top); BlockSignalAndSetValue(ui->crop_bot, m_Cropping.bottom); // inform user QMessageBox msgBox; msgBox.setInformativeText("The crop area you specified is invalid.\nPlease make sure that no more pixels are cropped than are available."); msgBox.setStandardButtons(QMessageBox::Ok); msgBox.exec(); MITK_WARN << "User tried to crop beyond limits of the image"; } } void QmitkUSControlsCustomVideoDeviceWidget::OnDepthChanged() { double depth = ui->m_UsDepth->currentText().toDouble(); MITK_INFO << "OnDepthChanged() " << depth; m_ControlInterface->SetNewDepth(depth); } void QmitkUSControlsCustomVideoDeviceWidget::OnProbeChanged() { std::string probename = ui->m_ProbeIdentifier->currentText().toStdString(); m_ControlInterface->SetNewProbeIdentifier(probename); SetDepthsForProbe(probename); + + mitk::USProbe::USProbeCropping cropping = m_ControlInterface->GetCropArea(); + ui->crop_left->setValue(cropping.left); + ui->crop_right->setValue(cropping.right); + ui->crop_bot->setValue(cropping.bottom); + ui->crop_top->setValue(cropping.top); } void QmitkUSControlsCustomVideoDeviceWidget::BlockSignalAndSetValue(QSpinBox* target, int value) { bool oldState = target->blockSignals(true); target->setValue(value); target->blockSignals(oldState); } void QmitkUSControlsCustomVideoDeviceWidget::SetDepthsForProbe(std::string probename) { ui->m_UsDepth->clear(); std::vector depths = m_ControlInterface->GetDepthsForProbe(probename); for (std::vector::iterator it = depths.begin(); it != depths.end(); it++) { ui->m_UsDepth->addItem(QString::number(*it)); } } diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp index 8b72ad79a4..7c3dcfdbb3 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp @@ -1,811 +1,811 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ //#define _USE_MATH_DEFINES #include // QT headers #include #include // mitk headers // itk headers #include #include const std::string QmitkUSNewVideoDeviceWidget::VIEW_ID = "org.mitk.views.QmitkUSNewVideoDeviceWidget"; QmitkUSNewVideoDeviceWidget::QmitkUSNewVideoDeviceWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; CreateQtPartControl(this); } QmitkUSNewVideoDeviceWidget::~QmitkUSNewVideoDeviceWidget() {} //////////////////// INITIALIZATION ///////////////////// void QmitkUSNewVideoDeviceWidget::CreateQtPartControl(QWidget* parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkUSNewVideoDeviceWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkUSNewVideoDeviceWidget::CreateConnections() { if (m_Controls) { // connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, // SLOT(OnClickedDone())); connect(m_Controls->m_BtnCancel, SIGNAL(clicked()), this, SLOT(OnClickedCancel())); connect(m_Controls->m_RadioDeviceSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioFileSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLClientSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLServerSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonClicked())); connect(m_Controls->m_BtnSave, SIGNAL(clicked()), this, SLOT(OnSaveButtonClicked())); connect(m_Controls->m_BtnLoadConfiguration, SIGNAL(clicked()), this, SLOT(OnLoadConfigurationButtonClicked())); //Connect buttons and functions for editing of probes connect(m_Controls->m_AddNewProbePushButton, SIGNAL(clicked()), this, SLOT(OnAddNewProbeClicked())); connect(m_Controls->m_BtnRemoveProbe, SIGNAL(clicked()), this, SLOT(OnClickedRemoveProbe())); connect(m_Controls->m_BtnRemoveDepth, SIGNAL(clicked()), this, SLOT(OnClickedRemoveDepth())); connect(m_Controls->m_BtnAddDepths, SIGNAL(clicked()), this, SLOT(OnClickedAddDepths())); connect(m_Controls->m_Probes, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnProbeChanged(const QString &))); connect(m_Controls->m_Depths, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnDepthChanged(const QString &))); connect(m_Controls->m_XSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnXSpacingSpinBoxChanged(double))); connect(m_Controls->m_YSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnYSpacingSpinBoxChanged(double))); connect(m_Controls->m_CroppingTopSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingTopSpinBoxChanged(int))); connect(m_Controls->m_CroppingRightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingRightSpinBoxChanged(int))); connect(m_Controls->m_CroppingBottomSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingBottomSpinBoxChanged(int))); connect(m_Controls->m_CroppingLeftSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingLeftSpinBoxChanged(int))); } } ///////////// Methods & Slots Handling Direct Interaction ///////////////// void QmitkUSNewVideoDeviceWidget::OnClickedDone() { m_Active = false; // Create Device mitk::USVideoDevice::Pointer newDevice; if (m_Controls->m_RadioDeviceSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_DeviceSelector->value(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioFileSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_FilePathSelector->text().toStdString(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioOIGTLClientSource->isChecked()) { std::string host = m_Controls->m_OIGTLClientHost->text().toStdString(); int port = m_Controls->m_OIGTLClientPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a client. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, false); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } else { std::string host = m_Controls->m_OIGTLServerHost->text().toStdString(); int port = m_Controls->m_OIGTLServerPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a server. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, true); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } // get USImageVideoSource from new device mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( newDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } if (m_Controls->m_Probes->count() != 0 ) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(newDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); newDevice->DeleteAllProbes(); newDevice->AddNewProbe(probe); } newDevice->Initialize(); CleanUpAfterCreatingNewDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedFinishedEditing() { m_Active = false; m_TargetDevice->SetManufacturer(m_Controls->m_Manufacturer->text().toStdString()); m_TargetDevice->SetName(m_Controls->m_Model->text().toStdString()); m_TargetDevice->SetComment(m_Controls->m_Comment->text().toStdString()); if (m_Controls->m_Probes->count() != 0) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(m_TargetDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); m_TargetDevice->DeleteAllProbes(); m_TargetDevice->AddNewProbe(probe); } mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( m_TargetDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } CleanUpAfterEditingOfDevice(); MITK_INFO << "Finished Editing"; emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedCancel() { m_TargetDevice = nullptr; m_Active = false; CleanUpAfterCreatingNewDevice(); CleanUpAfterEditingOfDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnDeviceTypeSelection() { m_Controls->m_FilePathSelector->setEnabled( m_Controls->m_RadioFileSource->isChecked()); m_Controls->m_DeviceSelector->setEnabled( m_Controls->m_RadioDeviceSource->isChecked()); m_Controls->m_OIGTLClientHost->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLClientPort->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLServerHost->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); m_Controls->m_OIGTLServerPort->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); } void QmitkUSNewVideoDeviceWidget::OnOpenFileButtonClicked() { QString fileName = QFileDialog::getOpenFileName(nullptr, "Open Video File"); if (fileName.isNull()) { return; } // user pressed cancel m_Controls->m_FilePathSelector->setText(fileName); m_Controls->m_RadioFileSource->setChecked(true); this->OnDeviceTypeSelection(); } ///////////////// Methods & Slots Handling Logic ////////////////////////// void QmitkUSNewVideoDeviceWidget::EditDevice(mitk::USDevice::Pointer device) { // If no VideoDevice is given, throw an exception if (device->GetDeviceClass().compare("org.mitk.modules.us.USVideoDevice") != 0) { // TODO Alert if bad path mitkThrow() << "NewVideoDeviceWidget recieved an incompatible device type " "to edit. Type was: " << device->GetDeviceClass(); } m_TargetDevice = static_cast(device.GetPointer()); m_Active = true; m_ConfigProbes.clear(); m_ConfigProbes = m_TargetDevice->GetAllProbes(); ChangeUIEditingUSVideoDevice(); } void QmitkUSNewVideoDeviceWidget::CreateNewDevice() { //Toggle functionality of Btn_Done connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_BtnDone->setText("Add Video Device"); //Fill Metadata with default information m_Controls->m_Manufacturer->setText("Unknown Manufacturer"); m_Controls->m_Model->setText("Unknown Model"); m_Controls->m_Comment->setText("None"); m_TargetDevice = nullptr; m_ConfigProbes.clear(); m_Active = true; } /////////////////////// HOUSEHOLDING CODE /////////////////////////////// QListWidgetItem* QmitkUSNewVideoDeviceWidget::ConstructItemFromDevice( mitk::USDevice::Pointer device) { QListWidgetItem* result = new QListWidgetItem; std::string text = device->GetManufacturer() + "|" + device->GetName(); result->setText(text.c_str()); return result; } void QmitkUSNewVideoDeviceWidget::ChangeUIEditingUSVideoDevice() { for (std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { std::string probeName = (*it)->GetName(); m_Controls->m_Probes->addItem(QString::fromUtf8(probeName.data(), probeName.size())); } OnProbeChanged(m_Controls->m_Probes->currentText()); //Toggle functionality of Btn_Done m_Controls->m_BtnDone->setText("Apply Changes"); connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); //Fill Metadata with Information provided by the Device selected to edit m_Controls->m_Manufacturer->setText(m_TargetDevice->GetManufacturer().c_str()); m_Controls->m_Model->setText(m_TargetDevice->GetName().c_str()); m_Controls->m_Comment->setText(m_TargetDevice->GetComment().c_str()); } void QmitkUSNewVideoDeviceWidget::OnClickedAddDepths() { if (!m_Controls->m_Probes->currentText().isEmpty()) { QString depths = m_Controls->m_AddDepths->text(); if( depths.isEmpty() ) return; std::string probename = m_Controls->m_Probes->currentText().toStdString(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); QStringList singleDepths = depths.split(','); for (int i = 0; i < singleDepths.size(); i++) { currentProbe->SetDepth(singleDepths.at(i).toInt()); } m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); OnProbeChanged(m_Controls->m_Probes->currentText()); } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveDepth() { if (!m_Controls->m_Probes->currentText().isEmpty() && !m_Controls->m_Depths->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfDepthToRemove = m_Controls->m_Depths->currentIndex(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); currentProbe->RemoveDepth(m_Controls->m_Depths->currentText().toInt()); m_Controls->m_Depths->removeItem(indexOfDepthToRemove); if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveProbe() { if (!m_Controls->m_Probes->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfProbeToRemove = m_Controls->m_Probes->currentIndex(); m_ConfigProbes.erase(m_ConfigProbes.begin() + indexOfProbeToRemove); m_Controls->m_Probes->removeItem(indexOfProbeToRemove); if( m_Controls->m_Probes->count() == 0 ) { m_Controls->m_Probes->setEnabled(false); m_Controls->m_BtnRemoveProbe->setEnabled(false); m_Controls->m_BtnAddDepths->setEnabled(false); m_Controls->m_AddDepths->setEnabled(false); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnProbeChanged(const QString & probename) { if (!probename.isEmpty()) { std::string name = probename.toStdString(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(name); if( probe.IsNotNull() ) { std::map depths = probe->GetDepthsAndSpacing(); m_Controls->m_Depths->clear(); for (std::map::iterator it = depths.begin(); it != depths.end(); it++) { m_Controls->m_Depths->addItem(QString::number(it->first)); } this->OnDepthChanged(m_Controls->m_Depths->currentText().toInt(), probe); } } else { m_Controls->m_Depths->clear(); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); } } -void QmitkUSNewVideoDeviceWidget::OnDepthChanged(int depth, mitk::USProbe* probe) +void QmitkUSNewVideoDeviceWidget::OnDepthChanged(int depth, mitk::USProbe::Pointer probe) { if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); return; } - if (probe != nullptr) + if (probe.IsNotNull()) { mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); m_Controls->m_XSpacingSpinBox->setValue(spacing[0]); m_Controls->m_YSpacingSpinBox->setValue(spacing[1]); mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); m_Controls->m_CroppingTopSpinBox->setValue(cropping.top); m_Controls->m_CroppingRightSpinBox->setValue(cropping.right); m_Controls->m_CroppingBottomSpinBox->setValue(cropping.bottom); m_Controls->m_CroppingLeftSpinBox->setValue(cropping.left); this->EnableDisableSpacingAndCropping(true); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); } } void QmitkUSNewVideoDeviceWidget::OnDepthChanged(const QString &depth) { MITK_INFO << "OnDepthChanged(int, mitk::USProbe)"; if( depth.isEmpty() ) { this->EnableDisableSpacingAndCropping(false); return; } QString probeName = m_Controls->m_Probes->currentText(); this->OnDepthChanged(depth.toInt(), this->CheckIfProbeExistsAlready(probeName.toStdString()) ); } void QmitkUSNewVideoDeviceWidget::OnSaveButtonClicked() { QString fileName = QFileDialog::getSaveFileName(nullptr, "Save Configuration ...", "", "XML files (*.xml)"); if( fileName.isNull() ) { return; } // user pressed cancel mitk::USDeviceWriterXML deviceWriter; deviceWriter.SetFilename(fileName.toStdString()); mitk::USDeviceReaderXML::USVideoDeviceConfigData config; this->CollectUltrasoundVideoDeviceConfigInformation(config); if (!deviceWriter.WriteUltrasoundVideoDeviceConfiguration(config)) { QMessageBox msgBox; msgBox.setText("Error when writing the configuration to the selected file. Could not write device information."); msgBox.exec(); return; } } void QmitkUSNewVideoDeviceWidget::OnLoadConfigurationButtonClicked() { QString fileName = QFileDialog::getOpenFileName(this, "Open ultrasound device configuration ..."); if (fileName.isNull()) { return; } // user pressed cancel mitk::USDeviceReaderXML deviceReader; deviceReader.SetFilename(fileName.toStdString()); if (!deviceReader.ReadUltrasoundDeviceConfiguration()) { QMessageBox msgBox; msgBox.setText("Error when parsing the selected file. Could not load stored device information."); msgBox.exec(); return; } mitk::USDeviceReaderXML::USVideoDeviceConfigData config = deviceReader.GetUSVideoDeviceConfigData(); if( config.fileversion == 1.0 ) { if (config.deviceType.compare("video") == 0) { //Fill info in metadata groupbox: m_Controls->m_DeviceName->setText(QString::fromStdString(config.deviceName)); m_Controls->m_Manufacturer->setText(QString::fromStdString(config.manufacturer)); m_Controls->m_Model->setText(QString::fromStdString(config.model)); m_Controls->m_Comment->setText(QString::fromStdString(config.comment)); //Fill info about video source: m_Controls->m_DeviceSelector->setValue(config.sourceID); m_Controls->m_FilePathSelector->setText(QString::fromStdString(config.filepathVideoSource)); //Fill video options: m_Controls->m_CheckGreyscale->setChecked(config.useGreyscale); //Fill override options: m_Controls->m_CheckResolutionOverride->setChecked(config.useResolutionOverride); m_Controls->m_ResolutionWidth->setValue(config.resolutionWidth); m_Controls->m_ResolutionHeight->setValue(config.resolutionHeight); //Fill information about probes: m_ConfigProbes.clear(); m_ConfigProbes = config.probes; m_Controls->m_Probes->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->clear(); for( size_t index = 0; index < m_ConfigProbes.size(); ++index) { m_Controls->m_Probes->addItem(QString::fromStdString(config.probes.at(index)->GetName())); } this->OnProbeChanged(m_Controls->m_Probes->currentText()); } else { MITK_WARN << "Unknown device type detected. The device type must be of type |video|"; } } else { MITK_WARN << "Unknown fileversion. Only fileversion 1.0 is known to the system."; } } void QmitkUSNewVideoDeviceWidget::OnAddNewProbeClicked() { QString probeName = m_Controls->m_ProbeNameLineEdit->text(); probeName = probeName.trimmed(); if (probeName.isEmpty()) { m_Controls->m_ProbeNameLineEdit->clear(); return; } if( this->CheckIfProbeExistsAlready(probeName.toStdString() ) != nullptr ) { QMessageBox msgBox; msgBox.setText("Probe name already exists. Please choose another name for the probe."); msgBox.exec(); m_Controls->m_ProbeNameLineEdit->clear(); } else { mitk::USProbe::Pointer newProbe = mitk::USProbe::New(probeName.toStdString()); m_ConfigProbes.push_back(newProbe); m_Controls->m_Probes->addItem(QString::fromStdString(probeName.toStdString())); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_ProbeNameLineEdit->clear(); } } void QmitkUSNewVideoDeviceWidget::OnXSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing x-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[0] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnYSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing y-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[1] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnCroppingTopSpinBoxChanged(int value) { MITK_INFO << "Changing cropping top to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(value, cropping.bottom, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingRightSpinBoxChanged(int value) { MITK_INFO << "Changing cropping right to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, cropping.left, value); } void QmitkUSNewVideoDeviceWidget::OnCroppingBottomSpinBoxChanged(int value) { MITK_INFO << "Changing cropping bottom to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, value, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingLeftSpinBoxChanged(int value) { MITK_INFO << "Changing cropping left to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, value, cropping.right); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterCreatingNewDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterEditingOfDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::AddProbesToDevice(mitk::USVideoDevice::Pointer device) { device->DeleteAllProbes(); for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { if ((*it)->IsDepthAndSpacingEmpty()) { (*it)->SetDepth(0); } device->AddNewProbe((*it)); } } -mitk::USProbe::Pointer QmitkUSNewVideoDeviceWidget::CheckIfProbeExistsAlready(std::string &probeName) +mitk::USProbe::Pointer QmitkUSNewVideoDeviceWidget::CheckIfProbeExistsAlready(const std::string &probeName) { for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++ ) { if( probeName.compare((*it)->GetName()) == 0) return (*it); } return nullptr; //no matching probe was found so nullptr is returned } void QmitkUSNewVideoDeviceWidget::CollectUltrasoundVideoDeviceConfigInformation(mitk::USDeviceReaderXML::USVideoDeviceConfigData &config) { config.fileversion = 1.0; config.deviceType = "video"; //Fill info in metadata groupbox: config.deviceName = m_Controls->m_DeviceName->text().toStdString(); config.manufacturer = m_Controls->m_Manufacturer->text().toStdString(); config.model = m_Controls->m_Model->text().toStdString(); config.comment = m_Controls->m_Comment->text().toStdString(); //Fill info about video source: config.sourceID = m_Controls->m_DeviceSelector->value(); config.filepathVideoSource = m_Controls->m_FilePathSelector->text().toStdString(); //Fill video options: config.useGreyscale = m_Controls->m_CheckGreyscale->isChecked(); //Fill override options: config.useResolutionOverride = m_Controls->m_CheckResolutionOverride->isChecked(); config.resolutionWidth = m_Controls->m_ResolutionWidth->value(); config.resolutionHeight = m_Controls->m_ResolutionHeight->value(); //Fill information about probes: config.probes = m_ConfigProbes; } void QmitkUSNewVideoDeviceWidget::EnableDisableSpacingAndCropping(bool enable) { m_Controls->m_XSpacingSpinBox->setEnabled(enable); m_Controls->m_YSpacingSpinBox->setEnabled(enable); m_Controls->m_XSpacingLabel->setEnabled(enable); m_Controls->m_YSpacingLabel->setEnabled(enable); m_Controls->m_CroppingTopSpinBox->setEnabled(enable); m_Controls->m_CroppingRightSpinBox->setEnabled(enable); m_Controls->m_CroppingBottomSpinBox->setEnabled(enable); m_Controls->m_CroppingLeftSpinBox->setEnabled(enable); m_Controls->m_CroppingTopLabel->setEnabled(enable); m_Controls->m_CroppingBottomLabel->setEnabled(enable); m_Controls->m_CroppingLeftLabel->setEnabled(enable); m_Controls->m_CroppingRightLabel->setEnabled(enable); } diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h index 531d3a342b..6c7aef6b49 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h @@ -1,169 +1,169 @@ /*=================================================================== 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 _QmitkUSNewVideoDeviceWidget_H_INCLUDED #define _QmitkUSNewVideoDeviceWidget_H_INCLUDED #include "MitkUSUIExports.h" #include "ui_QmitkUSNewVideoDeviceWidgetControls.h" #include "mitkUSVideoDevice.h" #include "mitkUSIGTLDevice.h" #include "mitkUSDeviceReaderXML.h" //QT headers #include #include //mitk header /** * @brief This Widget enables the USer to create and connect Video Devices. * * @ingroup USUI */ class MITKUSUI_EXPORT QmitkUSNewVideoDeviceWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkUSNewVideoDeviceWidget(QWidget* p = nullptr, Qt::WindowFlags f1 = nullptr); ~QmitkUSNewVideoDeviceWidget() override; /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); signals: void Finished(); public slots: /* \brief Activates the widget and displays the given device's Data to edit. */ void EditDevice(mitk::USDevice::Pointer device); /* \brief Activates the widget with fields empty. */ void CreateNewDevice(); protected slots: /* \brief Called, when the the user clicks the "Done" button (Labeled either "Add Device" or "Edit Device", depending on the situation. */ void OnClickedDone(); void OnClickedFinishedEditing(); /* \brief Called, when the button "Cancel" was clicked */ void OnClickedCancel(); /* \brief Called, when the Use selects one of the Radiobuttons */ void OnDeviceTypeSelection(); void OnOpenFileButtonClicked(); void OnClickedRemoveProbe(); void OnClickedRemoveDepth(); void OnClickedAddDepths(); void OnProbeChanged(const QString & probename); - void OnDepthChanged(int depth, mitk::USProbe* probe); + void OnDepthChanged(int depth, mitk::USProbe::Pointer probe); void OnDepthChanged(const QString &depth); void OnSaveButtonClicked(); void OnLoadConfigurationButtonClicked(); void OnAddNewProbeClicked(); void OnXSpacingSpinBoxChanged(double value); void OnYSpacingSpinBoxChanged(double value); void OnCroppingTopSpinBoxChanged(int value); void OnCroppingRightSpinBoxChanged(int value); void OnCroppingBottomSpinBoxChanged(int value); void OnCroppingLeftSpinBoxChanged(int value); protected: Ui::QmitkUSNewVideoDeviceWidgetControls* m_Controls; ///< member holding the UI elements of this widget /* \brief Constructs a ListItem from the given device for display in the list of active devices */ QListWidgetItem* ConstructItemFromDevice(mitk::USDevice::Pointer device); void ChangeUIEditingUSVideoDevice(); void CleanUpAfterEditingOfDevice(); void CleanUpAfterCreatingNewDevice(); void AddProbesToDevice(mitk::USVideoDevice::Pointer device); - mitk::USProbe::Pointer CheckIfProbeExistsAlready(std::string &probe); + mitk::USProbe::Pointer CheckIfProbeExistsAlready(const std::string &probe); void CollectUltrasoundVideoDeviceConfigInformation(mitk::USDeviceReaderXML::USVideoDeviceConfigData &config); /** * \brief Enables or disables the GUI elements of the spacing and cropping options. * \param enable If true: the GUI elements are enabled. If false: elements are disabled. */ void EnableDisableSpacingAndCropping(bool enable); /* \brief Displays whether this widget is active or not. It gets activated by either sending a Signal to * the "CreateNewDevice" Slot or to the "EditDevice" Slot. If the user finishes editing the device, a * "EditingComplete" Signal is sent, and the widget is set to inactive again. Clicking Cancel also * deactivates it. */ bool m_Active; /** * \brief This is the device to edit. It is either the device transmitted in the "EditDevice" signal, or a new one * if the "CreateNewDevice slot was called. */ mitk::USVideoDevice::Pointer m_TargetDevice; /** * \brief The config probes are used to have a possibility to configure ultrasound probes without having an existing * created USVideoDevice yet. */ std::vector m_ConfigProbes; }; #endif // _QmitkUSNewVideoDeviceWidget_H_INCLUDED diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 03f3de6e54..ecfb25c700 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,102 +1,103 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF + org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tbss:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.cest:OFF ) diff --git a/Plugins/org.blueberry.ui.qt.help/resources/help.svg b/Plugins/org.blueberry.ui.qt.help/resources/help.svg index 2eea8fafba..13b270ac75 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/help.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/help.svg @@ -1,54 +1,54 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg b/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg index 1bd9d6cf2d..df07bbce39 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg @@ -1,62 +1,62 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg b/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg index 63c3cd84db..3f27badd40 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg @@ -1,59 +1,59 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.log/resources/logging.svg b/Plugins/org.blueberry.ui.qt.log/resources/logging.svg index bf7e60d22b..2b9894f8f8 100644 --- a/Plugins/org.blueberry.ui.qt.log/resources/logging.svg +++ b/Plugins/org.blueberry.ui.qt.log/resources/logging.svg @@ -1,74 +1,74 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg index 579aeb2abe..2d55a20f8c 100644 --- a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg +++ b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg @@ -1,74 +1,74 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg index 32dda23c66..4582f8cfae 100644 --- a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg +++ b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg @@ -1,79 +1,79 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/resources/tab_close.svg b/Plugins/org.blueberry.ui.qt/resources/tab_close.svg index 7a3bdfb95a..8e9ca2109d 100644 --- a/Plugins/org.blueberry.ui.qt/resources/tab_close.svg +++ b/Plugins/org.blueberry.ui.qt/resources/tab_close.svg @@ -1,56 +1,56 @@ image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml b/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml index ffc671d614..bb84a730ad 100644 --- a/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml +++ b/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml @@ -1,47 +1,47 @@ - + Perform basic image operations like add, subtract etc.. diff --git a/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui index 179daf05a9..b6a6c4dd2b 100644 --- a/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui @@ -1,473 +1,428 @@ QmitkBasicImageProcessingViewControls 0 0 448 980 Form - true + false - - 0 - - - 6 - - - 0 - - - 6 - Filters (One Image) true Arithmetic (Two Images) - Select an Image in Data Manager + Select an image in the Data Manager true false Output image will be 3D Choose time step if 4D (Slider for both images) false false Output image will be 3D true - - true - - - false - false - - 0 - - - 6 - - - 0 - - - 0 - false Select second image: false m_ImageSelector2 false false E&xecute false Select an operation: false cbWhat2 false Qt::Vertical 254 403 - - true - - - 0 - - - 6 - - - 0 - - - 0 - false Select an operation: false cbWhat1 false false ... and parameters: false false Parameter 1: false sbParam1 false Parameter 2: false sbParam2 false &Execute false Hide Original Image true false Parameter 3: false Parameter 4: false 0 0 false 0 0 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 -999999999 999999999 false 0 0 -999999999 999999999 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 2564418383..850134fb4e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,38 +1,62 @@ 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/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/plugin.xml b/Plugins/org.mitk.gui.qt.common/plugin.xml new file mode 100644 index 0000000000..e81a484d36 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/plugin.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/resources/times.svg b/Plugins/org.mitk.gui.qt.common/resources/times.svg new file mode 100644 index 0000000000..571a32a122 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/resources/times.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp new file mode 100644 index 0000000000..669c0b128f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp @@ -0,0 +1,114 @@ +/*=================================================================== + +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 "QmitkAbstractNodeSelectionWidget.h" + +#include +#include + +QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent), m_InvalidInfo("Error. Select data."), +m_EmptyInfo("Empty. Make a selection."), m_PopUpTitel("Select a data node"), m_PopUpHint(""), +m_IsOptional(false), m_SelectOnlyVisibleNodes(true) +{ +} + +void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + } +}; + +void QmitkAbstractNodeSelectionWidget::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->OnNodePredicateChanged(nodePredicate); + this->UpdateInfo(); + } +}; + +mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const +{ + return m_InvalidInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const +{ + return m_EmptyInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const +{ + return m_PopUpTitel; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const +{ + return m_PopUpHint; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const +{ + return m_IsOptional; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) +{ + m_InvalidInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) +{ + m_EmptyInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info) +{ + m_PopUpTitel = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info) +{ + m_PopUpHint = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional) +{ + m_IsOptional = isOptional; + this->UpdateInfo(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h new file mode 100644 index 0000000000..0292dca521 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h @@ -0,0 +1,149 @@ +/*=================================================================== + +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 QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H +#define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkAbstractNodeSelectionWidget +* \brief Abstract base class for the selection of data from a data storage. +*/ +class MITK_QT_COMMON QmitkAbstractNodeSelectionWidget : public QWidget +{ + Q_OBJECT + +public: + explicit QmitkAbstractNodeSelectionWidget(QWidget* parent = nullptr); + + /** + * @brief Sets the data storage that will be used /monitored by widget. + * + * @par dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * Sets the node predicate and updates the widget, according to the node predicate. + * Implement OnNodePredicateChange() for custom actualization of a derived widget class. + * + * @par nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + QString GetInvalidInfo() const; + QString GetEmptyInfo() const; + QString GetPopUpTitel() const; + QString GetPopUpHint() const; + + bool GetSelectionIsOptional() const; + + bool GetSelectOnlyVisibleNodes() const; + + using NodeList = QList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @par selectOnlyVisibleNodes The bool value to define the selection modus. + */ + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @par nodes A list of data nodes that should be newly selected. + */ + virtual void SetCurrentSelection(NodeList selectedNodes) = 0; + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is mandatory. + * The string can contain HTML code. if wanted*/ + void SetInvalidInfo(QString info); + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is optional. + * The string can contain HTML code. if wanted*/ + void SetEmptyInfo(QString info); + + /** Set the caption of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpTitel(QString info); + + /** Set the hint text of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpHint(QString info); + + /** Set the widget into an optional mode. Optional means that the selection of no valid + node does not mean an invalid state. Thus no node is a valid "node" selection too.*/ + void SetSelectionIsOptional(bool isOptional); + +protected: + /**Member is called if the display of the selected nodes should be updated.*/ + virtual void UpdateInfo() = 0; + + /**Member is called if the predicate has changed. Thus the selection might change to.*/ + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + QString m_InvalidInfo; + QString m_EmptyInfo; + QString m_PopUpTitel; + QString m_PopUpHint; + + bool m_IsOptional; + bool m_SelectOnlyVisibleNodes; +}; +#endif // QmitkAbstractNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp new file mode 100644 index 0000000000..47b5f1d2cc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp @@ -0,0 +1,167 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkMultiNodeSelectionWidget.h" + +#include +#include +#include + +QmitkMultiNodeSelectionWidget::QmitkMultiNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + this->UpdateList(); + this->UpdateInfo(); + + connect(m_Controls.btnChange, SIGNAL(clicked(bool)), this, SLOT(OnEditSelection())); +} + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + for (int i = 0; i < m_Controls.list->count(); ++i) + { + QListWidgetItem* item = m_Controls.list->item(i); + + auto node = item->data(Qt::UserRole).value(); + result.append(node); + } + + + if (!m_SelectOnlyVisibleNodes) + { + for (auto node : m_CurrentSelection) + { + if (!result.contains(node)) + { + result.append(node); + } + } + } + + return result; +} + +void QmitkMultiNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + this->UpdateInfo(); + this->UpdateList(); +}; + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::GetSelectedNodes() const +{ + return m_CurrentSelection; +}; + +void QmitkMultiNodeSelectionWidget::OnEditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + dialog->SetCurrentSelection(this->CompileEmitSelection()); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + + m_Controls.btnChange->setChecked(true); + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = dialog->GetSelectedNodes(); + this->UpdateList(); + this->UpdateInfo(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + } + } + m_Controls.btnChange->setChecked(false); + + delete dialog; +}; + +void QmitkMultiNodeSelectionWidget::UpdateInfo() +{ + m_Controls.infoLabel->setVisible(m_Controls.list->count()==0); + + if (!m_Controls.list->count()) + { + if (m_IsOptional) + { + m_Controls.infoLabel->setText(m_EmptyInfo); + } + else + { + m_Controls.infoLabel->setText(m_InvalidInfo); + } + } +}; + +void QmitkMultiNodeSelectionWidget::UpdateList() +{ + m_Controls.list->clear(); + + for (auto node : m_CurrentSelection) + { + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) + { + QListWidgetItem *newItem = new QListWidgetItem; + newItem->setText(QString::fromStdString(node->GetName())); + newItem->setData(Qt::UserRole, QVariant::fromValue(node)); + + m_Controls.list->addItem(newItem); + } + } +}; + +void QmitkMultiNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateList(); + this->UpdateInfo(); + } +}; + +void QmitkMultiNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = selectedNodes; + this->UpdateList(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h new file mode 100644 index 0000000000..d1f736be51 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h @@ -0,0 +1,76 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef QMITK_MULTI_NODE_SELECTION_WIDGET_H +#define QMITK_MULTI_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkMultiNodeSelectionWidget.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkMultiNodeSelectionWidget +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkMultiNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkMultiNodeSelectionWidget(QWidget* parent = nullptr); + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + + NodeList GetSelectedNodes() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + + public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + void OnEditSelection(); + +protected: + NodeList CompileEmitSelection() const; + + virtual void UpdateInfo() override; + virtual void UpdateList(); + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_CurrentSelection; + + Ui_QmitkMultiNodeSelectionWidget m_Controls; +}; +#endif // QmitkMultiNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui new file mode 100644 index 0000000000..87eae80c7e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui @@ -0,0 +1,92 @@ + + + QmitkMultiNodeSelectionWidget + + + + 0 + 0 + 391 + 265 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::NoDragDrop + + + Qt::MoveAction + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + + + + TextLabel + + + true + + + + + + + Change selection + + + true + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp new file mode 100644 index 0000000000..fa21db2d4b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp @@ -0,0 +1,163 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkNodeSelectionButton.h" + +#include "QPainter" +#include "QTextDocument" + +#include +#include + + +// mitk core +#include +#include +#include +#include +#include +#include + +// vtk +#include + +QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode, int height) +{ + if (nullptr == dataNode) + { + return QPixmap(); + } + + const mitk::Image* image = dynamic_cast(dataNode->GetData()); + if ((nullptr == image || !image->IsInitialized()) || // -> must be an image + (image->GetPixelType().GetNumberOfComponents() != 1)) // -> for now only single component are allowed + { + auto descManager = QmitkNodeDescriptorManager::GetInstance(); + auto desc = descManager->GetDescriptor(dataNode); + auto icon = desc->GetIcon(dataNode); + auto fallBackMap = icon.pixmap(height, height); + return fallBackMap; + } + + mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); + int sliceNumber = image->GetDimension(2) / 2; + planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Axial, sliceNumber); + + mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); + extractSliceFilter->SetInput(image); + extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); + extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); + extractSliceFilter->SetWorldGeometry(planeGeometry); + extractSliceFilter->SetOutputDimensionality(2); + extractSliceFilter->SetVtkOutputRequest(true); + extractSliceFilter->Update(); + + vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); + + mitk::LevelWindow levelWindow; + dataNode->GetLevelWindow(levelWindow); + vtkSmartPointer lookupTable = vtkSmartPointer::New(); + lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); + lookupTable->SetSaturationRange(0.0, 0.0); + lookupTable->SetValueRange(0.0, 1.0); + lookupTable->SetHueRange(0.0, 0.0); + lookupTable->SetRampToLinear(); + + vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); + levelWindowFilter->SetLookupTable(lookupTable); + levelWindowFilter->SetInputData(imageData); + levelWindowFilter->SetMinOpacity(0.0); + levelWindowFilter->SetMaxOpacity(1.0); + int dims[3]; + imageData->GetDimensions(dims); + double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; + levelWindowFilter->SetClippingBounds(clippingBounds); + levelWindowFilter->Update(); + imageData = levelWindowFilter->GetOutput(); + + QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); + + thumbnailImage = thumbnailImage.scaledToHeight(height,Qt::SmoothTransformation).rgbSwapped(); + return QPixmap::fromImage(thumbnailImage); +} + +QmitkNodeSelectionButton::QmitkNodeSelectionButton(QWidget *parent) + : QPushButton(parent), m_OutDatedThumpNail(true) +{ } + +QmitkNodeSelectionButton::~QmitkNodeSelectionButton() +{ + this->m_SelectedNode = nullptr; +} + +void QmitkNodeSelectionButton::SetSelectedNode(mitk::DataNode* node) +{ + if (m_SelectedNode != node) + { + this->m_SelectedNode = node; //mitk::WeakPointer(node); + this->m_OutDatedThumpNail = true; + } + + this->update(); +}; + +void QmitkNodeSelectionButton::SetNodeInfo(QString info) +{ + this->m_Info = info; + this->update(); +}; + +void QmitkNodeSelectionButton::paintEvent(QPaintEvent *p) +{ + QPushButton::paintEvent(p); + + QPainter painter(this); + + QTextDocument td; + + auto widgetSize = this->size(); + QPoint origin = QPoint(5, 5); + + if (this->m_SelectedNode) + { + auto iconLength = widgetSize.height() - 10; + auto node = this->m_SelectedNode; // .Lock(); + + if (this->m_OutDatedThumpNail) + { + this->m_ThumpNail = GetPixmapFromImageNode(node, iconLength); + this->m_OutDatedThumpNail = false; + } + + painter.drawPixmap(origin, m_ThumpNail); + origin.setX(origin.x() + iconLength + 5); + + td.setHtml(QString::fromStdString(node->GetName())); + } + else + { + td.setHtml(m_Info); + } + + auto textSize = td.size(); + + origin.setY( (widgetSize.height() - textSize.height()) / 2.); + + painter.translate(origin); + td.drawContents(&painter); + +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h new file mode 100644 index 0000000000..74ea357652 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h @@ -0,0 +1,56 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef QMITK_NODE_SELECTION_BUTTON_H +#define QMITK_NODE_SELECTION_BUTTON_H + +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "QPushButton" +#include "QPixmap" + + +/** Button class that can be used to display informations about a passed node. + * If the passed node is a null ptr the node info text will be shown. + * In difference to the normal push button text property. The node info can + * be formated text (e.g. HTML code; like the tooltip text).*/ +class MITK_QT_COMMON QmitkNodeSelectionButton : public QPushButton +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionButton(QWidget *parent = nullptr); + ~QmitkNodeSelectionButton(); + +public Q_SLOTS : + virtual void SetSelectedNode(mitk::DataNode* node); + virtual void SetNodeInfo(QString info); + +protected: + void paintEvent(QPaintEvent *p) override; + + mitk::DataNode::Pointer m_SelectedNode; + QString m_Info; + bool m_OutDatedThumpNail; + QPixmap m_ThumpNail; +}; + + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp new file mode 100644 index 0000000000..702baa98c9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -0,0 +1,185 @@ +/*=================================================================== + +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 "QmitkNodeSelectionDialog.h" + +#include +#include +#include + +QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent), m_NodePredicate(nullptr), m_SelectOnlyVisibleNodes(false) +{ + m_Controls.setupUi(this); + + auto providers = QmitkDataStorageInspectorGenerator::GetProviders(); + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto favoriteID = mitk::GetFavoriteDataStorageInspector(); + + if (visibleProviders.empty()) + { + MITK_DEBUG << "No presets for visible node selection inspectors available. Use fallback (show all available inspectors)"; + unsigned int order = 0; + for (auto proIter : providers) + { + visibleProviders.insert(std::make_pair(order, proIter.first)); + } + } + + int favIndex = 0; + bool favoriteFound = false; + for (auto proIter : visibleProviders) + { + auto finding = providers.find(proIter.second); + if (finding != providers.end()) + { + auto inspector = finding->second->CreateInspector(); + QString name = QString::fromStdString(finding->second->GetInspectorDisplayName()); + QString desc = QString::fromStdString(finding->second->GetInspectorDescription()); + AddPanel(inspector, name, desc); + + favoriteFound = favoriteFound || proIter.second == favoriteID; + if (!favoriteFound) + { + ++favIndex; + } + } + else + { + MITK_DEBUG << "No provider registered for inspector that is defined as visible in the preferences. Illegal inspector ID: " << proIter.second; + } + } + + m_Controls.tabWidget->setCurrentIndex(favIndex); + this->setWindowTitle(title); + this->setToolTip(hint); + + m_Controls.hint->setText(hint); + m_Controls.hint->setVisible(!hint.isEmpty()); + + connect(m_Controls.buttonBox, SIGNAL(accepted()), this, SLOT(OnOK())); + connect(m_Controls.buttonBox, SIGNAL(rejected()), this, SLOT(OnCancel())); +} + +void QmitkNodeSelectionDialog::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + for (auto panel : m_Panels) + { + panel->SetDataStorage(dataStorage); + } + } + } +}; + +void QmitkNodeSelectionDialog::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + for (auto panel : m_Panels) + { + panel->SetNodePredicate(m_NodePredicate); + } + } +}; + +mitk::NodePredicateBase* QmitkNodeSelectionDialog::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QmitkNodeSelectionDialog::NodeList QmitkNodeSelectionDialog::GetSelectedNodes() const +{ + return m_SelectedNodes; +}; + +void QmitkNodeSelectionDialog::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) + { + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + for (auto panel : m_Panels) + { + panel->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + } + } +}; + +void QmitkNodeSelectionDialog::SetCurrentSelection(NodeList selectedNodes) +{ + m_SelectedNodes = selectedNodes; + for (auto panel : m_Panels) + { + panel->SetCurrentSelection(selectedNodes); + } +}; + +void QmitkNodeSelectionDialog::OnSelectionChanged(NodeList selectedNodes) +{ + SetCurrentSelection(selectedNodes); + emit CurrentSelectionChanged(selectedNodes); +}; + +void QmitkNodeSelectionDialog::AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc) +{ + view->setParent(this); + view->SetSelectionMode(m_SelectionMode); + + auto tabPanel = new QWidget(); + tabPanel->setObjectName(QString("tab_")+name); + tabPanel->setToolTip(desc); + m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); + + auto verticalLayout = new QVBoxLayout(tabPanel); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(view); + + m_Panels.push_back(view); + connect(view, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); +}; + +void QmitkNodeSelectionDialog::OnOK() +{ + this->accept(); +}; + +void QmitkNodeSelectionDialog::OnCancel() +{ + this->reject(); +}; + +void QmitkNodeSelectionDialog::SetSelectionMode(SelectionMode mode) +{ + m_SelectionMode = mode; + for (auto panel : m_Panels) + { + panel->SetSelectionMode(mode); + } +}; + +QmitkNodeSelectionDialog::SelectionMode QmitkNodeSelectionDialog::GetSelectionMode() const +{ + return m_SelectionMode; +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h new file mode 100644 index 0000000000..02f828bcc5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h @@ -0,0 +1,127 @@ +/*=================================================================== + +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 QMITK_NODE_SELECTION_DIALOG_H +#define QMITK_NODE_SELECTION_DIALOG_H + + +#include +#include +#include + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkNodeSelectionDialog.h" + +#include + +/** +* \class QmitkNodeSelectionDialog +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkNodeSelectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionDialog(QWidget* parent = nullptr, QString caption = "", QString hint = ""); + + /* + * @brief Sets the data storage that will be used /monitored by widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /* + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + NodeList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + void SetSelectionMode(SelectionMode mode); + SelectionMode GetSelectionMode() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + void OnOK(); + void OnCancel(); + +protected: + void AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + bool m_SelectOnlyVisibleNodes; + NodeList m_SelectedNodes; + + SelectionMode m_SelectionMode; + + using PanelVectorType = std::vector; + PanelVectorType m_Panels; + + Ui_QmitkNodeSelectionDialog m_Controls; +}; +#endif // QmitkNodeSelectionDialog_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui new file mode 100644 index 0000000000..190293767e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui @@ -0,0 +1,82 @@ + + + QmitkNodeSelectionDialog + + + + 0 + 0 + 596 + 539 + + + + Dialog + + + true + + + true + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 6 + + + 6 + + + + + QFrame::NoFrame + + + Info text ... + + + true + + + + + + + + + -1 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp new file mode 100644 index 0000000000..1e739cc705 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp @@ -0,0 +1,123 @@ +/*=================================================================== + +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 "QmitkNodeSelectionPreferenceHelper.h" + +#include + +#include + +#include +#include +#include + + +#include "mitkExceptionMacro.h" + +void mitk::PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType &inspectors) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + visNode->RemoveNode(); + prefNode->Flush(); + + // new empty preset node + visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + // store map in new node + for (const auto &inspector : inspectors) + { + std::ostringstream sstr; + sstr << inspector.first; + berry::IPreferences::Pointer aNode = visNode->Node(QString::fromStdString(sstr.str())); + + aNode->Put(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), inspector.second.c_str()); + aNode->Flush(); + } + + visNode->Flush(); +} + +mitk::VisibleDataStorageInspectorMapType mitk::GetVisibleDataStorageInspectors() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + typedef QStringList NamesType; + NamesType names = visNode->ChildrenNames(); + + VisibleDataStorageInspectorMapType visMap; + + if (!names.empty()) + { + for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) + { + berry::IPreferences::Pointer aNode = visNode->Node(*pos); + + if (aNode.IsNull()) + { + mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " + << (*pos).toStdString(); + } + + std::istringstream isstr(pos->toStdString()); + unsigned int order = 0; + isstr >> order; + + auto id = aNode->Get(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), ""); + if (id.isEmpty()) + { + mitkThrow() << "Error in preference interface. ID of visible inspector is not set. Inspector position: " + << order; + } + + visMap.insert(std::make_pair(order, id.toStdString())); + } + } + return visMap; +} + +mitk::DataStorageInspectorIDType mitk::GetFavoriteDataStorageInspector() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + auto id = prefNode->Get(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), ""); + + mitk::DataStorageInspectorIDType result = id.toStdString(); + return result; +} + +void mitk::PutFavoriteDataStorageInspector(const DataStorageInspectorIDType &id) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + prefNode->Put(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), id.c_str()); + prefNode->Flush(); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h new file mode 100644 index 0000000000..09bc4a719c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h @@ -0,0 +1,44 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H +#define __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H + +#include +#include + +namespace mitk +{ + using DataStorageInspectorIDType = std::string; + + using VisibleDataStorageInspectorMapType = std::map; + + /** Stores the given ID as favorite inspector.*/ + void PutFavoriteDataStorageInspector(const DataStorageInspectorIDType& id); + + /** Gets the ID of the current favorite data storage inspector. + * If empty string is returned, no favorite is set.*/ + DataStorageInspectorIDType GetFavoriteDataStorageInspector(); + + /** Stores the given map of visible inspectors.*/ + void PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType& inspectors); + + /** Gets the map of current visible inspectors.*/ + VisibleDataStorageInspectorMapType GetVisibleDataStorageInspectors(); +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp new file mode 100644 index 0000000000..10a89c0be3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp @@ -0,0 +1,130 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkSelectionServiceConnector.h" +#include "internal/QmitkDataNodeSelection.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +// blueberry ui qt plugin +#include + +QmitkSelectionServiceConnector::QmitkSelectionServiceConnector() + : m_SelectionService(nullptr) + , m_SelectionProvider(nullptr) +{ + m_DataNodeItemModel = std::make_shared(); + m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); +} + +QmitkSelectionServiceConnector::~QmitkSelectionServiceConnector() +{ + RemovePostSelectionListener(); + RemoveAsSelectionProvider(); +} + +void QmitkSelectionServiceConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) +{ + if (nullptr == selectionService) + { + return; + } + + m_SelectionService = selectionService; + m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkSelectionServiceConnector::OnServiceSelectionChanged)); + m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); +} + +void QmitkSelectionServiceConnector::RemovePostSelectionListener() +{ + if (nullptr == m_SelectionService) + { + return; + } + + m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); + m_SelectionService = nullptr; +} + +void QmitkSelectionServiceConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) +{ + m_SelectionProvider = selectionProvider; +} + +void QmitkSelectionServiceConnector::RemoveAsSelectionProvider() +{ + m_SelectionProvider = nullptr; +} + +void QmitkSelectionServiceConnector::ChangeServiceSelection(QList nodes) +{ + if (nullptr == m_SelectionProvider) + { + return; + } + + m_SelectionProvider->SetItemSelectionModel(m_DataNodeSelectionModel.get()); + + if (nodes.empty()) + { + m_DataNodeSelectionModel->clearSelection(); + m_DataNodeItemModel->clear(); + } + else + { + m_DataNodeItemModel->clear(); + // fill the temporary helper data node item model with the nodes to select + for (const auto& node : nodes) + { + m_DataNodeItemModel->AddDataNode(node); + } + + m_DataNodeSelectionModel->select(QItemSelection(m_DataNodeItemModel->index(0, 0), m_DataNodeItemModel->index(nodes.size() - 1, 0)), QItemSelectionModel::ClearAndSelect); + } +} + +void QmitkSelectionServiceConnector::OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection) +{ + if (sourcePart.IsNull()) + { + return; + } + + QList nodes; + if (selection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + + // transform valid selection to DataNodeSelection, which allows to retrieve the selected nodes + mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast(); + if (dataNodeSelection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + else + { + nodes = QList::fromStdList(dataNodeSelection->GetSelectedDataNodes()); + } + + // send new (possibly empty) list of selected nodes + emit ServiceSelectionChanged(nodes); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h new file mode 100644 index 0000000000..21c1f8f7f1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h @@ -0,0 +1,133 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKSELECTIONSERVICECONNECTOR_H +#define QMITKSELECTIONSERVICECONNECTOR_H + +#include + +// qt widgets module +#include + +// mitk gui qt common plugin +#include "QmitkDataNodeSelectionProvider.h" +#include "internal/QmitkDataNodeItemModel.h" + + // blueberry ui qt plugin +#include + +/* +* @brief The 'QmitkSelectionServiceConnector' is used to handle the selections of the global selection bus (selection service). +* +* The selection service connector can listen to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The selection service connector can provide selections. This should be done by using 'SetAsSelectionProvider' +* with the existing selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkSelectionServiceConnector' offers a public slot and signal that can be used to propagate the selected +* nodes from or to the global selection bus: +* The 'ChangeServiceSelection'-slot transforms the given list of selected nodes into a QItemSelection of a temporary +* data node selection model. This data node selection model is set as the item selection model of the member selection provider. +* So by temporary adding a new data node selection model and changing its selection the selection provider sends a new selection +* that can be received at any place in the workbench. +* +* The 'ServiceSelectionChanged'-signal sends a list of selected nodes to it's local environment (e.g. containing widget). +* The 'ServiceSelectionChanged'-signal is emitted by the 'ServiceSelectionChanged'-function, which transforms the +* berry selection of the selection into a data node list. The 'ServiceSelectionChanged'-function is called whenever +* the selection service sends a selection changed event. +* +* In order to connect the 'QmitkSelectionServiceConnector' with a model-view pair, a 'QmitkModelViewSelectionConnector' needs to be used: +* The 'QmitkModelViewSelectionConnector' offers a 'SetCurrentSelection'-slot that can be connected with the +* 'ServiceSelectionChanged'-signal of this class. +* The 'QmitkModelViewSelectionConnector' offers a 'CurrentSelectionChanged'-signal that can be connected with the +* 'ChangeServiceSelection'-slot of this class. +*/ +class MITK_QT_COMMON QmitkSelectionServiceConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkSelectionServiceConnector(); + ~QmitkSelectionServiceConnector(); + + /* + * @brief Create a selection listener and add it to the list of selection listener of the given selection service. + * + * The selection listener is connected to the 'ServiceSelectionChanged' member function, which is + * called if a berry selection is changed in the workbench. + */ + void AddPostSelectionListener(berry::ISelectionService* selectionService); + /* + * @brief Remove a selection listener from the list of selection listener of the selection service member. + */ + void RemovePostSelectionListener(); + /* + * @brief Store the given selection provider as a private member. + * In order to use the public slot 'ChangeServiceSelection'-function, the selection provider member had to be + * previously set. + */ + void SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider); + /* + * @brief Set the selection provider member to a nullptr. This will prevent the public slot + * 'ChangeServiceSelection'-function from working. + */ + void RemoveAsSelectionProvider(); + +Q_SIGNALS: + /* + * @brief A signal that will be emitted by the private 'ServiceSelectionChanged'-function. This happens if a selection is changed + * via the selection service. + * + * @par nodes A list of data nodes that are newly selected. + */ + void ServiceSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Send new selections to the selection service via the private selection provider member. + * + * This slot-function is called whenever a local selection is changed in the surrounding widget and a selection provider was set. + * The newly selected data nodes are added temporary to a 'QmitkDataNodeItemModel', which is then used to define + * the indices to select. + * The 'QItemSelectionModel' is set as the item selection model of the selection provider member and its items are + * selected by the indices previously defined by the 'QmitkDataNodeItemModel'. + */ + void ChangeServiceSelection(QList nodes); + +private: + + std::unique_ptr m_BerrySelectionListener; + berry::ISelectionService* m_SelectionService; + QmitkDataNodeSelectionProvider* m_SelectionProvider; + std::shared_ptr m_DataNodeItemModel; + std::shared_ptr m_DataNodeSelectionModel; + + /* + * @brief Handle a selection received from the selection service. + * + * This function is called whenever a berry selection of the selection service is changed in the workbench. + * The new selection is transformed into a data node selection and the contained data nodes are propagated + * as the new current selection of the item view member. + * + * @par sourcePart The workbench part containing the selection. + * @par selection The current selection. + */ + void OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection); + +}; + +#endif // QMITKSELECTIONSERVICECONNECTOR_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp new file mode 100644 index 0000000000..7bfe3d420c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp @@ -0,0 +1,212 @@ +/*=================================================================== + +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 "QmitkSingleNodeSelectionWidget.h" + +#include +#include + +#include "QPainter" +#include "QTextDocument" + +QmitkSingleNodeSelectionWidget::QmitkSingleNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + m_Controls.btnSelect->installEventFilter(this); + m_Controls.btnSelect->setVisible(true); + m_Controls.btnClear->setVisible(false); + + this->UpdateInfo(); + + connect(m_Controls.btnClear, SIGNAL(clicked(bool)), this, SLOT(OnClearSelection())); +} + +QmitkSingleNodeSelectionWidget::~QmitkSingleNodeSelectionWidget() +{ +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::ExtractCurrentValidSelection(const NodeList& nodes) const +{ + mitk::DataNode::Pointer result = nullptr; + + for (auto node : nodes) + { + bool valid = true; + if (m_NodePredicate.IsNotNull()) + { + valid = m_NodePredicate->CheckNode(node); + } + if (valid) + { + result = node; + break; + } + } + + return result; +} + +QmitkSingleNodeSelectionWidget::NodeList QmitkSingleNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + if (!m_SelectOnlyVisibleNodes) + { + result = m_ExternalSelection; + } + + if (m_SelectedNode.IsNotNull() && !result.contains(m_SelectedNode)) + { + result.append(m_SelectedNode); + } + + return result; +} + +void QmitkSingleNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + m_SelectedNode = this->ExtractCurrentValidSelection(m_ExternalSelection); +}; + +void QmitkSingleNodeSelectionWidget::OnClearSelection() +{ + if (m_IsOptional) + { + NodeList emptyList; + this->SetCurrentSelection(emptyList); + } + + this->UpdateInfo(); +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::GetSelectedNode() const +{ + return m_SelectedNode; +}; + +bool QmitkSingleNodeSelectionWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_Controls.btnSelect) + { + if (ev->type() == QEvent::MouseButtonRelease) + { + this->EditSelection(); + return true; + } + } + + return false; +} + +void QmitkSingleNodeSelectionWidget::EditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + NodeList list; + if (m_SelectedNode.IsNotNull()) + { + list.append(m_SelectedNode); + } + dialog->SetCurrentSelection(list); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::SingleSelection); + + m_Controls.btnSelect->setChecked(true); + + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + auto nodes = dialog->GetSelectedNodes(); + if (nodes.empty()) + { + m_SelectedNode = nullptr; + } + else + { + m_SelectedNode = nodes.first(); + } + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } + } + + m_Controls.btnSelect->setChecked(false); + + delete dialog; +}; + +void QmitkSingleNodeSelectionWidget::UpdateInfo() +{ + if (m_SelectedNode.IsNull()) + { + if (m_IsOptional) + { + m_Controls.btnSelect->SetNodeInfo(m_EmptyInfo); + } + else + { + m_Controls.btnSelect->SetNodeInfo(m_InvalidInfo); + } + m_Controls.btnClear->setVisible(false); + } + else + { + m_Controls.btnClear->setVisible(m_IsOptional); + } + + m_Controls.btnSelect->SetSelectedNode(m_SelectedNode); +}; + +void QmitkSingleNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; + +void QmitkSingleNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_ExternalSelection = selectedNodes; + m_SelectedNode = this->ExtractCurrentValidSelection(selectedNodes); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h new file mode 100644 index 0000000000..9fbe2c040d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h @@ -0,0 +1,84 @@ +/*=================================================================== + +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 QMITK_SINGLE_NODE_SELECTION_WIDGET_H +#define QMITK_SINGLE_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkSingleNodeSelectionWidget.h" + +#include +#include + +class QmitkAbstractDataStorageModel; + +/** +* \class QmitkSingleNodeSelectionWidget +* \brief Widget that that represents a node selection. It acts like a button. Clicking on it +* allows to change the selection. +*/ +class MITK_QT_COMMON QmitkSingleNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkSingleNodeSelectionWidget(QWidget* parent = nullptr); + ~QmitkSingleNodeSelectionWidget(); + + mitk::DataNode::Pointer GetSelectedNode() const; + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + +protected Q_SLOTS: + virtual void OnClearSelection(); + +protected: + mitk::DataNode::Pointer ExtractCurrentValidSelection(const NodeList& nodes) const; + NodeList CompileEmitSelection() const; + + virtual bool eventFilter(QObject *obj, QEvent *ev) override; + void EditSelection(); + virtual void UpdateInfo() override; + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_ExternalSelection; + mitk::DataNode::Pointer m_SelectedNode; + + Ui_QmitkSingleNodeSelectionWidget m_Controls; +}; + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui new file mode 100644 index 0000000000..7a13c0bbe2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui @@ -0,0 +1,121 @@ + + + QmitkSingleNodeSelectionWidget + + + + 0 + 0 + 348 + 25 + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 16777215 + 40 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 25 + 16777215 + + + + Press to remove the current selection. + + + + + + + :/org.mitk.gui.qt.common/resources/times.svg:/org.mitk.gui.qt.common/resources/times.svg + + + + 19 + 19 + + + + + + + + + QmitkNodeSelectionButton + QPushButton +
QmitkNodeSelectionButton.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp index 8116c685e3..188d1d6738 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp @@ -1,70 +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 "QmitkCommonActivator.h" #include #include +#include "QmitkNodeSelectionPreferencePage.h" QmitkCommonActivator* QmitkCommonActivator::m_Instance = nullptr; ctkPluginContext* QmitkCommonActivator::m_Context = nullptr; ctkPluginContext* QmitkCommonActivator::GetContext() { return m_Context; } QmitkCommonActivator* QmitkCommonActivator::GetInstance() { return m_Instance; } berry::IPreferencesService* QmitkCommonActivator::GetPreferencesService() { return m_PrefServiceTracker->getService(); } void QmitkCommonActivator::start(ctkPluginContext* context) { this->m_Instance = this; this->m_Context = context; this->m_PrefServiceTracker.reset(new ctkServiceTracker(context)); if(berry::PlatformUI::IsWorkbenchRunning()) { m_ViewCoordinator.reset(new QmitkViewCoordinator); m_ViewCoordinator->Start(); } else { MITK_ERROR << "BlueBerry Workbench not running!"; } + + BERRY_REGISTER_EXTENSION_CLASS(QmitkNodeSelectionPreferencePage, context) } void QmitkCommonActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_ViewCoordinator->Stop(); m_ViewCoordinator.reset(); this->m_PrefServiceTracker.reset(); this->m_Context = nullptr; this->m_Instance = nullptr; } diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp similarity index 55% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp index b332e9eca7..2f6a3ceaf1 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp @@ -1,32 +1,22 @@ /*=================================================================== 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include "QmitkNodeSelectionConstants.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) -{ - auto pixels = new unsigned long[100]; - void *data = pixels; - - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; - - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +const std::string mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID = "/NODESELECTION/UI"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID = "visibleInspectors"; +const std::string mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID = "inspectorID"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID = "inspectorID"; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h new file mode 100644 index 0000000000..170ec1840c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h @@ -0,0 +1,51 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _QMITK_NODE_SELECTION_CONSTANTS_H_ +#define _QMITK_NODE_SELECTION_CONSTANTS_H_ + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4251) +#endif + +namespace mitk +{ +struct MITK_QT_COMMON NodeSelectionConstants +{ + /** ID/Path of main preference node for node selections. */ + static const std::string ROOT_PREFERENCE_NODE_ID; + + /** ID of main preference node where all visible inspectors are stored (e.g. ROOT_PREFERENCE_NODE_ID+"/"+VISIBLE_INSPECTORS_NODE_ID+"/[orderering #]"). + The sub node naming encodes the ordering number of the visible inspector.*/ + static const std::string VISIBLE_INSPECTORS_NODE_ID; + /** ID for the value that stores the favorite inspector ID in the root preference node.*/ + static const std::string FAVORITE_INSPECTOR_ID; + /** ID for the value that stores the inspector ID in the preference node.*/ + static const std::string VISIBLE_INSPECTOR_ID; +}; + +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp new file mode 100644 index 0000000000..86fe16b1de --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp @@ -0,0 +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. + +===================================================================*/ + + +#include "QmitkNodeSelectionPreferencePage.h" + +#include "QmitkNodeSelectionPreferenceHelper.h" + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::QmitkNodeSelectionPreferencePage() + : m_MainControl(0), m_Controls(0) +{ + +} + + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::~QmitkNodeSelectionPreferencePage() +{ + delete m_Controls; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Init(berry::IWorkbench::Pointer ) +{ + +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::CreateQtControl(QWidget* parent) +{ + m_MainControl = new QWidget(parent); + m_Controls = new Ui::QmitkNodeSelectionPreferencePage; + m_Controls->setupUi( m_MainControl ); + + connect(m_Controls->comboFavorite, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateWidgets())); + connect(m_Controls->btnUp, SIGNAL(clicked(bool)), this, SLOT(MoveUp())); + connect(m_Controls->btnDown, SIGNAL(clicked(bool)), this, SLOT(MoveDown())); + connect(m_Controls->listInspectors, SIGNAL(itemSelectionChanged()), this, SLOT(UpdateWidgets())); + + this->Update(); +} + + +//----------------------------------------------------------------------------- +QWidget* QmitkNodeSelectionPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +//----------------------------------------------------------------------------- +bool QmitkNodeSelectionPreferencePage::PerformOk() +{ + //store favorite + auto id = m_Controls->comboFavorite->currentData().toString(); + mitk::PutFavoriteDataStorageInspector(id.toStdString()); + + //store visible + mitk::VisibleDataStorageInspectorMapType visibles; + + unsigned int visiblePos = 0; + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->checkState() == Qt::Checked) + { + visibles.insert(std::make_pair(visiblePos++, item->data(Qt::UserRole).toString().toStdString())); + } + } + mitk::PutVisibleDataStorageInspectors(visibles); + + return true; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::PerformCancel() +{ +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Update() +{ + m_Providers = QmitkDataStorageInspectorGenerator::GetProviders(); + + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto allProviders = QmitkDataStorageInspectorGenerator::GetProviders(); + auto favorite = mitk::GetFavoriteDataStorageInspector(); + + auto finding = m_Providers.find(favorite); + if (finding == m_Providers.cend()) + { + favorite = m_Providers.begin()->first; + } + + //fill favorite combo + int index = 0; + int currentIndex = 0; + m_Controls->comboFavorite->clear(); + for (auto iter : m_Providers) + { + m_Controls->comboFavorite->addItem(QString::fromStdString(iter.second->GetInspectorDisplayName()),QVariant::fromValue(QString::fromStdString(iter.first))); + if (iter.first == favorite) + { + currentIndex = index; + }; + ++index; + } + m_Controls->comboFavorite->setCurrentIndex(currentIndex); + + //fill inspector list + m_Controls->listInspectors->clear(); + for (const auto iter : allProviders) + { + auto currentID = iter.first; + QListWidgetItem* item = new QListWidgetItem; + item->setText(QString::fromStdString(iter.second->GetInspectorDisplayName())); + item->setData(Qt::UserRole, QVariant::fromValue(QString::fromStdString(currentID))); + item->setToolTip(QString::fromStdString(iter.second->GetInspectorDescription())); + + auto finding = std::find_if(visibleProviders.cbegin(), visibleProviders.cend(), [¤tID](auto v) {return v.second == currentID; }); + if (finding == visibleProviders.cend()) + { + item->setCheckState(Qt::Unchecked); + m_Controls->listInspectors->addItem(item); + } + else + { + item->setCheckState(Qt::Checked); + m_Controls->listInspectors->insertItem(finding->first, item); + } + } + + this->UpdateWidgets(); +} + +void QmitkNodeSelectionPreferencePage::UpdateWidgets() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + m_Controls->btnUp->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex > 0); + m_Controls->btnDown->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex + 1 < m_Controls->listInspectors->count()); + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->data(Qt::UserRole).toString() == m_Controls->comboFavorite->currentData().toString()) + { + //favorites are always visible. + item->setCheckState(Qt::Checked); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); + } + else + { + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable); + } + } +}; + +void QmitkNodeSelectionPreferencePage::MoveDown() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex+1 < m_Controls->listInspectors->count()) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex + 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex + 1); + } + this->UpdateWidgets(); +}; + +void QmitkNodeSelectionPreferencePage::MoveUp() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex > 0) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex - 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex - 1); + } + this->UpdateWidgets(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h new file mode 100644 index 0000000000..2e959c43c5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h @@ -0,0 +1,91 @@ +/*=================================================================== + +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 __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H +#define __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H + +#include "berryIQtPreferencePage.h" +#include "berryIPreferences.h" + +#include "QmitkDataStorageInspectorGenerator.h" + +#include "ui_QmitkNodeSelectionPreferencePage.h" + +class QWidget; + +/** +* \class QmitkNodeSelectionPreferencePage +* \brief Preference page for general node selection settings. +*/ +class QmitkNodeSelectionPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + QmitkNodeSelectionPreferencePage(); + ~QmitkNodeSelectionPreferencePage(); + + /** + * \brief Called by framework to initialize this preference page, but currently does nothing. + * \param workbench The workbench. + */ + void Init(berry::IWorkbench::Pointer workbench); + + /** + * \brief Called by framework to create the GUI, and connect signals and slots. + * \param widget The Qt widget that acts as parent to all GUI components, as this class itself is not derived from QWidget. + */ + void CreateQtControl(QWidget* widget); + + /** + * \brief Required by framework to get hold of the GUI. + * \return QWidget* the top most QWidget for the GUI. + */ + QWidget* GetQtControl() const; + + /** + * \see IPreferencePage::PerformOk + */ + virtual bool PerformOk(); + + /** + * \see IPreferencePage::PerformCancel + */ + virtual void PerformCancel(); + + /** + * \see IPreferencePage::Update + */ + virtual void Update(); + +protected slots: + + void UpdateWidgets(); + void MoveDown(); + void MoveUp(); + +protected: + + QWidget *m_MainControl; + Ui::QmitkNodeSelectionPreferencePage* m_Controls; + + QmitkDataStorageInspectorGenerator::ProviderMapType m_Providers; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui new file mode 100644 index 0000000000..c88f7330f2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui @@ -0,0 +1,145 @@ + + + QmitkNodeSelectionPreferencePage + + + + 0 + 0 + 715 + 713 + + + + Form + + + + + + + + Up + + + + + + + Down + + + + + + + + + Favorite inspector: + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>The favorite inspector is always visible.</p><p>Additionally the favorite inspector has always the focus when opening a node selection dialoge.</p></body></html> + + + + Neues Element + + + + + 2 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Instruction:</span><br/>Only checked inspectors will be shown in node selection dialogs.<br/>You may change the order in the inspector list, to change the order of the tabs in the node selection dialog.</p></body></html> + + + true + + + + + + + + + Inspector visiblitiy and order: + + + + + + + + 16777215 + 16777215 + + + + List of all available inspectors. Checked inspectores will be display + + + + TreeInspector + + + ffffff + + + Checked + + + + + List + + + Checked + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg b/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg index 0e4b601122..82a332cdab 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg +++ b/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg @@ -1,55 +1,55 @@ image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt new file mode 100644 index 0000000000..add23310bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_datastorageviewertest) + +mitk_create_plugin( + EXPORT_DIRECTIVE DATASTORAGEVIEWERTEST_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgets +) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake new file mode 100644 index 0000000000..7346b84a06 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake @@ -0,0 +1,32 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + mitkPluginActivator.cpp + QmitkDataStorageViewerTestView.cpp +) + +set(UI_FILES + src/internal/QmitkDataStorageViewerTestControls.ui +) + +set(MOC_H_FILES + src/internal/mitkPluginActivator.h + src/internal/QmitkDataStorageViewerTestView.h +) + +set(CACHED_RESOURCE_FILES + resources/DataStorageViewer_48.png + plugin.xml +) + +set(QRC_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.datastorageviewertest/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake new file mode 100644 index 0000000000..3189816295 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Data storage viewer test") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml new file mode 100644 index 0000000000..9b1f6fd52c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png new file mode 100644 index 0000000000..d297828a0d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png differ diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui new file mode 100644 index 0000000000..66866a9712 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui @@ -0,0 +1,158 @@ + + + QmitkDataStorageViewerTestControls + + + + 0 + 0 + 945 + 728 + + + + + 0 + 0 + + + + Data storage viewer test + + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection provider + + + + + + + Set as selection listener + + + + + + + Set as selection listener + + + + + + + + 0 + 40 + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ + QmitkMultiNodeSelectionWidget + QWidget +
QmitkMultiNodeSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp new file mode 100644 index 0000000000..dbe3bd1cc8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -0,0 +1,247 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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. + +===================================================================*/ + +// data storage viewer test plugin +#include "QmitkDataStorageViewerTestView.h" + +#include "mitkNodePredicateDataType.h" + +// berry +#include + +// qt +#include + +const std::string QmitkDataStorageViewerTestView::VIEW_ID = "org.mitk.views.datastorageviewertest"; + +void QmitkDataStorageViewerTestView::SetFocus() +{ + // nothing here +} + +void QmitkDataStorageViewerTestView::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets + m_Controls.setupUi(parent); + + m_DataStorageDefaultListModel = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView->setAlternatingRowColors(true); + m_Controls.selectionListView->setModel(m_DataStorageDefaultListModel); + + m_DataStorageDefaultListModel2 = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel2->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView2->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView2->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView2->setAlternatingRowColors(true); + m_Controls.selectionListView2->setModel(m_DataStorageDefaultListModel2); + + m_Controls.singleSlot->SetDataStorage(GetDataStorage()); + m_Controls.singleSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.singleSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.singleSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.singleSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_Controls.multiSlot->SetDataStorage(GetDataStorage()); + m_Controls.multiSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.multiSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.multiSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.multiSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_ModelViewSelectionConnector = std::make_unique(); + try + { + m_ModelViewSelectionConnector->SetView(m_Controls.selectionListView); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector = std::make_unique(); + + m_ModelViewSelectionConnector2 = std::make_unique(); + try + { + m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector2 = std::make_unique(); + + m_SelectionServiceConnector3 = std::make_unique(); + m_SelectionServiceConnector4 = std::make_unique(); + + connect(m_Controls.selectionProviderCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider1(bool))); + connect(m_Controls.selectionProviderCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider2(bool))); + + connect(m_Controls.selectionListenerCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener1(bool))); + connect(m_Controls.selectionListenerCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener2(bool))); + + connect(m_Controls.selectionProviderCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider3(bool))); + connect(m_Controls.selectionListenerCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener3(bool))); + + connect(m_Controls.checkOnlyVisible, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages(bool))); + + connect(m_Controls.selectionProviderCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider4(bool))); + connect(m_Controls.selectionListenerCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener4(bool))); + + connect(m_Controls.checkOnlyVisible_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages_2, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages2(bool))); +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector3->RemoveAsSelectionProvider(); + disconnect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector3->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector4->RemoveAsSelectionProvider(); + disconnect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector4->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::OnOnlyImages(bool checked) +{ + if (checked) + { + m_Controls.singleSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.singleSlot->SetNodePredicate(nullptr); + } +}; + +void QmitkDataStorageViewerTestView::OnOnlyImages2(bool checked) +{ + if (checked) + { + m_Controls.multiSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.multiSlot->SetNodePredicate(nullptr); + } +}; diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h new file mode 100644 index 0000000000..ce4042ae3e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h @@ -0,0 +1,77 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGEVIEWERTESTVIEW_H +#define QMITKDATASTORAGEVIEWERTESTVIEW_H + +// mitk gui qt common plugin +#include +#include "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" + +// data storage viewer test plugin +#include "ui_QmitkDataStorageViewerTestControls.h" + +// qt widgets module +#include "QmitkDataStorageDefaultListModel.h" + +/** +* @brief DataStorageViewerTestView +*/ +class QmitkDataStorageViewerTestView : public QmitkAbstractView +{ + Q_OBJECT + +public: + + static const std::string VIEW_ID; + +protected: + + virtual void SetFocus() override; + + virtual void CreateQtPartControl(QWidget* parent) override; + +private Q_SLOTS: + + void SetAsSelectionProvider1(bool checked); + void SetAsSelectionProvider2(bool checked); + void SetAsSelectionProvider3(bool checked); + void SetAsSelectionProvider4(bool checked); + void SetAsSelectionListener1(bool checked); + void SetAsSelectionListener2(bool checked); + void SetAsSelectionListener3(bool checked); + void SetAsSelectionListener4(bool checked); + + void OnOnlyImages(bool checked); + void OnOnlyImages2(bool checked); + +private: + + Ui::QmitkDataStorageViewerTestControls m_Controls; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel2; + + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; + std::unique_ptr m_ModelViewSelectionConnector2; + std::unique_ptr m_SelectionServiceConnector2; + + std::unique_ptr m_SelectionServiceConnector3; + std::unique_ptr m_SelectionServiceConnector4; +}; + +#endif // QMITKDATASTORAGEVIEWERTESTVIEW_H diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp similarity index 50% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp index b332e9eca7..deb5df0dc0 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp @@ -1,32 +1,28 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. +Division of Medical Image Computing. 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include "mitkPluginActivator.h" +#include "QmitkDataStorageViewerTestView.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +namespace mitk { - auto pixels = new unsigned long[100]; - void *data = pixels; + void DataStorageViewerTestActivator::start(ctkPluginContext *context) + { + BERRY_REGISTER_EXTENSION_CLASS(QmitkDataStorageViewerTestView, context) + } - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; - - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; + void DataStorageViewerTestActivator::stop(ctkPluginContext *context) { Q_UNUSED(context) } } diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h new file mode 100644 index 0000000000..080450ba33 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h @@ -0,0 +1,37 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 MITKPLUGINACTIVATOR_H +#define MITKPLUGINACTIVATOR_H + +#include + +namespace mitk +{ + class DataStorageViewerTestActivator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_datastorageviewertest") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + + }; +} + +#endif // MITKPLUGINACTIVATOR_H diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui index 575ec4f153..e7196a043c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui @@ -1,306 +1,299 @@ QmitkConnectomicsDataViewControls 0 0 286 639 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Input Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a parcellation and a tractogram! Image 1: - Image 2: - Network Creation Options 6 6 6 6 Create a network from a parcellation and a fiber image Networkify Create Correlation Matrix true Synthetic Network Options 6 6 6 6 Parameter 2 false 3 999.899999999999977 Parameter 1 false 9999 Create Synthetic Networks 0 0 Anatomical labeling 6 6 6 6 Qt::Vertical 20 40 QmitkFreeSurferParcellationWidget QWidget

QmitkFreeSurferParcellationWidget.h
1 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui index 5eba3ef537..50883169d6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui @@ -1,313 +1,306 @@ QmitkConnectomicsNetworkOperationsViewControls 0 0 283 639 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a network or a parcellation! Image 1: - Convert the selected image to RGBA format Turn Into RGBA Image Assign FreeSurfer Colors Divide in Modules Connectivity Matrix Image Options 6 6 6 6 Create Connectivity Matrix Image Rescale Binary Prune Options 6 6 6 6 Prune Network Target Density 1.000000000000000 0.010000000000000 Target Threshold Threshold weight Threshold Below Density Random Removal Threshold Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui index 7e3b0384ed..1610d78f61 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui @@ -1,324 +1,317 @@ QmitkConnectomicsStatisticsViewControls 0 0 557 1218 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Input Data 6 6 6 6 Network: Network Statistics 6 6 6 6 true 0 0 true Informational Balloons. 6 6 6 6 false PointingHandCursor Qt::RightToLeft true false false -1 12 QComboBox::InsertAlphabetically 0 0 MS Shell Dlg 2 8 IBeamCursor false true Histograms 6 6 6 6 0 0 50 150 50 150 50 150 Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkNetworkHistogramCanvas QWidget
internal/QmitkNetworkHistogramCanvas.h
1
networkBalloonsNodeLabelsComboBox currentIndexChanged(int) networkBalloonsNodeLabelsComboBox setCurrentIndex(int) 360 409 360 409
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui index 832419054d..0078a5b273 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui @@ -1,350 +1,343 @@ QmitkRandomParcellationViewControls true 0 0 327 591 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 QLabel { color: rgb(255, 0, 0) } Please select an image! true Nodes false 6 6 6 6 true Choose the number of nodes: 2 5000 true Merging 6 6 6 6 Merging on false QFrame::NoFrame QFrame::Raised 0 0 0 0 According to the number of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Number of Parcels: 1 5000 According to the size of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Size of the smallest parcel: 2 100000 Just merge small parcels false Do image processing Select random nodes Qt::Vertical 20 40 Counting 6 6 6 6 Number of voxels with value 1: Number of nodes: \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui index bfb9603eb8..7f732f0e06 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui @@ -1,382 +1,375 @@ QmitkDenoisingViewControls 0 0 351 734 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: Total-variation Discrete Gaussian Non-local means Filter: Parameters 6 6 6 6 Lambda: 4 0.000000000000000 1.000000000000000 0.100000000000000 0.100000000000000 Iterations: 1 999 1 Parameters 6 6 6 6 Sampling Radius: 1 999 10 1 999 4 1 999 4 Num. Patches: 1 50 1 Iterations: Patch Size: Parameters 6 6 6 6 4 1.000000000000000 99999.000000000000000 0.100000000000000 1.000000000000000 Variance: Start Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui index d00a61791e..9228e80e1e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui @@ -1,3615 +1,3608 @@ QmitkFiberfoxViewControls 0 0 463 875 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } Load Parameters :/QmitkDiffusionImaging/general_icons/upload.ico :/QmitkDiffusionImaging/general_icons/upload.ico Save Parameters :/QmitkDiffusionImaging/general_icons/download.ico :/QmitkDiffusionImaging/general_icons/download.ico Signal Generation 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true <html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html> Start Simulation :/QmitkDiffusionImaging/general_icons/right.ico :/QmitkDiffusionImaging/general_icons/right.ico Input Data 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 - ... <html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html> QComboBox::AdjustToMinimumContentsLength Fiber Bundle: false Save path: false Tissue Mask: false <html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html> QComboBox::AdjustToMinimumContentsLength Template Image: false <html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html> QComboBox::AdjustToMinimumContentsLength true Stop current simulation. Abort Simulation :/QmitkDiffusionImaging/general_icons/abort.ico :/QmitkDiffusionImaging/general_icons/abort.ico Courier 7 true Extra-axonal Compartments 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Select signal model for extra-axonal compartment. Ball Model Astrosticks Model Dot Model Prototype Signal Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. Select signal model for extra-axonal compartment. -- Ball Model Astrosticks Model Dot Model Prototype Signal Intra-axonal Compartment 6 6 6 6 Select signal model for intra-axonal compartment. Stick Model Zeppelin Model Tensor Model Prototype Signal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. Image Settings 6 6 6 6 Advanced Options QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 30 <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> false b-value in s/mm² 0 10000 100 1000 color: rgb(255, 0, 0); Using geometry of selected image! color: rgb(255, 0, 0); Using gradients of selected DWI! QFrame::NoFrame QFrame::Raised 0 0 0 0 6 <html><head/><body><p>Number of Channels:</p></body></html> false TR in milliseconds 1 999999999 1 4000 Output one image per compartment containing the corresponding volume fractions per voxel. Reverse Phase Encoding Direction false Signal Scale: Dwell time (time to read one line in k-space) in ms. 100.000000000000000 0.100000000000000 1.000000000000000 TE in milliseconds 1 999999999 1 100 Fiber Radius: Partial Fourier: false Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present. Disable Partial Volume Effects false <html><head/><body><p>Coil Sensitivity:</p></body></html> false Partial fourier factor (0.5-1) 3 0.500000000000000 1.000000000000000 0.100000000000000 1.000000000000000 Output phase image and volume fraction maps. Output Additional Images false Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). 1 10000 1 50 <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> false Constant Linear Exponential Dwell Time: false <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> false <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> Simulate Signal Relaxation true <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> false TE in milliseconds 1 10000 1 100 Number of coil elements used for the acquisiton. 1 128 1 1 Acquisition Type: Single Shot EPI Spin Echo Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. 9999.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 3 Inter-axonal Compartment 6 6 6 6 Select signal model for intra-axonal compartment. -- Stick Model Zeppelin Model Tensor Model QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. Noise and other Artifacts 6 6 6 6 Add Distortions false Add Spikes false true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 0 0 0 Gradient: false Eddy current induced magnetic field gradient (in mT/m). 4 1000.000000000000000 0.001000000000000 0.010000000000000 Add Motion Artifacts false Qt::Horizontal true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 K-Space Line Offset: false A larger offset increases the inensity of the ghost image. 3 1.000000000000000 0.010000000000000 0.250000000000000 Add Noise false QFrame::NoFrame QFrame::Raised 0 0 0 0 Num. Spikes: The number of randomly occurring signal spikes. 1 Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice. 0.100000000000000 0.100000000000000 Scale: true QFrame::NoFrame QFrame::Raised 0 6 0 0 6 Toggle between random movement and linear movement. Randomize motion true Rotation 6 9 6 6 Degree: false x false Axis: false Maximum rotation around x-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 Maximum rotation around z-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 15.000000000000000 y false z false Maximum rotation around y-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 Translation 6 6 6 Distance: false x false y false Axis: false z false Maximum translation along x-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along y-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along z-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Motion volumes: Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes. random Add ringing artifacts occuring at strong edges in the image. Add Gibbs Ringing false Qt::Horizontal Qt::Horizontal Qt::Horizontal Qt::Horizontal Add N/2 Ghosts false Add Aliasing false Qt::Horizontal Qt::Horizontal Add Eddy Current Effects false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 Shrink FOV (%): false Shrink FOV by this percentage. 1 0.000000000000000 90.000000000000000 0.100000000000000 25.000000000000000 true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 Frequency Map: false Select image specifying the frequency inhomogeneities (in Hz). QFrame::NoFrame QFrame::Raised 0 0 0 0 Variance: Variance of selected noise distribution. 10 0.000000000000000 999999999.000000000000000 0.001000000000000 50.000000000000000 Distribution: Noise distribution Complex Gaussian Rician Fiber Definition 25 Qt::Vertical 20 40 color: rgb(255, 0, 0); Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true Fiducial Options 6 6 6 6 All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. Align With Grid :/QmitkDiffusionImaging/general_icons/right.ico :/QmitkDiffusionImaging/general_icons/right.ico Operations 6 6 6 6 false Join Bundles :/QmitkDiffusionImaging/general_icons/plus.ico :/QmitkDiffusionImaging/general_icons/plus.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Y false Rotation angle (in degree) around x-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Axis: false Rotation angle (in degree) around y-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation: false Translation (in mm) in direction of the z-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 X false Rotation: false Z false Rotation angle (in degree) around z-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false Copy Bundles :/QmitkDiffusionImaging/general_icons/copy2.ico :/QmitkDiffusionImaging/general_icons/copy2.ico false Transform Selection :/QmitkDiffusionImaging/general_icons/refresh.ico :/QmitkDiffusionImaging/general_icons/refresh.ico If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true Fiber Options 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Tension: false Fiber Sampling: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Bias: false Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Distance of fiber sampling points (in mm) 1 0.100000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false Generate Fibers :/QmitkDiffusionImaging/general_icons/right.ico :/QmitkDiffusionImaging/general_icons/right.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Select fiber distribution inside of the fiducials. Uniform Gaussian Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 0 0 0 false 30 30 Draw elliptical fiducial. :/QmitkDiffusionImaging/circle.png :/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. :/QmitkDiffusionImaging/general_icons/refresh.ico :/QmitkDiffusionImaging/general_icons/refresh.ico 32 32 false true Qt::Horizontal 40 20 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkTensorModelParametersWidget QWidget
QmitkTensorModelParametersWidget.h
1
QmitkStickModelParametersWidget QWidget
QmitkStickModelParametersWidget.h
1
QmitkZeppelinModelParametersWidget QWidget
QmitkZeppelinModelParametersWidget.h
1
QmitkBallModelParametersWidget QWidget
QmitkBallModelParametersWidget.h
1
QmitkAstrosticksModelParametersWidget QWidget
QmitkAstrosticksModelParametersWidget.h
1
QmitkDotModelParametersWidget QWidget
QmitkDotModelParametersWidget.h
1
QmitkPrototypeSignalParametersWidget QWidget
QmitkPrototypeSignalParametersWidget.h
1
m_CircleButton m_FlipButton m_RealTimeFibers m_AdvancedOptionsBox m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_FiberBundleComboBox m_MaskComboBox m_TemplateComboBox m_SavePathEdit m_OutputPathButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_AdvancedOptionsBox_2 m_SignalScaleBox m_TEbox m_TRbox m_LineReadoutTimeBox m_PartialFourier m_T2starBox m_FiberRadius m_ReversePhaseBox m_RelaxationBox m_EnforcePureFiberVoxelsBox m_VolumeFractionsBox m_Compartment1Box m_Comp1VolumeFraction m_Compartment2Box m_Comp2VolumeFraction m_Compartment3Box m_Comp3VolumeFraction m_Compartment4Box m_Comp4VolumeFraction m_AddNoise m_NoiseDistributionBox m_NoiseLevel m_AddSpikes m_SpikeNumBox m_SpikeScaleBox m_AddGhosts m_kOffsetBox m_AddAliasing m_WrapBox m_AddDistortions m_FrequencyMapBox m_AddMotion m_RandomMotion m_MaxRotationBoxX m_MaxRotationBoxY m_MaxRotationBoxZ m_MaxTranslationBoxX m_MaxTranslationBoxY m_MaxTranslationBoxZ m_AddEddy m_EddyGradientStrength m_AddGibbsRinging m_SaveParametersButton m_LoadParametersButton toolBox
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui index b0d6ed02b3..58600b9fab 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui @@ -1,414 +1,407 @@ QmitkFieldmapGeneratorViewControls 0 0 358 536 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Place Field Source QFrame::NoFrame QFrame::Raised 0 0 0 0 World Coordinates: - Index: - Generate Fieldmap Please Select Reference Image 6 6 6 6 Add Gradient 6 6 6 6 Gradient x: z: 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 y: 4 -1000.000000000000000 1000.000000000000000 Offset 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 Qt::Vertical QSizePolicy::Expanding 20 220 Edit Selected Source 6 6 6 6 Name: Height: Variance: - 999999.000000000000000 999999.000000000000000 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui index 142f9b6f4b..83c5746932 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui @@ -1,552 +1,545 @@ QmitkFiberClusteringViewControls 0 0 474 683 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Qt::Vertical 20 40 Metrics 6 6 6 6 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean true Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean STDEV Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean Maximum Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Inner Angles Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Distance is based on the selected parcellation. Anatomical Distance is based on the selected parcellation. Weighting factor for metric values. 1 999.000000000000000 30.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Distance is based on the scalar map values along the tract. Scalar Map Distance is based on the scalar map values along the tract. Streamline Length Input Data 6 6 6 6 Input Centroids: If set, the input tractogram is clustered around the input centroids and no new clusters are created. false 0 0 200 16777215 11 Start Tractogram: Parameters Only output clusters with ate least the specified number of fibers. 1 9999999 50 Only output the N largest clusters. Zero means no limit. 99999999 10 Min. Fibers per Cluster: Max. Clusters: Fiber Points: Merge duplicate clusters withthe specified distance threshold. If threshold is < 0, the threshold is set to half of the specified cluster size. -1.000000000000000 99999.000000000000000 0.000000000000000 Cluster Size: Cluster size in mm. 1 9999999 20 Fibers are resampled to the desired number of points for clustering. Smaller is faster but less accurate. 2 9999999 12 Merge Duplicate Clusters: Output Centroids: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui index eada3d492a..1712aaae56 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui @@ -1,252 +1,245 @@ QmitkFiberFitViewControls 0 0 484 574 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 false Output Residuals: Weight for regularization. 999999.000000000000000 0.100000000000000 0.100000000000000 Tractogram: false 0 0 200 16777215 11 Start λ: Image: false Suppress Outliers: Regularization: Voxel-wise Variance Variance Mean Squared Magnitude Lasso None Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui index 9a8a405915..e155a9b83e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,1625 +1,1620 @@ - + QmitkFiberProcessingViewControls 0 0 385 684 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 9 9 9 9 0 5 0 0 353 441 Fiber Extraction Extract a fiber subset from the selected fiber bundle using manually placed planar figures as waypoints or binary regions of interest. false 0 0 200 16777215 11 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Interactive Extraction 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 30 30 Draw circular ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png + :/QmitkDiffusionImaging/circle.png +:/QmitkDiffusionImaging/circle.png 32 32 false true Qt::Horizontal 40 20 30 30 Draw polygonal ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png + :/QmitkDiffusionImaging/polygon.png +:/QmitkDiffusionImaging/polygon.png 32 32 true true 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 false 60 16777215 Create NOT composition from selected ROI. NOT false 60 16777215 Create OR composition with selected ROIs. OR Qt::Horizontal 40 20 false 60 16777215 Create AND composition with selected ROIs. AND false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. Generate ROI Image 0 0 Extract using planar figures Extract using ROI image QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. overlap: Extract fibers: Both ends true - Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". + Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". 3 1.000000000000000 0.100000000000000 0 0 Ending in ROI Not ending in ROI Passing ROI Not passing ROI Interpolate ROI true Threshold: Threshold on ROI image for positions to be considered as positive. 3 9999.000000000000000 0.100000000000000 0.500000000000000 0 0 367 408 Fiber Removal Remove fibers that satisfy certain criteria from the selected bundle. QFrame::NoFrame QFrame::Raised 0 0 0 0 If unchecked, the fiber exceeding the threshold will be split in two instead of removed. Remove Fiber false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Max. Angular Deviation: Qt::Horizontal 40 20 Maximum angular deviation in degree 180.000000000000000 0.100000000000000 30.000000000000000 Distance: Distance in mm 1 999.000000000000000 1.000000000000000 10.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 X: Y: - + - + Z: - + Angle: Angular deviation threshold in degree 1 90.000000000000000 1.000000000000000 25.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Qt::Horizontal 40 20 Minimum fiber length in mm 0 999999999 20 Max. Length: Min. Length: Maximum fiber length in mm 0 999999999 300 false 0 0 200 16777215 11 - + Remove Qt::Vertical 20 40 0 0 Remove fibers in direction Remove fibers by length Remove fibers by curvature Remove fiber parts outside mask Remove fiber parts inside mask Remove fibers by weight QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight threshold: Only fibers with weight larger than this threshold are kept. 5 99999.000000000000000 0.100000000000000 0 0 367 408 Bundle Modification Modify the selected bundle with operations such as fiber resampling, FA coloring, etc. QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Error threshold in mm: 999999999.000000000000000 0.100000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Sagittal Coronal Axial Select direction: QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 If checked, the image values are not only used to color the fibers but are also used as opaxity values. Values as opacity false - + Scalar map: The values used to color the fibers are min-max normalized. If not checked, the values should be between 0 and 1. Normalize values true 0 0 Resample fibers (spline) Resample fibers (linear) Compress fibers Color fibers by scalar map (e.g. FA) Mirror fibers Weight bundle Color fibers by curvature Color fibers by fiber weights Color fibers by length QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 0.010000000000000 999999999.000000000000000 0.100000000000000 1.000000000000000 Point distance in mm: Qt::Vertical 20 40 false 0 0 200 16777215 11 - + Execute QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight: 7 999999999.000000000000000 0.100000000000000 1.000000000000000 0 0 367 172 Bundle Operations Join, subtract or copy bundles. false 0 0 200 16777215 11 Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. Substract Qt::Vertical 20 40 false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Copy Please Select Input Data 6 6 6 6 - <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true - <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> + <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> true Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
- - + + - -
+ + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui index 68b0065306..bd45e43f55 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui @@ -1,448 +1,441 @@ QmitkFiberQuantificationViewControls 0 0 365 581 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Fiber-derived images 6 6 6 6 false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image 0 0 Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset Principal Fiber Directions 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 Fiber directions with an angle smaller than the defined threshold are clustered. 2 0.000000000000000 90.000000000000000 1.000000000000000 30.000000000000000 0 0 <html><head/><body><p>Directions shorter than the defined threshold are discarded.</p></body></html> 3 1.000000000000000 0.100000000000000 0.300000000000000 Angular Threshold: Max. Peaks: Size Threshold: 0 0 Maximum number of fiber directions per voxel. 100 3 Normalization: 0 0 0 Global maximum Single vector Voxel-wise maximum 0 0 Image containing the number of distinct fiber clusters per voxel. Output #Directions per Voxel false false Generate Directions Input Data 6 6 6 6 Tractogram: Reference Image: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui index 0706ec6ad1..fe454057d0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui @@ -1,164 +1,157 @@ QmitkTractometryViewControls 0 0 484 574 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Input Image: 3 99999 100 Sampling Points: Qt::Vertical 20 40 0 100 Show STDEV true QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkChartWidget QWidget
QmitkChartWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui index 02febef950..b83e5d07d1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui @@ -1,1215 +1,1208 @@ QmitkIVIMViewControls 0 0 423 1563 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 9 9 9 9 9 Intra Voxel Incoherent Motion Estimation 6 9 6 6 Input Data 6 6 6 6 Optional ROI image ROI: DWI to analyze Raw DWI: QFrame::NoFrame QFrame::Raised 0 0 0 0 warning display Qt::RichText true 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 0 IVIM Parameters 9 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 D* 100 60 Qt::Horizontal 51 16777215 200 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 neglect b< 250 34 Qt::Horizontal 51 16777215 46.5 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 #iterations 100 10 Qt::Horizontal 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 lambda 1000 10 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Plain 0 0 0 0 0 80 16777215 neglect Si< 100 0 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Raised 0 0 0 0 80 0 Output Images f true D false D* false true 0 0 0 400 Choose Method 2 3 Param. Fit Fit D & f with fixed D* value Fit D & f (high b), then fit D* Linearly fit D & f (high b), then fit D* Regularized Kurtosis QFrame::StyledPanel QFrame::Raised 2 2 2 2 2 Smoothing sigma Select Fit Type Omit b=0 Measurement 80 0 Output Images Force the fitting of K to remain within the given boundaries Boundaries for K Select if the data is fitted directly (straight) or the logarithmic equation is used Straight Fit Logarithmic Fit 2 QLayout::SetMaximumSize D false K true Signa for gaussian smoothing applied prior to map computation 0.000000000000000 5.000000000000000 0.100000000000000 On 0 0 0 400 Generate Output Images QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Datapoints to Clipboard Parameters to Clipboard QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkIVIMWidget QWidget
QmitkIVIMWidget.h
1
QmitkKurtosisWidget QWidget
QmitkKurtosisWidget.h
1
ctkRangeWidget QWidget
ctkRangeWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui index 56cfad412f..dc363b8334 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,504 +1,497 @@ QmitkOdfMaximaExtractionViewControls 0 0 397 848 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Generate ODF image and MITK compatible SH coefficient from other toolkits. Start SH Coefficient Import true Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Peak Extraction Please Select Input Data 6 6 6 6 Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: Additional Output QFormLayout::AllNonFixedFieldsGrow 6 6 6 6 Output unsigned char image containing the number of directions per voxel. #Peaks per Voxel false Parameters 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Vector Normalization: <html><head/><body><p>The vector fields are always coorected for image spacing and using the lagest eigenvalue in case of the tensor peak extraction. This is done for visualizytion purposes. The output direction images are not affected.</p></body></html> 1 No Normalization MAX Normalize Single Vec Normalization true QFrame::NoFrame QFrame::Raised 0 0 0 0 6 true Max. Peaks: Relative Threshold: true Peak threshold relative to the largest peak per voxel. 3 0.000000000000000 1.000000000000000 0.100000000000000 0.500000000000000 true Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.010000000000000 0.030000000000000 true Maximum number of peaks to extract. 1 1000 3 Clustering Angle: Cluster close directions. Define "close" here. 90 30 Absolute Threshold: Angular Threshold: Discard smaller peaks in the defined angle around the maximum peaks that were too far away to be clustered. 0 90 0 Qt::Vertical 20 259 Spherical Harmonic Convention 6 6 6 6 Define SH coefficient convention (depends on toolkit) 0 MITK/MRtrix FSL QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui index 0cb2586b38..baec9ccaa4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui @@ -1,886 +1,879 @@ QmitkPartialVolumeAnalysisViewControls true 0 0 360 565 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 0 9 3 9 3 Data 0 0 Tensor/Scalar Image: 0 0 Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> Parameters QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 0 false QFrame::NoFrame QFrame::Raised 0 30 30 Draw circular ROI :/QmitkDiffusionImaging/circle.png :/QmitkDiffusionImaging/circle.png 32 32 true true 30 30 Draw quadratic ROI :/QmitkDiffusionImaging/rectangle.png :/QmitkDiffusionImaging/rectangle.png 32 32 true true 30 30 Draw polygonal ROI :/QmitkDiffusionImaging/polygon.png :/QmitkDiffusionImaging/polygon.png 32 32 true true Qt::Horizontal 40 20 true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Upsampling QFrame::NoFrame QFrame::Raised 0 1 50 1 25 Qt::Horizontal 50 0 2.5 Similar angles QFrame::NoFrame 0 90 0 Qt::Horizontal QSlider::NoTicks 50 0 90° QFrame::NoFrame QFrame::Raised 0 0 display histogram true 0 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 20 20 true true Green Partial Volume Partial Volume Partial Volume Partial Volume PV Red true All Export clustering result as float image. ... :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png QFrame::NoFrame 0 Opacity 10 5 Qt::Horizontal QSlider::TicksBelow Qt::Vertical QSizePolicy::Fixed 20 10 The computed class values (median, variance of the gaussians) are automatically copied to clipboard. Qt::AutoText true Qt::Vertical QSizePolicy::Fixed 20 10 Histogram to Clipboard Advanced Qt::Vertical QSizePolicy::Preferred 10 1 QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Blurring QFrame::NoFrame QFrame::Raised 0 200 1 0 Qt::Horizontal 50 0 0.0 # Bins QFrame::NoFrame 0 1 100 10 Qt::Horizontal QSlider::NoTicks 50 0 50 quantiles QFrame::StyledPanel QFrame::Raised 0 1.000000000000000 0.010000000000000 0.250000000000000 1.000000000000000 0.010000000000000 0.750000000000000 Estimate circle from binary image "Thick" PFs Qt::Vertical 20 40 QmitkPartialVolumeAnalysisWidget QWidget
QmitkPartialVolumeAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui index dfd044558f..6120fc9c5f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui @@ -1,1766 +1,1759 @@ QmitkPreprocessingViewControls 0 0 503 813 0 0 false QmitkPreprocessingViewControls true QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Please Select Input Data 6 6 6 6 Image: QComboBox::AdjustToMinimumContentsLength 0 Gradients 25 Qt::Vertical 20 40 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients QFrame::NoFrame QFrame::Raised 0 0 0 0 6 <html><head/><body><p>Define the sampling frame the b-Values are rounded with.</p></body></html> Sampling frame: false <html><head/><body><p>Round b-values to nearest multiple of this value (click &quot;Round b-value&quot; to create new image with these values).</p></body></html> QAbstractSpinBox::CorrectToNearestValue 1 10000 10 false Sometimes the gradient directions are not located on one half sphere. Mirror gradients to half sphere false Generate pointset displaying the gradient vectors (applied measurement frame). Show gradients false Generate pointset displaying the gradient vectors (applied measurement frame). Flip gradients false Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. Reduce number of gradients QFrame::NoFrame QFrame::Plain 0 0 0 0 0 x y z false Round b-values false By default, the image matrix is applied to the image gradients. This button removes this additional rotation. Clear rotation of gradients Remove or extract gradient volumes 6 6 6 6 6 6 false Remove gradient volume false Extract gradient volume Image Values 25 Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Merge radius false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs false Normalizes the diffusion-weighted image values across all weighted volumes to the given mean and standard deviation. Normalize image values QFrame::NoFrame QFrame::Raised 0 0 0 0 0 false Target b-value 100000 500 Select projection method. QComboBox::AdjustToMinimumContentsLength ADC Average AKC Bi-Exponential false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average repetitions false Project image values onto one b-shell. Project onto shell QFrame::NoFrame QFrame::Raised 0 0 0 0 0 true New stdev 100000 100 500 Select binary mask image. The mask is used to calculate the old mean and standard deviation. QComboBox::AdjustToMinimumContentsLength true New mean value 100000 100 1000 false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Flip axis QFrame::NoFrame QFrame::Raised 0 0 0 0 Y Qt::Horizontal 40 20 X Z Axis: QComboBox::AdjustToMinimumContentsLength Resample image 6 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 Sampling factor New image spacing New image size QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Interpolator: Nearest neighbour Linear B-spline Windowed sinc false Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 1 10000 1 10000 1 10000 Crop Image 6 6 6 6 6 x: y: z: Crop Image Header 25 Voxel size 6 6 6 6 4 0.000000000000000 99.989999999999995 4 4 false Apply new header information Direction matrix 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 0 0 Measurment frame 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 Qt::Vertical 20 40 Origin 6 6 6 6 4 -999999999.000000000000000 999999999.000000000000000 4 -99999999.000000000000000 999999999.000000000000000 4 -999999999.000000000000000 999999999.000000000000000 Align origins 6 6 6 6 QComboBox::AdjustToMinimumContentsLength Align to Other false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Estimate binary brain mask Maximum number of iterations. 10000 10000 Qt::Vertical 20 40 false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract baseline image Create a 3D+t data set containing all b0 images as timesteps Disable averaging QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_SelctedImageComboBox tabWidget m_B_ValueMap_TableWidget m_CreateLengthCorrectedDwi m_B_ValueMap_Rounder_SpinBox m_FlipGradientsButton m_FlipGradBoxX m_FlipGradBoxY m_FlipGradBoxZ m_ShowGradientsButton m_MirrorGradientToHalfSphereButton m_ReduceGradientsButton m_ClearRotationButton m_RemoveGradientButton m_RemoveGradientBox m_ExtractGradientButton m_ExtractGradientBox m_ButtonAverageGradients m_Blur m_ProjectSignalButton m_targetBValueSpinBox m_ProjectionMethodBox m_NormalizeImageValuesButton m_NewMean m_NewStdev m_NormalizationMaskBox m_FlipAxis m_FlipX m_FlipY m_FlipZ m_MergeDwisButton m_MergeDwiBox m_ResampleTypeBox m_ResampleDoubleX m_ResampleDoubleY m_ResampleDoubleZ m_ResampleIntX m_ResampleIntY m_ResampleIntZ m_InterpolatorBox m_ResampleImageButton m_XstartBox m_XendBox m_YstartBox m_YendBox m_ZstartBox m_ZendBox m_CropImageButton m_ModifyHeader m_HeaderOriginX m_HeaderOriginY m_HeaderOriginZ m_HeaderSpacingX m_HeaderSpacingY m_HeaderSpacingZ m_DirectionMatrixTable m_MeasurementFrameTable m_ButtonExtractB0 m_CheckExtractAll m_ExtractBrainMask m_BrainMaskIterationsBox
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui index 01a01e31c5..3671293c44 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui @@ -1,125 +1,118 @@ QmitkBrainExtractionViewControls 0 0 435 744 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } false Start Brain Extraction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui index efcc1114a2..6002ee62c4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui @@ -1,458 +1,451 @@ QmitkDiffusionQuantificationViewControls 0 0 343 888 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Input Data 6 6 6 6 Image Scale Image Values: 9999999.000000000000000 1.000000000000000 Raw diffusion-weighted image 6 6 6 6 false ADC false MD false Ball-Stick false Multi-Tensor Fit ODF image 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Generalized GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 true k true true p true false GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. angle Max. angle false Curvature Tensor image 6 6 6 6 false FA (Fractional Anisotropy) false RA (Relative Anisotropy) false AD (Axial Diffusivity) false RD (Radial Diffusivity) false MD (Mean Diffusivity) false 1-(λ2+λ3)/(2*λ1) Qt::Vertical QSizePolicy::Expanding 20 220 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui index 01204eabad..bad0fc4932 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui @@ -1,287 +1,280 @@ QmitkODFDetailsViewControls 0 0 351 734 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 6 9 9 9 9 Please Select Input Data 6 6 6 6 DTI/ODF: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Overview 6 6 6 6 0 0 0 0 true 0 0 200 200 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 ODF Values 6 6 6 6 true 0 0 0 200 Qt::Vertical QSizePolicy::Expanding 20 220 QmitkODFDetailsWidget QWidget
QmitkODFDetailsWidget.h
1
QmitkODFRenderWidget QWidget
QmitkODFRenderWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui index 5d8166f03f..bb4d30e9be 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui @@ -1,457 +1,450 @@ QmitkQBallReconstructionViewControls 0 0 372 844 0 0 true QmitkQBallReconstructionViewControls QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Parameters 6 6 6 6 2 Numerical Standard Solid Angle Constraint Solid Angle ADC-Profile only Raw Signal only Multi-Shell TextLabel QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Regularization Parameter Lambda: false Regularization factor 3 1.000000000000000 0.001000000000000 0.006000000000000 true SH-Order: false true -1 true B0 Threshold false 10000 Output SH-Coefficient Image false false Start Reconstruction Input Data 6 6 6 6 Input for Q-Ball reconstruction. Raw DWI: true Qt::LeftToRight false Multi-Shell Reconstruction 6 6 6 6 Qt::Vertical 20 0 Convert SH to sampled ODF image 6 6 6 6 false Convert QFrame::NoFrame QFrame::Raised 0 0 0 0 Input for Q-Ball reconstruction. SH Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui index b32a923947..a7512461be 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui @@ -1,785 +1,778 @@ QmitkTensorReconstructionViewControls 0 0 368 1019 0 0 true QmitkTensorReconstructionViewControls QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 ODF Image from Tensors 6 6 6 6 false Calculate ODF value as tensor value in the according direction Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Diffusion-weighted Image from Tensors 6 6 6 6 false Estimates the original diffusion weighted image based on a reconstructed tensor image. Estimate DWI based on Tensor Image QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 6 0 0 0 0 how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" B-Value false #Gradient Directions 3 12 42 92 162 252 362 492 642 812 1002 10000 100 1000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Calculate Residuals false false 6 6 6 6 6 false percentages of error 0 Per volume 200 300 Per slice outliers per slice QFrame::NoFrame QFrame::Raised 0 0 0 0 300 400 QFrame::NoFrame QFrame::Raised 0 0 0 0 20 255 Volume: .., Slice:.. false Calculate the residual from a dti and a dwi image Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: Tensor Image: Qt::Vertical 20 40 Tensor Reconstruction 6 6 6 6 Advanced Settings false false Select raw DWI! Start Reconstruction QFrame::StyledPanel QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 B0 Threshold false 10000 Only influences WLS reconstruction Ignore voxels with negative eigenvalues 0 ITK Linear Least Squares With correction for negative eigenvalues QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkResidualAnalysisWidget QWidget
QmitkResidualAnalysisWidget.h
1
QmitkResidualViewWidget QGraphicsView
QmitkResidualViewWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui index c48527cac1..c73acb1a3a 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui @@ -1,125 +1,118 @@ QmitkHeadMotionCorrectionViewControls 0 0 435 744 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } false Start DWI registration/Head Motion Correction Start Head Motion Correction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui index b413b63e85..1073648dd4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui @@ -1,316 +1,309 @@ QmitkSimpleRegistrationViewControls 0 0 435 744 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 25 Qt::Vertical 20 40 Image Registration 6 6 6 6 false Start Registration QFrame::NoFrame QFrame::Raised 0 0 0 0 Rigid Affine Registration Type: Output Registration Object: QFrame::NoFrame QFrame::Raised 0 0 0 0 Moving Image: false Select dMRI volume used to calculate transformation. false Select dMRI volume used to calculate transformation. Fixed Image: QFrame::NoFrame QFrame::Raised 0 0 0 0 false Start Tractography Registration Tractography Registration 6 6 6 6 Registration Object: Tractogram: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui index d213dba93f..3edd0a05a2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui @@ -1,165 +1,158 @@ QmitkTbssSkeletonizationViewControls 0 0 431 811 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 0 0 0 80 QFrame::StyledPanel QFrame::Raised false Mean: false Patient Data: false Tubular Structure Mask: false Skeletonize false Skeletonize and Project false Output binary mask true false Output distance map true \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui index 2628034274..fc056a2cfa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui @@ -1,502 +1,495 @@ QmitkTractbasedSpatialStatisticsViewControls 0 0 265 811 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 0 0 FSL import Subject Data false false QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised Group information QAbstractItemView::SelectRows 0 0 110 100 QFrame::NoFrame QFrame::Raised 0 0 Add group entry. After that give the group a name and the correct number Add 0 0 Remove selected entries Remove false 0 0 Import a 4D image containing group data after group information has been set Import data 0 0 QFrame::StyledPanel QFrame::Raised 0 0 Measure Measurement in the to be imported 4D image FA 0 0 Tract-specific analysis true To create a roi first load a tbss meta image into the datamanager 0 ROIs 0 0 Points on Roi 100 100 0 100 Use this widget to create points on the ROI by shift-leftclick on the right positions on the skeleton. Then click Create Roi. The Roi that will be created will pass through the points in the order of occurence in this list false 0 0 No suitable tbss meta image selected yet. The meta image needs to contain a mean FA skeleton and a skeleton mask Create ROI 0 0 Points on the ROI 0 0 Name Give a name to the region of interest roiname 0 0 Structure info On what anatomical structure lies the ROI? Structure 0 0 current selection mean FA skeleton: Qt::Horizontal 253 20 Measuring 16777215 50 false #segments false 100 25 false Average false Cut To plot, load a tbss image with subject information and a region of interest corresponding to the study and select them both Copy to clipboard QmitkPointListWidget QWidget
QmitkPointListWidget.h
QmitkTbssRoiAnalysisWidget QWidget
QmitkTbssRoiAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui index dd1813e50f..ea598ceab8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1206 +1,1199 @@ QmitkGibbsTrackingViewControls 0 0 463 1011 0 0 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } QFormLayout::AllNonFixedFieldsGrow QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 false No ODF/tensor image selected. Qt::LeftToRight Start Tractography :/QtWidgetsExt/play.xpm :/QtWidgetsExt/play.xpm false Qt::LeftToRight Stop Tractography :/QtWidgetsExt/stop.xpm :/QtWidgetsExt/stop.xpm Parameters 6 6 6 6 Output File: Advanced Settings true Activate continuous visualization of intermediate results. Visualize Tractography true QFrame::NoFrame QFrame::Plain 0 0 0 0 0 0 Select output file name and folder. ... N/A true Visualize intermediate result. :/QmitkDiffusionImaging/Refresh_48.png :/QmitkDiffusionImaging/Refresh_48.png true Iterations: 1e9 true QFrame::StyledPanel QFrame::Raised 0 0 0 0 6 Particle Width: 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0.1 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Particle Weight: 1 99 1 10 Qt::Horizontal QSlider::NoTicks Start Temperature: automatic estimation from gfa map and ODF data. 0 1000 1 0 Qt::Horizontal true QSlider::NoTicks IE Bias < 0 < EE Bias -50 50 1 Qt::Horizontal QSlider::NoTicks 0.001 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Curvature Threshold: Balance In/Ex Energy: 45° Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 0.5 * min. spacing; sigma 100 1 Qt::Horizontal QSlider::NoTicks Particle Length: auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Min. Fiber Length: Only fibers longer than specified are accepted. 500 1 20 Qt::Horizontal QSlider::NoTicks Allow only fiber curvature values smaller than the selected threshold. 180 1 45 Qt::Horizontal QSlider::NoTicks End Temperature: 20mm Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 1 100 1 10 Qt::Horizontal false false QSlider::NoTicks auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l 100 1 Qt::Horizontal QSlider::NoTicks Random Seed auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l -1 100 1 -1 Qt::Horizontal QSlider::NoTicks QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 true Save current parameters as xml (.gtp) Qt::LeftToRight Save Parameters :/QmitkDiffusionImaging/general_icons/download.ico :/QmitkDiffusionImaging/general_icons/download.ico true Load parameters from xml file (.gtp) Qt::LeftToRight Load Parameters :/QmitkDiffusionImaging/general_icons/upload.ico :/QmitkDiffusionImaging/general_icons/upload.ico Qt::Vertical QSizePolicy::Expanding 0 0 0 0 Input Data 6 6 6 6 0 0 ODF/Tensor Image: Mask Image: 0 0 0 0 0 0 Monitor 6 6 6 6 6 Progress: - Will only be updated if tracking is visualized Will only be updated if tracking is visualized Accepted Fibers: Connections: Particles: Proposal Acceptance Rate: Tracking Time: Will only be updated if tracking is visualized - - - - - QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui index f42e1f2b6b..cc06db5811 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui @@ -1,472 +1,465 @@ QmitkMLBTViewControls 0 0 476 548 Form QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Remove training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg Add additional training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">It is recommended to use the command line application 'RfTraining' instead of this graphical user interface for the training process. Additional feature images are not supported here.</span></p><p><span style=" font-weight:600; color:#ff0000;">The GUI is intended for testing using small examples.</span></p></body></html> Qt::RichText Qt::AlignCenter true 5 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Input DWI: Qt::AlignCenter Reference Tractogram: Qt::AlignCenter Mask: Qt::AlignCenter WM: Qt::AlignCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 Fraction of samples used to train each tree. 3 1.000000000000000 0.100000000000000 0.700000000000000 Num. Trees: Sample Fraction: Max. Depth: Fiber sampling in mm. Determines the number of white-matter samples (-1 = auto). 3 -1.000000000000000 999.000000000000000 0.100000000000000 -1.000000000000000 Number of tress in the final random forest. 1 999999999 30 Non-WM Sampling Points: Fiber Sampling: Maximum tree depth. 1 999999999 25 Number of sampling points outside of the white-matter (-1 = automatic estimation). -1 999999999 -1 Num. previous directions: Number of previous fiber directions used as features. 0 50 1 dMRI Features: Spherical Harmonics Coefficients Raw Data Start Training. This can take up to a couple of hours. Start Training Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui index 432fd0c51d..32fc1145d5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -1,1597 +1,1590 @@ - + QmitkStreamlineTrackingViewControls 0 0 453 859 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 3 3 0 40 QFrame::NoFrame QFrame::Raised 0 15 0 0 6 15 true 0 0 true QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image. ODF, tensor and peak images are currently supported. Input Image: Input Image. ODF, tensor, peak, and, in case of ML tractography, raw diffusion-weighted images are currently supported. - <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> true - + Tractography Forest: Random forest for machine learning based tractography. QComboBox::AdjustToMinimumContentsLength - true Stop tractography and return all fibers reconstructed until now. Stop Tractography false Start Tractography 0 0 0 0 0 0 0 421 262 Seeding Specify how, where and how many tractography seed points are placed. QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points equally distributed around selected position. 1 9999999 50 - + Radius: Seedpoints are equally distributed within a sphere centered at the selected position with the specified radius (in mm). 2 50.000000000000000 0.100000000000000 2.000000000000000 - + Num. Seeds: true When checked, parameter changes cause instant retracking while in interactive mode. - Update on Parameter Change + Update on Parameter Change true QFrame::NoFrame QFrame::Raised 0 0 0 0 Try each seed N times until a valid streamline is obtained (only for probabilistic tractography). Minimum fiber length (in mm) 1 999 10 - + Trials Per Seed: - + Max. Num. Fibers: Tractography is stopped after the desired number of fibers is reached, even before all seed points are processed (-1 means no limit). -1 999999999 -1 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points placed in each voxel. 1 9999999 - + Seeds per Voxel: Seed points are only placed inside the regions defined in the seed image. If no seed image is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - - + Seed Image: true Dynamically pick a seed location by click into image. Enable Interactive Tractography Qt::Vertical 20 40 0 0 435 224 ROI Constraints Specify various ROI and mask images to constrain the tractography process. - + Mask Image: Fibers that enter a region defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - Select which fibers should be accepted or rejected based on the location of their endpoints. QComboBox::AdjustToMinimumContentsLength No Constraints on EP locations Both EPs in Target Image Both EPs in Target Image But Different Label One EP in Seed Image and One EP in Target Image At Least One EP in Target Image Exactly One EP in Target Image No EP in Target Image - + Endpoint Constraints: - + Stop ROI Image: The target image is used for the endpoint constraint strategy defined above. QComboBox::AdjustToMinimumContentsLength - - + Exclusion ROI Image: Fibers that leave the regions defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - - + Target ROI Image: Fibers that enter a region defined in this image will be discarded. QComboBox::AdjustToMinimumContentsLength - Qt::Vertical 20 40 0 0 421 351 Tractography Parameters Specify the behavior of the tractography at each streamline integration step (step size, deterministic/probabilistic, ...). Qt::Vertical 20 40 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 0.000000000000000 Toggle between deterministic and probabilistic tractography. Some modes might not be available for all types of tractography. Deterministic Probabilistic - + Cutoff: - + FA/GFA Image: - + Mode: - + Angular Threshold: Step size (in voxels) 2 0.010000000000000 10.000000000000000 0.100000000000000 0.500000000000000 Maximum allowed angular SDTEV over 4 voxel lengths. Default: no loop check. - + -1 180 -1 If an image is selected, the stopping criterion is not calculated from the input image but instead the selected image is used. QComboBox::AdjustToMinimumContentsLength - - + Step Size: Additional threshold on the ODF magnitude. This is useful in case of CSD fODF tractography. For fODFs a good default value is 0.1, for normalized dODFs, e.g. Q-ball ODFs, this threshold should be very low (0.00025) or 0. 5 1.000000000000000 0.100000000000000 0.000250000000000 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 1.000000000000000 If you are using dODF images as input, it is advisable to sharpen the ODFs (min-max normalize and raise to the power of 4). This is not necessary for CSD fODFs, since they are naturally much sharper. - + f parameter of tensor tractography. f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). f: - + Min. Tract Length: Threshold on peak magnitude, FA, GFA, ... 5 1.000000000000000 0.100000000000000 0.100000000000000 - + ODF Cutoff: Minimum tract length in mm. Shorter fibers are discarded. Minimum fiber length (in mm) 1 999.000000000000000 1.000000000000000 20.000000000000000 - + Loop Check: Angular threshold between two steps (in degree). Default: 90° * step_size -1 90 1 -1 - + g: - + Sharpen ODFs: 0 0 435 224 Tractography Prior Restrict to Prior: Weight: Peak Image: Weighting factor between prior and data. 1.000000000000000 0.100000000000000 0.500000000000000 Restrict tractography to regions where the prior is valid. - + true - + Qt::Vertical 20 40 New Directions from Prior: If unchecked, the prior cannot create directions where there are none in the data. - + true 0 0 435 224 Neighborhood Sampling Specify if and how information about the current streamline neighborhood should be used. Only neighborhood samples in front of the current streamline position are considered. Use Only Frontal Samples false If checked, the majority of sampling points has to place a stop-vote for the streamline to terminate. If not checked, all sampling positions have to vote for a streamline termination. Use Stop-Votes false QFrame::NoFrame QFrame::Raised 0 0 0 0 - + Num. Samples: Number of neighborhood samples that are used to determine the next fiber progression direction. 50 - + Sampling Distance: Sampling distance (in voxels) 2 10.000000000000000 0.100000000000000 0.250000000000000 Qt::Vertical 20 40 0 0 435 224 Data Handling Specify interpolation and direction flips. QFrame::NoFrame QFrame::Raised 0 0 0 0 Trilinearly interpolate the input image used for tractography. Interpolate Tractography Data true Trilinearly interpolate the ROI images used to constrain the tractography. Interpolate ROI Images true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Internally flips progression directions. This might be necessary depending on the input data. x Internally flips progression directions. This might be necessary depending on the input data. y Internally flips progression directions. This might be necessary depending on the input data. z - + Flip directions: Qt::Vertical 20 40 0 0 435 224 Output and Postprocessing Specify the tractography output (streamlines or probability maps) and postprocessing steps. QFrame::NoFrame QFrame::Raised 0 0 0 0 Compress fibers using the specified error constraint. Compress Fibers true Qt::StrongFocus Lossy fiber compression. Recommended for large tractograms. Maximum error in mm. 3 10.000000000000000 0.010000000000000 0.100000000000000 Output map with voxel-wise visitation counts instead of streamlines. Output Probability Map false Qt::Vertical 20 40 - + QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
- - -
+ + + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui index 670cecafb9..9d779a6a02 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui @@ -1,1037 +1,1030 @@ QmitkControlVisualizationPropertiesViewControls 0 0 567 619 0 100 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Multislice Projection MIP QToolButton::MenuButtonPopup Qt::NoArrow QFrame::NoFrame QFrame::Plain 0 0 0 0 Toggle visibility of ODF glyphs (axial) :/QmitkDiffusionImaging/glyphsoff_T.png :/QmitkDiffusionImaging/glyphson_T.png :/QmitkDiffusionImaging/glyphsoff_T.png true false Toggle visibility of ODF glyphs (sagittal) :/QmitkDiffusionImaging/glyphsoff_S.png :/QmitkDiffusionImaging/glyphson_S.png :/QmitkDiffusionImaging/glyphsoff_S.png true false Toggle visibility of ODF glyphs (coronal) :/QmitkDiffusionImaging/glyphsoff_C.png :/QmitkDiffusionImaging/glyphson_C.png :/QmitkDiffusionImaging/glyphsoff_C.png true false #Glyphs 9999 Qt::Horizontal 20 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF normalization false Min-Max Max None ODF Normalization: ODF normalization false ODF Value Principal Direction Color ODFs/Tensors by: QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF Scale: false None FA/GFA * Additional scaling factor 3 999999999.000000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Position Crosshair by 3D-Click :/QmitkDiffusionImaging/crosshair.png :/QmitkDiffusionImaging/crosshair.png true false 2D Fiberfading on/off Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 2D Clipping 100 10 10 10 Qt::Horizontal 90 0 10000 16777215 Range QFrame::NoFrame QFrame::Raised 0 0 0 0 Tube Radius 3 0.100000000000000 Ribbon Width 3 0.100000000000000 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">One or more slices are rotated. ODF Visualisation is not possible in rotated planes. Use 'Reinit' on the image node to reset. </span></p></body></html> Qt::AutoText true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 y z x 0 0 Flip Peaks QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Qt::Horizontal 40 20 Line Width 1 1.000000000000000 0.100000000000000 1.000000000000000 3D Clipping 6 6 6 6 0 Coronal Axial No clipping true Sagittal Flipp Clipping Direction Enable 3D Rendering Qt::Vertical 20 40 QmitkDataStorageComboBox.h \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui index f80e09d34d..5c160ad17e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui @@ -1,193 +1,186 @@ QmitkDicomTractogramTagEditorViewControls 0 0 397 366 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 3 3 0 QFrame::NoFrame QFrame::Raised 0 0 0 9 Tractogram: Seed points are only placed inside the mask image. If no seed mask is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - Tractography DICOM Tags 6 6 6 6 0 QFrame::NoFrame Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::Vertical QSizePolicy::Expanding 20 220 Copies the DICOM properties of the tractogram selected in this view to the one selected in the datamanager. Copy Properties From Image QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui index 736bf50aa2..336dc2fbac 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui @@ -1,408 +1,401 @@ QmitkDiffusionDicomImportControls 0 0 374 603 0 0 true QmitkDiffusionDicomImport QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 16777215 70 QFrame::NoFrame QFrame::Plain 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Each input folder must only contain DICOM-images that can be combined into one vector-valued 3D output volume. Different patients must be loaded from different input-folders. The folders must not contain other acquisitions (e.g. T1,T2,localizer).</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">In case many imports are performed at once, it is recommended to set the the optional output folder argument. This prevents the images from being kept in memory.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p></td></tr></table></body></html> 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Add Input Folders Remove Clear 0 0 0 70 QFrame::Box QFrame::Plain 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOn QListView::Adjust true QFrame::StyledPanel QFrame::Raised Recursive 8 QLayout::SetNoConstraint Set Prefix Reset Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them anyway by taking into account all directions within a certain radius. QFrame::NoFrame QFrame::Raised 0 0 0 0 Merge duplicate gradients: false 4 2.000000000000000 0.000100000000000 0.001000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 40 25 30 16777215 Files are automaticall saved to disc. If the files can not be written, they are added to the data manager. Set ... optional out-folder ... false true 50 25 30 16777215 Clear Override existing files Split Mosaic Import DICOM as *.dwi Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui index 536be45e1e..e567f646f8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui @@ -1,71 +1,64 @@ QmitkWelcomeScreenViewControls 0 0 458 398 0 0 QmitkTemplate QCommandLinkButton { - font-weight: normal; + font-weight: lighter; } QCommandLinkButton:disabled { border: none; font-weight: lighter; } QToolBox::tab { - border: 1px solid #434346; font-weight: bold; } QToolBox::tab:hover { - background-color: #434346; font-weight: bold; } QToolBox::tab:selected { - background-color: #1c97ea; - border: 1px solid #1c97ea; font-weight: bold; } QGroupBox { - border: 1px solid #434346; - background-color: #2d2d30; - margin-top: 8px; - padding-top: 8px; + background-color: transparent; } QGroupBox, QGroupBox:disabled { - background-color: #2d2d30; + background-color: transparent; } 0 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistrationControls.ui b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistrationControls.ui index 3e320044a8..931b1781bb 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistrationControls.ui +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkIGTFiducialRegistrationControls.ui @@ -1,178 +1,166 @@ IGTFiducialRegistrationControls 0 0 - 392 - 753 + 454 + 625 0 0 QmitkTemplate - - - 2 - - - 2 - - - 2 - - - 2 - - + + Configuration - - + + <html><head/><body><p><span style=" font-weight:600;">Choose Tracking Pointer:</span></p></body></html> - + - + Choose Selected Qt::Horizontal 40 20 <none> - + Qt::Horizontal - + <html><head/><body><p><span style=" font-weight:600;">Choose Image or Surface:</span></p></body></html> - + - + Choose Selected Qt::Horizontal 40 20 <none> - + Point Based Registration - - + + 16777215 900 QmitkNavigationDataSourceSelectionWidget QWidget
QmitkNavigationDataSourceSelectionWidget.h
1
QmitkFiducialRegistrationWidget QTextBrowser
QmitkFiducialRegistrationWidget.h
QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
1
diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp index f5cd6b6732..ea16dd96c0 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp @@ -1,1426 +1,1426 @@ /*=================================================================== 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 "QmitkMITKIGTTrackingToolboxView.h" // Qt #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include //for exceptions #include #include #include "mitkPluginActivator.h" const std::string QmitkMITKIGTTrackingToolboxView::VIEW_ID = "org.mitk.views.mitkigttrackingtoolbox"; QmitkMITKIGTTrackingToolboxView::QmitkMITKIGTTrackingToolboxView() : QmitkAbstractView() , m_Controls(nullptr) , m_DeviceTypeCollection(nullptr) , m_ToolProjectionNode(nullptr) { m_TrackingLoggingTimer = new QTimer(this); m_TrackingRenderTimer = new QTimer(this); m_TimeoutTimer = new QTimer(this); m_tracking = false; m_connected = false; m_logging = false; m_ShowHideToolAxis = false; m_loggedFrames = 0; m_SimpleModeEnabled = false; m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); //create filename for autosaving of tool storage QString loggingPathWithoutFilename = QString(mitk::LoggingBackend::GetLogFile().c_str()); if (!loggingPathWithoutFilename.isEmpty()) //if there already is a path for the MITK logging file use this one { //extract path from path+filename (if someone knows a better way to do this feel free to change it) int lengthOfFilename = QFileInfo(QString::fromStdString(mitk::LoggingBackend::GetLogFile())).fileName().size(); loggingPathWithoutFilename.resize(loggingPathWithoutFilename.size() - lengthOfFilename); m_AutoSaveFilename = loggingPathWithoutFilename + "TrackingToolboxAutoSave.IGTToolStorage"; } else //if not: use a temporary path from IOUtil { m_AutoSaveFilename = QString(mitk::IOUtil::GetTempPath().c_str()) + "TrackingToolboxAutoSave.IGTToolStorage"; } MITK_INFO("IGT Tracking Toolbox") << "Filename for auto saving of IGT ToolStorages: " << m_AutoSaveFilename.toStdString(); //! [Thread 1] //initialize worker thread m_WorkerThread = new QThread(); m_Worker = new QmitkMITKIGTTrackingToolboxViewWorker(); //! [Thread 1] ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { QString interfaceName = QString::fromStdString(us_service_interface_iid()); QList serviceReference = pluginContext->getServiceReferences(interfaceName); if (serviceReference.size() > 0) { m_DeviceTypeServiceReference = serviceReference.at(0); const ctkServiceReference& r = serviceReference.at(0); m_DeviceTypeCollection = pluginContext->getService(r); } else { MITK_INFO << "No Tracking Device Collection!"; } } } QmitkMITKIGTTrackingToolboxView::~QmitkMITKIGTTrackingToolboxView() { this->StoreUISettings(); m_TrackingLoggingTimer->stop(); m_TrackingRenderTimer->stop(); m_TimeoutTimer->stop(); delete m_TrackingLoggingTimer; delete m_TrackingRenderTimer; delete m_TimeoutTimer; try { //! [Thread 2] // wait for thread to finish m_WorkerThread->terminate(); m_WorkerThread->wait(); //clean up worker thread if (m_WorkerThread) { delete m_WorkerThread; } if (m_Worker) { delete m_Worker; } //! [Thread 2] //remove the tracking volume this->GetDataStorage()->Remove(m_TrackingVolumeNode); //unregister microservices if (m_toolStorage) { m_toolStorage->UnRegisterMicroservice(); } if (m_IGTLMessageProvider.IsNotNull()){ m_IGTLMessageProvider->UnRegisterMicroservice(); } } catch (std::exception& e) { MITK_WARN << "Unexpected exception during clean up of tracking toolbox view: " << e.what(); } catch (...) { MITK_WARN << "Unexpected unknown error during clean up of tracking toolbox view!"; } //store tool storage and UI settings for persistence this->AutoSaveToolStorage(); this->StoreUISettings(); m_DeviceTypeCollection = nullptr; mitk::PluginActivator::GetContext()->ungetService(m_DeviceTypeServiceReference); } void QmitkMITKIGTTrackingToolboxView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkMITKIGTTrackingToolboxViewControls; m_Controls->setupUi(parent); //create connections connect(m_Controls->m_LoadTools, SIGNAL(clicked()), this, SLOT(OnLoadTools())); connect(m_Controls->m_ConnectDisconnectButton, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartStopTrackingButton, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_ConnectSimpleMode, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartTrackingSimpleMode, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_FreezeUnfreezeTrackingButton, SIGNAL(clicked()), this, SLOT(OnFreezeUnfreezeTracking())); connect(m_TrackingLoggingTimer, SIGNAL(timeout()), this, SLOT(UpdateLoggingTrackingTimer())); connect(m_TrackingRenderTimer, SIGNAL(timeout()), this, SLOT(UpdateRenderTrackingTimer())); connect(m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(OnTimeOut())); connect(m_Controls->m_ChooseFile, SIGNAL(clicked()), this, SLOT(OnChooseFileClicked())); connect(m_Controls->m_StartLogging, SIGNAL(clicked()), this, SLOT(StartLogging())); connect(m_Controls->m_StopLogging, SIGNAL(clicked()), this, SLOT(StopLogging())); connect(m_Controls->m_VolumeSelectionBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(OnTrackingVolumeChanged(QString))); connect(m_Controls->m_ShowTrackingVolume, SIGNAL(clicked()), this, SLOT(OnShowTrackingVolumeChanged())); connect(m_Controls->m_AutoDetectTools, SIGNAL(clicked()), this, SLOT(OnAutoDetectTools())); connect(m_Controls->m_ResetTools, SIGNAL(clicked()), this, SLOT(OnResetTools())); connect(m_Controls->m_AddSingleTool, SIGNAL(clicked()), this, SLOT(OnAddSingleTool())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(NavigationToolFinished()), this, SLOT(OnAddSingleToolFinished())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(Canceled()), this, SLOT(OnAddSingleToolCanceled())); connect(m_Controls->m_CsvFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_XmlFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_UseDifferentUpdateRates, SIGNAL(clicked()), this, SLOT(OnToggleDifferentUpdateRates())); connect(m_Controls->m_RenderUpdateRate, SIGNAL(valueChanged(int)), this, SLOT(OnChangeRenderUpdateRate())); connect(m_Controls->m_DisableAllTimers, SIGNAL(stateChanged(int)), this, SLOT(EnableDisableTimerButtons(int))); connect(m_Controls->m_advancedUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); connect(m_Controls->m_SimpleUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); connect(m_Controls->showHideToolProjectionCheckBox, SIGNAL(clicked()), this, SLOT(OnShowHideToolProjectionClicked())); connect(m_Controls->showHideToolAxisCheckBox, SIGNAL(clicked()), this, SLOT(OnShowHideToolAxisClicked())); connect(m_Controls->m_toolselector, SIGNAL(currentIndexChanged(int)), this, SLOT(SelectToolProjection(int))); //connections for the tracking device configuration widget connect(m_Controls->m_ConfigurationWidget, SIGNAL(TrackingDeviceSelectionChanged()), this, SLOT(OnTrackingDeviceChanged())); //! [Thread 3] //connect worker thread connect(m_Worker, SIGNAL(AutoDetectToolsFinished(bool, QString)), this, SLOT(OnAutoDetectToolsFinished(bool, QString))); connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), this, SLOT(OnConnectFinished(bool, QString))); connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), this, SLOT(OnStartTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), this, SLOT(OnStopTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), this, SLOT(OnDisconnectFinished(bool, QString))); connect(m_WorkerThread, SIGNAL(started()), m_Worker, SLOT(ThreadFunc())); connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnConnected(bool))); connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnDisconnected(bool))); connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnStartTracking(bool))); connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnStopTracking(bool))); //Add Listener, so that we know when the toolStorage changed. std::string m_Filter = "(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.NavigationToolStorage" + ")"; mitk::PluginActivator::GetContext()->connectServiceListener(this, "OnToolStorageChanged", QString(m_Filter.c_str())); //move the worker to the thread m_Worker->moveToThread(m_WorkerThread); //! [Thread 3] //initialize widgets m_Controls->m_TrackingToolsStatusWidget->SetShowPositions(true); m_Controls->m_TrackingToolsStatusWidget->SetTextAlignment(Qt::AlignLeft); m_Controls->m_simpleWidget->setVisible(false); //initialize tracking volume node m_TrackingVolumeNode = mitk::DataNode::New(); m_TrackingVolumeNode->SetName("TrackingVolume"); m_TrackingVolumeNode->SetBoolProperty("Backface Culling", true); mitk::Color red; red.SetRed(1); m_TrackingVolumeNode->SetColor(red); //initialize buttons m_Controls->m_AutoDetectTools->setVisible(false); //only visible if supported by tracking device m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //initialize warning labels m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_TrackingFrozenLabel->setVisible(false); //Update List of available models for selected tool. std::vector Compatibles; if ((m_Controls == nullptr) || //check all these stuff for NULL, latterly this causes crashes from time to time (m_Controls->m_ConfigurationWidget == nullptr) || (m_Controls->m_ConfigurationWidget->GetTrackingDevice().IsNull())) { MITK_ERROR << "Couldn't get current tracking device or an object is nullptr, something went wrong!"; return; } else { Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType()); } m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } //initialize tool storage m_toolStorage = mitk::NavigationToolStorage::New(GetDataStorage()); m_toolStorage->SetName("TrackingToolbox Default Storage"); m_toolStorage->RegisterAsMicroservice(); //set home directory as default path for logfile m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(QDir::homePath()) + QDir::separator() + "logfile.csv"); //tracking device may be changed already by the persistence of the //QmitkTrackingDeciveConfigurationWidget this->OnTrackingDeviceChanged(); this->LoadUISettings(); //add tracking volume node only to data storage this->GetDataStorage()->Add(m_TrackingVolumeNode); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); //Update List of available models for selected tool. m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } } void QmitkMITKIGTTrackingToolboxView::OnLoadTools() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Tool Storage"), "/", tr("Tool Storage Files (*.IGTToolStorage)")); if (filename.isNull()) return; //read tool storage from disk std::string errorMessage = ""; mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); // try-catch block for exceptions try { this->ReplaceCurrentToolStorage(myDeserializer->Deserialize(filename.toStdString()), filename.toStdString()); } catch (mitk::IGTException) { std::string errormessage = "Error during loading the tool storage file. Please only load tool storage files created with the NavigationToolManager view."; QMessageBox::warning(nullptr, "Tool Storage Loading Error", errormessage.c_str()); return; } if (m_toolStorage->isEmpty()) { errorMessage = myDeserializer->GetErrorMessage(); MessageBox(errorMessage); return; } //update label UpdateToolStorageLabel(filename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); //save filename for persistent storage m_ToolStorageFilename = filename; } void QmitkMITKIGTTrackingToolboxView::OnResetTools() { //remove data nodes of surfaces from data storage to clean up for (unsigned int i = 0; i < m_toolStorage->GetToolCount(); i++) { this->GetDataStorage()->Remove(m_toolStorage->GetTool(i)->GetDataNode()); } this->ReplaceCurrentToolStorage(mitk::NavigationToolStorage::New(GetDataStorage()), "TrackingToolbox Default Storage"); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); QString toolLabel = QString(""); m_Controls->m_ToolLabel->setText(toolLabel); m_ToolStorageFilename = ""; RemoveAllToolProjections(); } void QmitkMITKIGTTrackingToolboxView::OnStartStopTracking() { if (!m_connected) { MITK_WARN << "Can't start tracking if no device is connected. Aborting"; return; } if (m_tracking) { OnStopTracking(); } else { OnStartTracking(); } } void QmitkMITKIGTTrackingToolboxView::OnFreezeUnfreezeTracking() { if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Freeze Tracking") { m_Worker->GetTrackingDeviceSource()->Freeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Unfreeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(true); } else if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Unfreeze Tracking") { m_Worker->GetTrackingDeviceSource()->UnFreeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); } } void QmitkMITKIGTTrackingToolboxView::ShowToolProjection(int index) { mitk::DataNode::Pointer toolnode = m_toolStorage->GetTool(index)->GetDataNode(); QString ToolProjectionName = "ToolProjection" + QString::number(index); m_ToolProjectionNode = this->GetDataStorage()->GetNamedNode(ToolProjectionName.toStdString()); //If node does not exist, create the node for the Pointset if (m_ToolProjectionNode.IsNull()) { m_ToolProjectionNode = mitk::DataNode::New(); m_ToolProjectionNode->SetName(ToolProjectionName.toStdString()); if (index < static_cast(m_NeedleProjectionFilter->GetNumberOfInputs())) { m_NeedleProjectionFilter->SelectInput(index); m_NeedleProjectionFilter->Update(); m_ToolProjectionNode->SetData(m_NeedleProjectionFilter->GetProjection()); m_ToolProjectionNode->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(m_ToolProjectionNode, toolnode); } // this->FireNodeSelected(node); } else { m_ToolProjectionNode->SetBoolProperty("show contour", true); } } void QmitkMITKIGTTrackingToolboxView::RemoveAllToolProjections() { for (size_t i = 0; i < m_toolStorage->GetToolCount(); i++) { QString toolProjectionName = "ToolProjection" + QString::number(i); mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(toolProjectionName.toStdString()); //Deactivate and hide the tool projection if (!node.IsNull()) { this->GetDataStorage()->Remove(node); } } } void QmitkMITKIGTTrackingToolboxView::SelectToolProjection(int idx) { if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { //Deactivate and hide the tool projection if (!m_ToolProjectionNode.IsNull()) { this->GetDataStorage()->Remove(m_ToolProjectionNode); } if (m_NeedleProjectionFilter.IsNotNull()) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // Show the tool projection for the currently selected tool ShowToolProjection(idx); } } void QmitkMITKIGTTrackingToolboxView::OnShowHideToolProjectionClicked() { int index = m_Controls->m_toolselector->currentIndex(); //Activate and show the tool projection if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { ShowToolProjection(index); m_Controls->showHideToolAxisCheckBox->setEnabled(true); } else { RemoveAllToolProjections(); m_Controls->showHideToolAxisCheckBox->setEnabled(false); } if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnShowHideToolAxisClicked() { if( !m_ShowHideToolAxis ) { //Activate and show the tool axis m_NeedleProjectionFilter->ShowToolAxis(true); m_ShowHideToolAxis = true; } else { //Deactivate and hide the tool axis m_NeedleProjectionFilter->ShowToolAxis(false); m_NeedleProjectionFilter->GetProjection()->RemovePointIfExists(2); m_ShowHideToolAxis = false; } //Update the filter if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnConnectDisconnect() { if (m_connected) { OnDisconnect(); } else { OnConnect(); } } void QmitkMITKIGTTrackingToolboxView::OnConnect() { MITK_DEBUG << "Connect Clicked"; //check if everything is ready to start tracking if (this->m_toolStorage.IsNull()) { MessageBox("Error: No Tools Loaded Yet!"); return; } else if (this->m_toolStorage->GetToolCount() == 0) { MessageBox("Error: No Way To Track Without Tools!"); return; } //parse tracking device data mitk::TrackingDeviceData data = mitk::UnspecifiedTrackingTypeInformation::GetDeviceDataUnspecified(); QString qstr = m_Controls->m_VolumeSelectionBox->currentText(); if ((!qstr.isNull()) || (!qstr.isEmpty())) { std::string str = qstr.toStdString(); data = m_DeviceTypeCollection->GetDeviceDataByName(str); //Data will be set later, after device generation } //! [Thread 4] //initialize worker thread m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eConnectDevice); m_Worker->SetTrackingDevice(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()); m_Worker->SetInverseMode(m_Controls->m_InverseMode->isChecked()); m_Worker->SetNavigationToolStorage(this->m_toolStorage); m_Worker->SetTrackingDeviceData(data); //start worker thread m_WorkerThread->start(); //! [Thread 4] //disable buttons this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableDisableTimerButtons(int enable) { bool enableBool = enable; m_Controls->m_UpdateRateOptionsGroupBox->setEnabled(!enableBool); m_Controls->m_RenderWarningLabel->setVisible(enableBool); } void QmitkMITKIGTTrackingToolboxView::OnConnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); //enable buttons this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //! [Thread 6] //get data from worker thread m_TrackingDeviceData = m_Worker->GetTrackingDeviceData(); m_ToolVisualizationFilter = m_Worker->GetToolVisualizationFilter(); if( m_ToolVisualizationFilter.IsNotNull() ) { //Connect the NeedleProjectionFilter to the ToolVisualizationFilter as third filter of the IGT pipeline m_NeedleProjectionFilter->ConnectTo(m_ToolVisualizationFilter); if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { ShowToolProjection(m_Controls->m_toolselector->currentIndex()); } } //! [Thread 6] //enable/disable Buttons DisableOptionsButtons(); DisableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: connected"); m_Controls->m_ConnectDisconnectButton->setText("Disconnect"); m_Controls->m_ConnectSimpleMode->setText("Disconnect"); m_Controls->m_StartStopTrackingButton->setEnabled(true); m_Controls->m_StartTrackingSimpleMode->setEnabled(true); m_connected = true; //During connection, thi sourceID of the tool storage changed. However, Microservice can't be updated on a different thread. //UpdateMicroservice is necessary to use filter to get the right storage belonging to a source. //Don't do it before m_connected is true, as we don't want to call content of OnToolStorageChanged. m_toolStorage->UpdateMicroservice(); } void QmitkMITKIGTTrackingToolboxView::OnDisconnect() { m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eDisconnectDevice); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnDisconnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //enable/disable Buttons m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); EnableOptionsButtons(); EnableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: disconnected"); m_Controls->m_ConnectDisconnectButton->setText("Connect"); m_Controls->m_ConnectSimpleMode->setText("Connect"); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); m_connected = false; } void QmitkMITKIGTTrackingToolboxView::OnStartTracking() { //show tracking volume this->OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); //Reset the view to a defined start. Do it here and not in OnStartTrackingFinished, to give other tracking devices the chance to reset the view to a different direction. this->GlobalReinit(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStartTracking); m_WorkerThread->start(); this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStartTrackingFinished(bool success, QString errorMessage) { //! [Thread 5] m_WorkerThread->quit(); m_WorkerThread->wait(); //! [Thread 5] this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } if (!(m_Controls->m_DisableAllTimers->isChecked())) { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() != 0) m_TrackingRenderTimer->start(1000 / (m_Controls->m_RenderUpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_LogUpdateRate->value())); } else { m_TrackingRenderTimer->start(1000 / (m_Controls->m_UpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_UpdateRate->value())); } } m_Controls->m_TrackingControlLabel->setText("Status: tracking"); //connect the tool visualization widget for (std::size_t i = 0; i < m_Worker->GetTrackingDeviceSource()->GetNumberOfOutputs(); i++) { m_Controls->m_TrackingToolsStatusWidget->AddNavigationData(m_Worker->GetTrackingDeviceSource()->GetOutput(i)); } m_Controls->m_TrackingToolsStatusWidget->ShowStatusLabels(); if (m_Controls->m_ShowToolQuaternions->isChecked()) { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(true); } else { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(false); } //if activated enable open IGT link microservice if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { //create convertion filter m_IGTLConversionFilter = mitk::NavigationDataToIGTLMessageFilter::New(); m_IGTLConversionFilter->SetName("IGT Tracking Toolbox"); QString dataModeSelection = this->m_Controls->m_OpenIGTLinkDataFormat->currentText(); if (dataModeSelection == "TDATA") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTDataMsg); } else if (dataModeSelection == "TRANSFORM") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTransMsg); } else if (dataModeSelection == "QTDATA") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTDataMsg); } else if (dataModeSelection == "POSITION") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTransMsg); } m_IGTLConversionFilter->ConnectTo(m_ToolVisualizationFilter); m_IGTLConversionFilter->RegisterAsMicroservice(); //create server and message provider m_IGTLServer = mitk::IGTLServer::New(false); m_IGTLServer->SetName("Tracking Toolbox IGTL Server"); m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); m_IGTLMessageProvider->RegisterAsMicroservice(); } m_tracking = true; m_Controls->m_ConnectDisconnectButton->setEnabled(false); m_Controls->m_StartStopTrackingButton->setText("Stop Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Stop\nTracking"); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::OnStopTracking() { if (!m_tracking) return; for (unsigned int i = 0; i < m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); i++) { mitk::NavigationData::Pointer currentTool = m_ToolVisualizationFilter->GetOutput(i); if (currentTool->IsDataValid()) { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_INVALID); } } //refresh view and status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_TrackingRenderTimer->stop(); m_TrackingLoggingTimer->stop(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStopTracking); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStopTrackingFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } m_Controls->m_TrackingControlLabel->setText("Status: connected"); if (m_logging) StopLogging(); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_tracking = false; m_Controls->m_StartStopTrackingButton->setText("Start Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Start\nTracking"); m_Controls->m_ConnectDisconnectButton->setEnabled(true); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //unregister open IGT link micro service if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { m_IGTLConversionFilter->UnRegisterMicroservice(); m_IGTLMessageProvider->UnRegisterMicroservice(); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingDeviceChanged() { mitk::TrackingDeviceType Type; if (m_Controls->m_ConfigurationWidget->GetTrackingDevice().IsNotNull()) { Type = m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType(); //enable controls because device is valid m_Controls->m_TrackingToolsFrame->setEnabled(true); m_Controls->m_TrackingControlsFrame->setEnabled(true); } else { Type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); MessageBox("Error: This tracking device is not included in this project. Please make sure that the device is installed and activated in your MITK build."); m_Controls->m_TrackingToolsFrame->setEnabled(false); m_Controls->m_TrackingControlsFrame->setEnabled(false); return; } // Code to enable/disable device specific buttons if (m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { m_Controls->m_AutoDetectTools->setVisible(true); } else { m_Controls->m_AutoDetectTools->setVisible(false); } m_Controls->m_AddSingleTool->setEnabled(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AddSingleToolIsAvailable()); // Code to select appropriate tracking volume for current type std::vector Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(Type); m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingVolumeChanged(QString qstr) { if (qstr.isNull()) return; if (qstr.isEmpty()) return; mitk::TrackingVolumeGenerator::Pointer volumeGenerator = mitk::TrackingVolumeGenerator::New(); std::string str = qstr.toStdString(); mitk::TrackingDeviceData data = m_DeviceTypeCollection->GetDeviceDataByName(str); m_TrackingDeviceData = data; volumeGenerator->SetTrackingDeviceData(data); volumeGenerator->Update(); mitk::Surface::Pointer volumeSurface = volumeGenerator->GetOutput(); m_TrackingVolumeNode->SetData(volumeSurface); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnShowTrackingVolumeChanged() { if (m_Controls->m_ShowTrackingVolume->isChecked()) { OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); m_TrackingVolumeNode->SetOpacity(0.25); } else { m_TrackingVolumeNode->SetOpacity(0.0); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectTools() { if (m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { DisableTrackingConfigurationButtons(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eAutoDetectTools); m_Worker->SetTrackingDevice(m_Controls->m_ConfigurationWidget->GetTrackingDevice().GetPointer()); m_Worker->SetDataStorage(this->GetDataStorage()); m_WorkerThread->start(); - m_TimeoutTimer->start(7000); + m_TimeoutTimer->start(30000); //disable controls until worker thread is finished this->m_Controls->m_MainWidget->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectToolsFinished(bool success, QString errorMessage) { //Check, if the thread is running. There might have been a timeOut inbetween and this causes crashes... if (m_WorkerThread->isRunning()) { m_TimeoutTimer->stop(); m_WorkerThread->quit(); m_WorkerThread->wait(); } //enable controls again this->m_Controls->m_MainWidget->setEnabled(true); EnableTrackingConfigurationButtons(); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); EnableTrackingConfigurationButtons(); return; } mitk::NavigationToolStorage::Pointer autoDetectedStorage = m_Worker->GetNavigationToolStorage(); //save detected tools std::string _autoDetectText; _autoDetectText = "Autodetected "; _autoDetectText.append(this->m_TrackingDeviceData.Line); //This is the device name as string of the current TrackingDevice. _autoDetectText.append(" Storage"); this->ReplaceCurrentToolStorage(autoDetectedStorage, _autoDetectText); //auto save the new storage to hard disc (for persistence) AutoSaveToolStorage(); //update label QString toolLabel = QString("Loaded Tools: ") + QString::number(m_toolStorage->GetToolCount()) + " Tools (Auto Detected)"; m_Controls->m_ToolLabel->setText(toolLabel); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); EnableTrackingConfigurationButtons(); //print a logging message about the detected tools switch (m_toolStorage->GetToolCount()) { case 0: MITK_INFO("IGT Tracking Toolbox") << "Found no tools. Empty ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; case 1: MITK_INFO("IGT Tracking Toolbox") << "Found one tool. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; default: MITK_INFO("IGT Tracking Toolbox") << "Found " << m_toolStorage->GetToolCount() << " tools. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); } } void QmitkMITKIGTTrackingToolboxView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkMITKIGTTrackingToolboxView::UpdateRenderTrackingTimer() { //update filter m_ToolVisualizationFilter->Update(); MITK_DEBUG << "Number of outputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); MITK_DEBUG << "Number of inputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedInputs(); //update tool colors to show tool status for (unsigned int i = 0; i < m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); i++) { mitk::NavigationData::Pointer currentTool = m_ToolVisualizationFilter->GetOutput(i); if (currentTool->IsDataValid()) { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_VALID); } else { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_WARNING); } } //Update the NeedleProjectionFilter if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //refresh view and status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::UpdateLoggingTrackingTimer() { //update logging if (m_logging) { this->m_loggingFilter->Update(); m_loggedFrames = this->m_loggingFilter->GetNumberOfRecordedSteps(); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: " + QString::number(m_loggedFrames)); //check if logging stopped automatically if ((m_loggedFrames > 1) && (!m_loggingFilter->GetRecording())){ StopLogging(); } } //refresh status widget m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnChooseFileClicked() { QDir currentPath = QFileInfo(m_Controls->m_LoggingFileName->text()).dir(); // if no path was selected (QDir would select current working dir then) or the // selected path does not exist -> use home directory if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir(QDir::homePath()); } QString filename = QFileDialog::getSaveFileName(nullptr, tr("Choose Logging File"), currentPath.absolutePath(), "*.*"); if (filename == "") return; this->m_Controls->m_LoggingFileName->setText(filename); this->OnToggleFileExtension(); } // bug-16470: toggle file extension after clicking on radio button void QmitkMITKIGTTrackingToolboxView::OnToggleFileExtension() { QString currentInputText = this->m_Controls->m_LoggingFileName->text(); QString currentFile = QFileInfo(currentInputText).baseName(); QDir currentPath = QFileInfo(currentInputText).dir(); if (currentFile.isEmpty()) { currentFile = "logfile"; } // Setting currentPath to default home path when currentPath is empty or it does not exist if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir::homePath(); } // check if csv radio button is clicked if (this->m_Controls->m_CsvFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".csv"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".csv"); } } // check if xml radio button is clicked else if (this->m_Controls->m_XmlFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".xml"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".xml"); } } } void QmitkMITKIGTTrackingToolboxView::OnToggleAdvancedSimpleMode() { if (m_SimpleModeEnabled) { m_Controls->m_simpleWidget->setVisible(false); m_Controls->m_MainWidget->setVisible(true); m_Controls->m_SimpleUI->setChecked(false); m_SimpleModeEnabled = false; } else { m_Controls->m_simpleWidget->setVisible(true); m_Controls->m_MainWidget->setVisible(false); m_SimpleModeEnabled = true; } } void QmitkMITKIGTTrackingToolboxView::OnToggleDifferentUpdateRates() { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_RenderWarningLabel->setVisible(true); else m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(true); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(true); m_Controls->m_LogUpdateRate->setEnabled(true); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(true); } else { m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(true); m_Controls->m_OptionsUpdateRateLabel->setEnabled(true); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnChangeRenderUpdateRate() { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_RenderWarningLabel->setVisible(true); else m_Controls->m_RenderWarningLabel->setVisible(false); } void QmitkMITKIGTTrackingToolboxView::StartLogging() { if (m_ToolVisualizationFilter.IsNull()) { MessageBox("Cannot activate logging without a connected device. Configure and connect a tracking device first."); return; } if (!m_logging) { //initialize logging filter m_loggingFilter = mitk::NavigationDataRecorder::New(); m_loggingFilter->SetRecordOnlyValidData(m_Controls->m_SkipInvalidData->isChecked()); m_loggingFilter->ConnectTo(m_ToolVisualizationFilter); if (m_Controls->m_LoggingLimit->isChecked()){ m_loggingFilter->SetRecordCountLimit(m_Controls->m_LoggedFramesLimit->value()); } //start filter with try-catch block for exceptions try { m_loggingFilter->StartRecording(); } catch (mitk::IGTException) { std::string errormessage = "Error during start recording. Recorder already started recording?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_loggingFilter->StopRecording(); return; } //update labels / logging variables this->m_Controls->m_LoggingLabel->setText("Logging ON"); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: 0"); m_loggedFrames = 0; m_logging = true; DisableLoggingButtons(); } } void QmitkMITKIGTTrackingToolboxView::StopLogging() { if (m_logging) { //stop logging m_loggingFilter->StopRecording(); m_logging = false; //update GUI this->m_Controls->m_LoggingLabel->setText("Logging OFF"); EnableLoggingButtons(); //write the results to a file if (m_Controls->m_CsvFormat->isChecked()) { mitk::IOUtil::Save(m_loggingFilter->GetNavigationDataSet(), this->m_Controls->m_LoggingFileName->text().toStdString()); } else if (m_Controls->m_XmlFormat->isChecked()) { mitk::IOUtil::Save(m_loggingFilter->GetNavigationDataSet(), this->m_Controls->m_LoggingFileName->text().toStdString()); } } } void QmitkMITKIGTTrackingToolboxView::SetFocus() { } void QmitkMITKIGTTrackingToolboxView::OnAddSingleTool() { QString Identifier = "Tool#"; QString Name = "NewTool"; if (m_toolStorage.IsNotNull()) { Identifier += QString::number(m_toolStorage->GetToolCount()); Name += QString::number(m_toolStorage->GetToolCount()); } else { Identifier += "0"; Name += "0"; } m_Controls->m_NavigationToolCreationWidget->Initialize(GetDataStorage(), Identifier.toStdString(), Name.toStdString()); m_Controls->m_NavigationToolCreationWidget->SetTrackingDeviceType(m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType(), false); m_Controls->m_TrackingToolsWidget->setCurrentIndex(1); //disable tracking volume during tool editing lastTrackingVolumeState = m_Controls->m_ShowTrackingVolume->isChecked(); if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolFinished() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); if (this->m_toolStorage.IsNull()) { //this shouldn't happen! MITK_WARN << "No ToolStorage available, cannot add tool, aborting!"; return; } m_toolStorage->AddTool(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_Controls->m_ToolLabel->setText(""); //displya in tool selector // m_Controls->m_toolselector->addItem(QString::fromStdString(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()->GetToolName())); //auto save current storage for persistence MITK_INFO << "Auto saving manually added tools for persistence."; AutoSaveToolStorage(); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolCanceled() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::GlobalReinit() { // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } void QmitkMITKIGTTrackingToolboxView::DisableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(false); m_Controls->m_LoggingFileName->setEnabled(false); m_Controls->m_ChooseFile->setEnabled(false); m_Controls->m_LoggingLimit->setEnabled(false); m_Controls->m_LoggedFramesLimit->setEnabled(false); m_Controls->m_CsvFormat->setEnabled(false); m_Controls->m_XmlFormat->setEnabled(false); m_Controls->m_SkipInvalidData->setEnabled(false); m_Controls->m_StopLogging->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::EnableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(true); m_Controls->m_LoggingFileName->setEnabled(true); m_Controls->m_ChooseFile->setEnabled(true); m_Controls->m_LoggingLimit->setEnabled(true); m_Controls->m_LoggedFramesLimit->setEnabled(true); m_Controls->m_CsvFormat->setEnabled(true); m_Controls->m_XmlFormat->setEnabled(true); m_Controls->m_SkipInvalidData->setEnabled(true); m_Controls->m_StopLogging->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::DisableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(false); m_Controls->m_UseDifferentUpdateRates->setEnabled(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); m_Controls->m_DisableAllTimers->setEnabled(false); m_Controls->m_OtherOptionsGroupBox->setEnabled(false); m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(false); m_Controls->m_OpenIGTLinkDataFormat->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(true); m_Controls->m_UseDifferentUpdateRates->setEnabled(true); m_Controls->m_DisableAllTimers->setEnabled(true); m_Controls->m_OtherOptionsGroupBox->setEnabled(true); m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(true); m_Controls->m_OpenIGTLinkDataFormat->setEnabled(true); OnToggleDifferentUpdateRates(); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingControls() { m_Controls->m_TrackingControlsFrame->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingControls() { m_Controls->m_TrackingControlsFrame->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(true); m_Controls->m_AddSingleTool->setEnabled(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AddSingleToolIsAvailable()); m_Controls->m_LoadTools->setEnabled(true); m_Controls->m_ResetTools->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(false); m_Controls->m_AddSingleTool->setEnabled(false); m_Controls->m_LoadTools->setEnabled(false); m_Controls->m_ResetTools->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::ReplaceCurrentToolStorage(mitk::NavigationToolStorage::Pointer newStorage, std::string newStorageName) { //first: get rid of the old one //don't reset if there is no tool storage. BugFix #17793 if (m_toolStorage.IsNotNull()){ m_toolStorage->UnLockStorage(); //only to be sure... m_toolStorage->UnRegisterMicroservice(); m_toolStorage = nullptr; } //now: replace by the new one m_toolStorage = newStorage; m_toolStorage->SetName(newStorageName); m_toolStorage->RegisterAsMicroservice(); } void QmitkMITKIGTTrackingToolboxView::OnTimeOut() { MITK_WARN << "TimeOut. Quitting the thread..."; m_WorkerThread->quit(); //only if we can't quit use terminate. if (!m_WorkerThread->wait(1000)) { MITK_ERROR << "Can't quit the thread. Terminating... Might cause further problems, be careful!"; m_WorkerThread->terminate(); m_WorkerThread->wait(); } m_TimeoutTimer->stop(); } void QmitkMITKIGTTrackingToolboxView::OnToolStorageChanged(const ctkServiceEvent event) { //don't listen to any changes during connection, toolStorage is locked anyway, so this are only changes of e.g. sourceID which are not relevant for the widget. if (!m_connected && (event.getType() == ctkServiceEvent::MODIFIED)) { m_Controls->m_ConfigurationWidget->OnToolStorageChanged(); m_Controls->m_toolselector->clear(); for (size_t i = 0; i < m_toolStorage->GetToolCount(); i++) { m_Controls->m_toolselector->addItem(QString::fromStdString(m_toolStorage->GetTool(i)->GetToolName())); } } } //! [StoreUISettings] void QmitkMITKIGTTrackingToolboxView::StoreUISettings() { // persistence service does not directly work in plugins for now // -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); MITK_DEBUG << "Store UI settings"; // set the values of some widgets and attrbutes to the QSettings settings.setValue("ShowTrackingVolume", QVariant(m_Controls->m_ShowTrackingVolume->isChecked())); settings.setValue("toolStorageFilename", QVariant(m_ToolStorageFilename)); settings.setValue("VolumeSelectionBox", QVariant(m_Controls->m_VolumeSelectionBox->currentIndex())); settings.setValue("SimpleModeEnabled", QVariant(m_SimpleModeEnabled)); settings.setValue("OpenIGTLinkDataFormat", QVariant(m_Controls->m_OpenIGTLinkDataFormat->currentIndex())); settings.setValue("EnableOpenIGTLinkMicroService", QVariant(m_Controls->m_EnableOpenIGTLinkMicroService->isChecked())); settings.endGroup(); } //! [StoreUISettings] //! [LoadUISettings] void QmitkMITKIGTTrackingToolboxView::LoadUISettings() { // persistence service does not directly work in plugins for now -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); // set some widgets and attributes by the values from the QSettings - m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", true).toBool()); + m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", false).toBool()); m_Controls->m_EnableOpenIGTLinkMicroService->setChecked(settings.value("EnableOpenIGTLinkMicroService", true).toBool()); m_Controls->m_VolumeSelectionBox->setCurrentIndex(settings.value("VolumeSelectionBox", 0).toInt()); m_Controls->m_OpenIGTLinkDataFormat->setCurrentIndex(settings.value("OpenIGTLinkDataFormat", 0).toInt()); m_ToolStorageFilename = settings.value("toolStorageFilename", QVariant("")).toString(); if (settings.value("SimpleModeEnabled", false).toBool()) { this->OnToggleAdvancedSimpleMode(); } settings.endGroup(); //! [LoadUISettings] //! [LoadToolStorage] // try to deserialize the tool storage from the given tool storage file name if (!m_ToolStorageFilename.isEmpty()) { // try-catch block for exceptions try { mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); m_toolStorage->UnRegisterMicroservice(); m_toolStorage = myDeserializer->Deserialize(m_ToolStorageFilename.toStdString()); m_toolStorage->RegisterAsMicroservice(); //update label UpdateToolStorageLabel(m_ToolStorageFilename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); } - catch (mitk::IGTException) + catch (mitk::IGTException e) { - MITK_WARN("QmitkMITKIGTTrackingToolBoxView") << "Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() << "), please check the file?"; + MITK_WARN("QmitkMITKIGTTrackingToolBoxView") << "Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() << "), please check the file? Error message: "<OnResetTools(); //if there where errors reset the tool storage to avoid problems later on } } //! [LoadToolStorage] } void QmitkMITKIGTTrackingToolboxView::UpdateToolStorageLabel(QString pathOfLoadedStorage) { QFileInfo myPath(pathOfLoadedStorage); //use this to seperate filename from path QString toolLabel = myPath.fileName(); if (toolLabel.size() > 45) //if the tool storage name is to long trimm the string { toolLabel.resize(40); toolLabel += "[...]"; } m_Controls->m_ToolLabel->setText(toolLabel); } void QmitkMITKIGTTrackingToolboxView::AutoSaveToolStorage() { m_ToolStorageFilename = m_AutoSaveFilename; mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); mySerializer->Serialize(m_ToolStorageFilename.toStdString(), m_toolStorage); } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui index 864a7b13ee..8e043ac2f8 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui @@ -1,954 +1,954 @@ QmitkMITKIGTTrackingToolboxViewControls 0 0 - 849 - 701 + 370 + 739 0 0 QmitkTemplate 0 Tracking QFrame::NoFrame QFrame::Raised 0 0 QFrame::NoFrame QFrame::Raised 10 75 true true Tracking Tools Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 ToolStorage: <none> Qt::Horizontal 40 20 0 0 Qt::Horizontal 13 49 120 0 Auto Detection 120 0 Add Single Tool 120 0 Load Tool Storage 120 0 Reset QFrame::NoFrame QFrame::Raised 10 75 true Tracking Control Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Status: disconnected Qt::Horizontal 40 20 142 0 Connect Qt::Horizontal 40 20 142 0 Start Tracking Qt::Horizontal 40 20 <html><head/><body><p><span style=" color:#ff0000;">Tracking Frozen!</span></p></body></html> true 142 0 Freeze Tracking Qt::Vertical 20 40 Options Update Rate Options Update Rate [per second] Qt::Horizontal 40 20 100 - 10 + 30 Use different Render and Log Update Rates false Render Update Rate [fps] Qt::Horizontal 40 20 false 0 100 - 10 + 30 false Log Update Rate [per second] Qt::Horizontal 40 20 false 1 120 10 60 Other Options Show Tool Quaternions Simple UI Caution, only for backward compatibility: Inverse mode (Quaternions are stored inverse) Tracking Volume Options true Show Tracking Volume - true + false Select Model: Tool Visualization Options true Show Tool Projection false Show Tool Axis Open IGT Link Enable Open IGT Link MicroService true Select Open IGT Link Data Format: TRANSFORM QTDATA TDATA POSITION Disable All Timers true <html><head/><body><p align="right"><span style=" color:#ff0000;">Rendering Disabled!</span></p></body></html> Qt::AutoText Qt::Vertical 20 40 Logging Filename: Choose File Limit Number Of Logged Frames: Qt::Horizontal 40 20 1 9999 300 CSV format true XML format Skip invalid data Logging Status Logging OFF Logged Frames: 0 Qt::Horizontal 40 20 Start Logging Stop Logging Qt::Vertical 20 40 9 742 303 70 70 50 Connect 70 50 Start Tracking Qt::Horizontal 40 20 70 50 Advanced Mode QmitkToolTrackingStatusWidget QWidget
QmitkToolTrackingStatusWidget.h
1
QmitkTrackingDeviceConfigurationWidget QWidget
QmitkTrackingDeviceConfigurationWidget.h
1
QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png index 6b31cf0297..62f78ff57a 100644 Binary files a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png and b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png differ diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png index eb0b3ee384..7cb45a0828 100644 Binary files a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png and b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png differ diff --git a/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg b/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg index 50a086ca35..149209316f 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg +++ b/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg @@ -1,31 +1,31 @@ + height="128" + width="128"> image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui index e45fe66627..2c0107ebed 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui @@ -1,1133 +1,1133 @@ ImageCropperControls 0 0 329 863 0 0 QmitkTemplate 3 0 0 QLabel { color: rgb(255, 0, 0) } Please select an image. 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 120 120 120 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 127 0 0 255 255 255 127 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 255 220 0 0 0 Please select a bounding object. false 0 0 0 90 Bounding object 0 0 16777215 16777215 0 0 - New... + New 0 0 Do Cropping Mask 0 0 Crop true 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 255 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 255 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 127 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 127 0 0 255 255 255 127 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 255 220 0 0 0 Image geometry is rotated, result won't be pixel-aligned. You can reinit your image to get a pixel-aligned result, though. Qt::PlainText true 0 0 0 25 Advanced settings false 100 Qt::ToolButtonTextBesideIcon false 0 0 0 120 Output image settings 0 0 Outside pixel value (masking): false 0 0 16777210 16777215 0 0 Overrride original image false 0 0 Only crop current timestep / cut off other timesteps Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
ctkExpandButton QToolButton
ctkExpandButton.h
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp index 42f42ff803..6618810596 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp @@ -1,606 +1,575 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkImageCropper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK: added after using Plugin Generator #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include const std::string QmitkImageCropper::VIEW_ID = "org.mitk.views.qmitkimagecropper"; QmitkImageCropper::QmitkImageCropper(QObject *) : m_ParentWidget(0), m_ImageNode(nullptr), m_CroppingObject(nullptr), m_CroppingObjectNode(nullptr), m_BoundingShapeInteractor(nullptr), m_CropOutsideValue(0), m_Advanced(0), m_Active(0), m_ScrollEnabled(true) { CreateBoundingShapeInteractor(false); } QmitkImageCropper::~QmitkImageCropper() { //delete pointer objects m_CroppingObjectNode = nullptr; m_CroppingObject = nullptr; //disable interactor if (m_BoundingShapeInteractor != nullptr) { m_BoundingShapeInteractor->SetDataNode(nullptr); m_BoundingShapeInteractor->EnableInteraction(false); } } void QmitkImageCropper::SetFocus() { m_Controls.buttonCreateNewBoundingBox->setFocus(); } void QmitkImageCropper::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.boundingShapeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.boundingShapeSelector->SetPredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(DoCropping())); connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(DoMasking())); connect(m_Controls.boundingShapeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnDataSelectionChanged(const mitk::DataNode*))); connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(DoCreateNewBoundingObject())); connect(m_Controls.buttonAdvancedSettings, SIGNAL(clicked()), this, SLOT(OnAdvancedSettingsButtonToggled())); connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); setDefaultGUI(); m_Controls.labelWarningRotation->setVisible(false); - m_BoundingObjectNames.clear(); - m_Advanced = false; this->OnAdvancedSettingsButtonToggled(); m_ParentWidget = parent; } void QmitkImageCropper::OnDataSelectionChanged(const mitk::DataNode*) { m_Controls.boundingShapeSelector->setEnabled(true); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); if (m_CroppingObjectNode.IsNotNull() && dynamic_cast(this->m_CroppingObjectNode->GetData())) { m_Controls.buttonAdvancedSettings->setEnabled(true); m_Controls.labelWarningBB->setVisible(false); m_CroppingObject = dynamic_cast(m_CroppingObjectNode->GetData()); m_Advanced = true; mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { setDefaultGUI(); m_CroppingObject = nullptr; m_BoundingShapeInteractor->EnableInteraction(false); m_BoundingShapeInteractor->SetDataNode(nullptr); m_Advanced = false; this->OnAdvancedSettingsButtonToggled(); } } void QmitkImageCropper::OnAdvancedSettingsButtonToggled() { m_Controls.groupImageSettings->setVisible(m_Advanced); m_Advanced = !m_Advanced; } void QmitkImageCropper::CreateBoundingShapeInteractor(bool rotationEnabled) { if (m_BoundingShapeInteractor.IsNull()) { m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New(); m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); } m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled); } mitk::Geometry3D::Pointer QmitkImageCropper::InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry) { // convert a basegeometry into a Geometry3D (otherwise IO is not working properly) if (geometry == nullptr) mitkThrow() << "Geometry is not valid."; auto boundingGeometry = mitk::Geometry3D::New(); boundingGeometry->SetBounds(geometry->GetBounds()); boundingGeometry->SetImageGeometry(geometry->GetImageGeometry()); boundingGeometry->SetOrigin(geometry->GetOrigin()); boundingGeometry->SetSpacing(geometry->GetSpacing()); boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()); boundingGeometry->Modified(); return boundingGeometry; } -QString QmitkImageCropper::getAdaptedBoundingObjectName(const QString& name) const +QString QmitkImageCropper::AdaptBoundingObjectName(const QString& name) const { - bool nameNotTaken = false; unsigned int counter = 2; - QString newName; - while (!nameNotTaken) + QString newName = QString("%1 %2").arg(name).arg(counter); + + while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node) { - newName = name + "_" + QString::number(counter); - if (!m_BoundingObjectNames.contains(newName)) - { - nameNotTaken = true; - } - ++counter; + return 0 == node->GetName().compare(newName.toStdString()); + }))) + { + newName = QString("%1 %2").arg(name).arg(++counter); } + return newName; } void QmitkImageCropper::DoCreateNewBoundingObject() { if (!m_ImageNode.IsExpired()) { auto imageNode = m_ImageNode.Lock(); + QString name = QString::fromStdString(imageNode->GetName() + " Bounding Shape"); - bool ok = false; - QString defaultName = "BoundingShape"; - if (m_BoundingObjectNames.contains(defaultName)) + auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node) { - defaultName = getAdaptedBoundingObjectName(defaultName); - } - QString name = QInputDialog::getText(QApplication::activeWindow() - , "Add cropping shape...", "Enter name for the new cropping shape", QLineEdit::Normal, defaultName, &ok); - if (!ok) - return; + return 0 == node->GetName().compare(name.toStdString()); + })); - if (name == "") - { - name = "Bounding Shape"; - } - if (m_BoundingObjectNames.contains(name)) - { - name = getAdaptedBoundingObjectName(name); - QMessageBox::information(nullptr, "Information", "Bounding object name already exists. It was changed to: " + name); - } - m_BoundingObjectNames.append(name); + if (nullptr != boundingShape) + name = this->AdaptBoundingObjectName(name); m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.boundingShapeSelector->setEnabled(true); m_Controls.groupImageSettings->setEnabled(true); // get current timestep to support 3d+t images auto renderWindowPart = this->GetRenderWindowPart(OPEN); int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); mitk::BaseGeometry::Pointer imageGeometry = static_cast(imageNode->GetData()->GetGeometry(timeStep)); m_CroppingObject = mitk::GeometryData::New(); m_CroppingObject->SetGeometry(static_cast(this->InitializeWithImageGeometry(imageGeometry))); m_CroppingObjectNode = mitk::DataNode::New(); m_CroppingObjectNode->SetData(m_CroppingObject); m_CroppingObjectNode->SetProperty("name", mitk::StringProperty::New(name.toStdString())); m_CroppingObjectNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); m_CroppingObjectNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); m_CroppingObjectNode->SetProperty("layer", mitk::IntProperty::New(99)); m_CroppingObjectNode->AddProperty("handle size factor", mitk::DoubleProperty::New(1.0 / 40.0)); m_CroppingObjectNode->SetBoolProperty("pickable", true); if (!this->GetDataStorage()->Exists(m_CroppingObjectNode)) { GetDataStorage()->Add(m_CroppingObjectNode, imageNode); m_Controls.boundingShapeSelector->SetSelectedNode(m_CroppingObjectNode); m_CroppingObjectNode->SetVisibility(true); m_BoundingShapeInteractor->EnableInteraction(true); m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); this->OnDataSelectionChanged(m_CroppingObjectNode); } } // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, m_CroppingObjectNode); //// initialize the views to the bounding geometry //mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); //mitk::RenderingManager::GetInstance()->InitializeViews(bounds); //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkImageCropper::setDefaultGUI() { m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); m_Controls.labelWarningImage->setVisible(true); m_Controls.labelWarningBB->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningBB->setText(QString::fromStdString("Create a bounding shape below.")); m_Controls.labelWarningBB->setVisible(true); m_Controls.buttonCreateNewBoundingBox->setEnabled(false); m_Controls.labelWarningRotation->setVisible(false); m_Controls.buttonCropping->setEnabled(false); m_Controls.buttonMasking->setEnabled(false); m_Controls.boundingShapeSelector->setEnabled(false); m_Controls.buttonAdvancedSettings->setEnabled(false); m_Controls.groupImageSettings->setEnabled(false); m_Controls.checkOverwriteImage->setChecked(false); m_Controls.checkBoxCropTimeStepOnly->setChecked(false); } void QmitkImageCropper::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { bool rotationEnabled = false; if (nodes.empty()) { setDefaultGUI(); return; } m_ParentWidget->setEnabled(true); foreach(mitk::DataNode::Pointer node, nodes) { if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_ImageNode = nodes[0]; m_Controls.groupBoundingObject->setEnabled(true); - m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(0, 0, 0) }"); - m_Controls.labelWarningImage->setText(QString::fromStdString("File name: " + nodes[0]->GetName())); + m_Controls.labelWarningImage->setStyleSheet(""); + m_Controls.labelWarningImage->setText(QString::fromStdString("Selected image: " + nodes[0]->GetName())); m_Controls.buttonCreateNewBoundingBox->setEnabled(true); mitk::Image::Pointer image = dynamic_cast(nodes[0]->GetData()); if (image != nullptr) { if (image->GetDimension() < 3) { QMessageBox::warning(nullptr, tr("Invalid image selected"), tr("ImageCropper only works with 3 or more dimensions."), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); setDefaultGUI(); return; } vtkSmartPointer imageMat = image->GetGeometry()->GetVtkMatrix(); // check whether the image geometry is rotated, if so, no pixel aligned cropping or masking can be performed if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) && (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) && (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0)) { rotationEnabled = false; m_Controls.labelWarningRotation->setVisible(false); } else { rotationEnabled = true; m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningRotation->setVisible(true); } this->CreateBoundingShapeInteractor(rotationEnabled); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); if (m_CroppingObjectNode != nullptr) { this->OnDataSelectionChanged(m_CroppingObjectNode); m_BoundingShapeInteractor->EnableInteraction(true); m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); m_Controls.boundingShapeSelector->setEnabled(true); } if (image->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) { // Might be changed with the upcoming new image statistics plugin //(recomputation might be very expensive for large images ;) ) auto statistics = image->GetStatistics(); auto minPixelValue = statistics->GetScalarValueMin(); auto maxPixelValue = statistics->GetScalarValueMax(); if (minPixelValue < std::numeric_limits::min()) { minPixelValue = std::numeric_limits::min(); } if (maxPixelValue > std::numeric_limits::max()) { maxPixelValue = std::numeric_limits::max(); } m_Controls.spinBoxOutsidePixelValue->setEnabled(true); m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast(maxPixelValue)); m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast(minPixelValue)); m_Controls.spinBoxOutsidePixelValue->setValue(static_cast(minPixelValue)); } else { m_Controls.spinBoxOutsidePixelValue->setEnabled(false); } unsigned int dim = image->GetDimension(); if (dim < 2 || dim > 4) { m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); m_ParentWidget->setEnabled(false); } if (m_CroppingObjectNode != nullptr) { m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.boundingShapeSelector->setEnabled(true); m_Controls.labelWarningBB->setVisible(false); } else { m_Controls.buttonCropping->setEnabled(false); m_Controls.buttonMasking->setEnabled(false); m_Controls.boundingShapeSelector->setEnabled(false); m_Controls.labelWarningBB->setVisible(true); } return; } // iterate all selected objects, adjust warning visibility setDefaultGUI(); m_ParentWidget->setEnabled(true); m_Controls.labelWarningRotation->setVisible(false); } } } -void QmitkImageCropper::NodeRemoved(const mitk::DataNode * node) -{ - QList::iterator it = m_BoundingObjectNames.begin(); - while (it != m_BoundingObjectNames.end()) - { - if (node->GetName() == it->toStdString()) - { - it = m_BoundingObjectNames.erase(it); - } - else - { - ++it; - } - } -} - void QmitkImageCropper::OnComboBoxSelectionChanged(const mitk::DataNode* node) { mitk::DataNode* selectedNode = const_cast(node); if (selectedNode != nullptr) { if (!m_ImageNode.IsExpired()) selectedNode->SetDataInteractor(m_ImageNode.Lock()->GetDataInteractor()); // m_ImageNode->GetDataInteractor()->SetDataNode(selectedNode); m_ImageNode = selectedNode; } } void QmitkImageCropper::OnSliderValueChanged(int slidervalue) { m_CropOutsideValue = slidervalue; } void QmitkImageCropper::DoMasking() { this->ProcessImage(true); } void QmitkImageCropper::DoCropping() { this->ProcessImage(false); } void QmitkImageCropper::ProcessImage(bool mask) { // cropping only possible if valid bounding shape as well as a valid image are loaded QList nodes = this->GetDataManagerSelection(); auto renderWindowPart = this->GetRenderWindowPart(OPEN); int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); if (nodes.empty()) return; mitk::DataNode* node = nodes[0]; if (node == nullptr) { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); return; } if (m_CroppingObject == nullptr) { QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing."); return; } mitk::BaseData* data = node->GetData(); //get data from node if (data != nullptr) { QString imageName; if (mask) { imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_masked"); } else { imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_cropped"); } if (m_Controls.checkBoxCropTimeStepOnly->isChecked()) { imageName = imageName + "_T" + QString::number(timeStep); } // image and bounding shape ok, set as input auto croppedImageNode = mitk::DataNode::New(); auto cutter = mitk::BoundingShapeCropper::New(); cutter->SetGeometry(m_CroppingObject); // adjustable in advanced settings cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false) cutter->SetOutsideValue(m_CropOutsideValue); cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked()); cutter->SetCurrentTimeStep(timeStep); // TODO: Add support for MultiLayer (right now only Mulitlabel support) mitk::LabelSetImage* labelsetImageInput = dynamic_cast(data); if (labelsetImageInput != nullptr) { cutter->SetInput(labelsetImageInput); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } auto labelSetImage = mitk::LabelSetImage::New(); labelSetImage->InitializeByLabeledImage(cutter->GetOutput()); for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++) { labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i)); } croppedImageNode->SetData(labelSetImage); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { node->SetData(labelSetImage); node->Modified(); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, node); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else { mitk::Image::Pointer imageInput = dynamic_cast(data); if (imageInput != nullptr) { cutter->SetInput(imageInput); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { croppedImageNode->SetData(cutter->GetOutput()); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); croppedImageNode->SetProperty("layer", mitk::IntProperty::New(99)); // arbitrary, copied from segmentation functionality if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { node->SetData(cutter->GetOutput()); node->Modified(); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, node); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } } else { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); } } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h index 6c70c8fe40..845ab34055 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h @@ -1,179 +1,173 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QmitkImageCropper_h #define QmitkImageCropper_h #include #ifdef WIN32 #pragma warning( disable : 4250 ) #endif #include #include "QmitkRegisterClasses.h" #include #include "itkCommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_ImageCropperControls.h" #include "usServiceRegistration.h" /*! @brief QmitkImageCropperView \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkImageCropper : 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) private: Q_OBJECT public: /*! @brief Constructor. Called by SampleApp (or other apps that use functionalities) */ QmitkImageCropper(QObject *parent = 0); virtual ~QmitkImageCropper(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); virtual void SetFocus() override; /*! @brief Creates the Qt connections needed */ QWidget* GetControls(); /// @brief Called when the user clicks the GUI button protected slots: /*! * @brief Creates a new bounding object */ virtual void DoCreateNewBoundingObject(); /*! * @brief Whenever Crop button is pressed, issue a cropping action */ void DoCropping(); /*! * @brief Whenever Mask button is pressed, issue a masking action */ void DoMasking(); /*! * @brief Dis- or enable the advanced setting section */ void OnAdvancedSettingsButtonToggled(); /*! * @brief Updates current selection of the bounding object */ void OnDataSelectionChanged(const mitk::DataNode* node); /*! * @brief Sets the scalar value for outside pixels in case of masking */ void OnSliderValueChanged(int slidervalue); protected: /*! @brief called by QmitkFunctionality when DataManager's selection has changed */ void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; /*! - @brief called by QmitkFunctionality when DataNode is removed from DataManager - */ - void NodeRemoved(const mitk::DataNode* node) override; - /*! @brief Sets the selected bounding object as current bounding object and set up interactor */ void OnComboBoxSelectionChanged(const mitk::DataNode* node); /*! * @brief Initializes a new bounding shape using the selected image geometry. */ mitk::Geometry3D::Pointer InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry); void CreateBoundingShapeInteractor(bool rotationEnabled); private: /*! * The parent QWidget */ QWidget* m_ParentWidget; /*! * @brief A pointer to the node of the image to be cropped. */ mitk::WeakPointer m_ImageNode; /*! * @brief The cuboid used for cropping. */ mitk::GeometryData::Pointer m_CroppingObject; /*! * @brief Tree node of the cuboid used for cropping. */ mitk::DataNode::Pointer m_CroppingObjectNode; /*! * @brief Interactor for moving and scaling the cuboid */ mitk::BoundingShapeInteractor::Pointer m_BoundingShapeInteractor; void ProcessImage(bool crop); - QList m_BoundingObjectNames; - /*! * @brief Resets GUI to default */ void setDefaultGUI(); - QString getAdaptedBoundingObjectName(const QString& name) const; + QString AdaptBoundingObjectName(const QString& name) const; // cropping parameter mitk::ScalarType m_CropOutsideValue; bool m_Advanced; bool m_Active; bool m_ScrollEnabled; Ui::ImageCropperControls m_Controls; }; #endif // QmitkImageCropper_h diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg index 949e311a9f..639a54b9c3 100644 --- a/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg +++ b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg @@ -1,88 +1,88 @@ image/svg+xml \ No newline at end of file + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg index 308bf09546..5bae539eb8 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:zoom="4" + inkscape:cx="-105.61111" + inkscape:cy="108.17143" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:0.99999994" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png index cbf2067d84..567bee6f1d 100644 Binary files a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png and b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png differ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox index 05b657bdeb..71a6a17ed4 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox @@ -1,19 +1,19 @@ /** \page org_mitk_views_screenshotmaker The Screenshot Maker This view provides the functionality to create and save screenshots of the data. Available sections: - \ref QmitkScreenshotMakerUserManualUse \imageMacro{QmitkMovieMaker_ScreenshotMakerInterface.png,"The Screenshot Maker User Interface",7.09} \section QmitkScreenshotMakerUserManualUse Usage The first section offers the option of creating a screenshot of the last activated render window (thus the one, which was last clicked into). Upon clicking the button, the Screenshot Maker asks for a filename in which the screenshot is to be stored. The multiplanar Screenshot button asks for a folder, where screenshots of the three 2D views will be stored with default names. The high resolution screenshot section works the same as the simple screenshot section, aside from the fact, that the user can choose a magnification factor. -In the option section one can rotate the camera in the 3D view by using the buttons. Furthermore one can choose the background colour for the screenshots, default is black. +In the option section one can choose the background color for the screenshots, default is black. */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg index 2d02fb8175..83bd2c07d1 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg +++ b/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:0.99999964" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg index 2ea461af15..2cb2d02eae 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg +++ b/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:1.00000167" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp index 12b65c6b6e..413aca9909 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp @@ -1,448 +1,427 @@ /*=================================================================== 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 "QmitkScreenshotMaker.h" //#include "QmitkMovieMakerControls.h" #include "QmitkStepperAdapter.h" #include "mitkVtkPropRenderer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "qapplication.h" #include "vtkImageWriter.h" #include "vtkJPEGWriter.h" #include "vtkPNGWriter.h" #include "vtkRenderLargeImage.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTestUtilities.h" #include #include "vtkMitkRenderProp.h" #include #include #include "vtkRenderWindowInteractor.h" #include #include "mitkSliceNavigationController.h" #include "mitkPlanarFigure.h" QmitkScreenshotMaker::QmitkScreenshotMaker(QObject *parent, const char * /*name*/) : QmitkAbstractView(), m_Controls(nullptr), m_BackgroundColor(QColor(0,0,0)), m_SelectedNode(0) { parentWidget = parent; } QmitkScreenshotMaker::~QmitkScreenshotMaker() { } void QmitkScreenshotMaker::CreateConnections() { if (m_Controls) { connect((QObject*) m_Controls->m_AllViews, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanar3DHighresScreenshot())); - connect((QObject*) m_Controls->m_View1, SIGNAL(clicked()), (QObject*) this, SLOT(View1())); - connect((QObject*) m_Controls->m_View2, SIGNAL(clicked()), (QObject*) this, SLOT(View2())); - connect((QObject*) m_Controls->m_View3, SIGNAL(clicked()), (QObject*) this, SLOT(View3())); connect((QObject*) m_Controls->m_Shot, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanarScreenshots())); connect((QObject*) m_Controls->m_BackgroundColor, SIGNAL(clicked()), (QObject*) this, SLOT(SelectBackgroundColor())); connect((QObject*) m_Controls->btnScreenshot, SIGNAL(clicked()), this, SLOT(GenerateScreenshot())); connect((QObject*) m_Controls->m_HRScreenshot, SIGNAL(clicked()), this, SLOT(Generate3DHighresScreenshot())); QString styleSheet = "background-color:rgb(0,0,0)"; m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } } void QmitkScreenshotMaker::GenerateScreenshot() { if (m_LastFile.size()==0) m_LastFile = QDir::currentPath()+"/screenshot.png"; QString filter; QString fileName = QFileDialog::getSaveFileName(nullptr, "Save screenshot to...", m_LastFile, m_PNGExtension + ";;" + m_JPGExtension, &filter); if (fileName.size()>0) m_LastFile = fileName; auto renderWindowPart = this->GetRenderWindowPart(OPEN); mitk::BaseRenderer* renderer = renderWindowPart->GetActiveQmitkRenderWindow()->GetRenderer(); renderer = nullptr; // WORKAROUND FOR T23702 if (renderer == nullptr) { renderer = renderWindowPart->GetQmitkRenderWindow(m_Controls->m_DirectionBox->currentText())->GetRenderer(); if (renderer == nullptr) return; } this->TakeScreenshot(renderer->GetVtkRenderer(), 1, fileName, filter); } void QmitkScreenshotMaker::GenerateMultiplanarScreenshots() { if (m_LastPath.size()==0) m_LastPath = QDir::currentPath(); QString filePath = QFileDialog::getExistingDirectory(nullptr, "Save screenshots to...", m_LastPath); if (filePath.size()>0) m_LastPath = filePath; if( filePath.isEmpty() ) { return; } //emit StartBlockControls(); auto renderWindowPart = this->GetRenderWindowPart(OPEN); renderWindowPart->EnableDecorations(false, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); QString fileName = "/axial.png"; int c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/axial_"); fileName += QString::number(c); fileName += ".png"; c++; } vtkRenderer* renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); fileName = "/sagittal.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/sagittal_"); fileName += QString::number(c); fileName += ".png"; c++; } renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); fileName = "/coronal.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/coronal_"); fileName += QString::number(c); fileName += ".png"; c++; } renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); /// TODO I do not find a simple way of doing this through the render window part API, /// however, I am also not convinced that this code is needed at all. The colour /// of the crosshair planes is never set to any colour other than these. /// I suggest a new 'mitk::DataNode* mitk::ILinkedRendererPart::GetSlicingPlane(const std::string& name) const' /// function to introduce that could return the individual ("axial", "sagittal" or /// "coronal" crosshair planes. // mitk::DataNode* n = renderWindowPart->GetSlicingPlane("axial"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 1,0,0 ) ); // } // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 0,1,0 ) ); // } // // n = renderWindowPart->GetSlicingPlane("coronal"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 0,0,1 ) ); // } renderWindowPart->EnableDecorations(true, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); } void QmitkScreenshotMaker::Generate3DHighresScreenshot() { if (m_LastFile.size()==0) m_LastFile = QDir::currentPath()+"/3D_screenshot.png"; QString filter; QString fileName = QFileDialog::getSaveFileName(nullptr, "Save screenshot to...", m_LastFile, m_PNGExtension + ";;" + m_JPGExtension, &filter); if (fileName.size()>0) m_LastFile = fileName; GenerateHR3DAtlasScreenshots(fileName, filter); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::GenerateMultiplanar3DHighresScreenshot() { if (m_LastPath.size()==0) m_LastPath = QDir::currentPath(); QString filePath = QFileDialog::getExistingDirectory( nullptr, "Save screenshots to...", m_LastPath); if (filePath.size()>0) m_LastPath = filePath; if( filePath.isEmpty() ) { return; } QString fileName = "/3D_View1.png"; int c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View1_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Azimuth( -7.5 ); GetCam()->Roll(-4); GenerateHR3DAtlasScreenshots(filePath+fileName); GetCam()->Roll(4); fileName = "/3D_View2.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View2_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Azimuth( 90 ); GetCam()->Elevation( 4 ); GenerateHR3DAtlasScreenshots(filePath+fileName); fileName = "/3D_View3.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View3_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Elevation( 90 ); GetCam()->Roll( -2.5 ); GenerateHR3DAtlasScreenshots(filePath+fileName); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::GenerateHR3DAtlasScreenshots(QString fileName, QString filter) { // only works correctly for 3D RenderWindow this->GetRenderWindowPart()->EnableDecorations(false, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); vtkRenderer* renderer = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer(); if (renderer == nullptr) return; this->TakeScreenshot(renderer, this->m_Controls->m_MagFactor->text().toFloat(), fileName, filter); this->GetRenderWindowPart()->EnableDecorations(true, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); } vtkCamera* QmitkScreenshotMaker::GetCam() { mitk::BaseRenderer* renderer = this->GetRenderWindowPart(OPEN)->GetQmitkRenderWindow("3d")->GetRenderer(); vtkCamera* cam = 0; const mitk::VtkPropRenderer *propRenderer = dynamic_cast( renderer ); if (propRenderer) { // get vtk renderer vtkRenderer* vtkrenderer = propRenderer->GetVtkRenderer(); if (vtkrenderer) { // get vtk camera vtkCamera* vtkcam = vtkrenderer->GetActiveCamera(); if (vtkcam) { // vtk smart pointer handling cam = vtkcam; cam->Register( nullptr ); } } } return cam; } -void QmitkScreenshotMaker::View1() -{ - GetCam()->Elevation( 45 ); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkScreenshotMaker::View2() -{ - GetCam()->Azimuth(45); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkScreenshotMaker::View3() -{ - GetCam()->Roll(45); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - void QmitkScreenshotMaker::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if(nodes.size()) m_SelectedNode = nodes[0]; } void QmitkScreenshotMaker::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Parent = parent; m_Controls = new Ui::QmitkScreenshotMakerControls; m_Controls->setupUi(parent); // Initialize "Selected Window" combo box const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); } this->CreateConnections(); } void QmitkScreenshotMaker::SetFocus() { m_Controls->btnScreenshot->setFocus(); } void QmitkScreenshotMaker::RenderWindowPartActivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_Parent->setEnabled(true); } void QmitkScreenshotMaker::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_Parent->setEnabled(false); } void QmitkScreenshotMaker::TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName, QString filter) { if ((renderer == nullptr) ||(magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter* fileWriter = nullptr; QFileInfo fi(fileName); QString suffix = fi.suffix().toLower(); if (suffix.isEmpty() || (suffix != "png" && suffix != "jpg" && suffix != "jpeg")) { if (filter == m_PNGExtension) { suffix = "png"; } else if (filter == m_JPGExtension) { suffix = "jpg"; } fileName += "." + suffix; } if (suffix.compare("jpg", Qt::CaseInsensitive) == 0 || suffix.compare("jpeg", Qt::CaseInsensitive) == 0) { vtkJPEGWriter* w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } else //default is png { fileWriter = vtkPNGWriter::New(); } vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); //magnifier->Update(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); // QColor color = QColorDialog::getColor(); double bgcolor[] = {m_BackgroundColor.red()/255.0, m_BackgroundColor.green()/255.0, m_BackgroundColor.blue()/255.0}; renderer->SetBackground(bgcolor); mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); renderWindowPart->EnableDecorations(false); fileWriter->Write(); fileWriter->Delete(); renderWindowPart->EnableDecorations(true); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void QmitkScreenshotMaker::SelectBackgroundColor() { m_BackgroundColor = QColorDialog::getColor(); m_Controls->m_BackgroundColor->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(m_BackgroundColor.red())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.green())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.blue())); styleSheet.append(")"); m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h index d5028f4715..3fde4127d5 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h @@ -1,132 +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. ===================================================================*/ #if !defined(QMITK_ScreenshotMaker_H__INCLUDED) #define QMITK_ScreenshotMaker_H__INCLUDED #include #include #include "mitkCameraRotationController.h" #include "mitkStepper.h" #include "mitkMultiStepper.h" #include "mitkMovieGenerator.h" #include "itkCommand.h" #include "vtkEventQtSlotConnect.h" #include "vtkRenderWindow.h" #include "mitkVtkPropRenderer.h" #include "ui_QmitkScreenshotMakerControls.h" //#include "../MovieMakerDll.h" //class QmitkMovieMakerControls; class QmitkStepperAdapter; class vtkCamera; class QTimer; class QTime; /** * \brief View for creating movies (AVIs) */ class QmitkScreenshotMaker: public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: /** \brief Constructor. */ QmitkScreenshotMaker(QObject *parent=0, const char *name=0); /** \brief Destructor. */ virtual ~QmitkScreenshotMaker(); /** \brief Method for creating the widget containing the application * controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; // virtual QWidget * CreateControlWidget(QWidget *parent); /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; /** \brief Method for creating the connections of main and control widget. */ virtual void CreateConnections(); /** \brief Method for creating an QAction object, i.e. button & menu entry. * @param parent the parent QWidget */ // virtual QAction * CreateAction(QActionGroup *parent); /// /// Called when a RenderWindowPart becomes available. /// virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; /// /// Called when a RenderWindowPart becomes unavailable. /// virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; signals: protected slots: void GenerateScreenshot(); void GenerateMultiplanarScreenshots(); void Generate3DHighresScreenshot(); void GenerateMultiplanar3DHighresScreenshot(); - void View1(); - void View2(); - void View3(); void SelectBackgroundColor(); protected: QObject *parentWidget; QWidget* m_Parent; vtkEventQtSlotConnect * connections; vtkRenderWindow * renderWindow; mitk::VtkPropRenderer::Pointer m_PropRenderer; Ui::QmitkScreenshotMakerControls* m_Controls; private: virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; vtkCamera* GetCam(); void GenerateHR3DAtlasScreenshots(QString fileName, QString filter = ""); void GenerateMultiplanarScreenshots(QString fileName); /*! \brief taking a screenshot "from" the specified renderer \param magnificationFactor specifying the quality of the screenshot (the magnification of the actual RenderWindow size) \param fileName file location and name where the screenshot should be saved */ void TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName, QString filter = ""); QColor m_BackgroundColor; mitk::DataNode* m_SelectedNode; QString m_LastPath; QString m_LastFile; QString m_PNGExtension = "PNG File (*.png)"; QString m_JPGExtension = "JPEG File (*.jpg)"; }; #endif // !defined(QMITK_ScreenshotMaker_H__INCLUDED) diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui index d406327559..f80d180dac 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui @@ -1,241 +1,175 @@ QmitkScreenshotMakerControls 0 0 315 368 ScreenshotMaker 2D Screenshots axial coronal sagittal Single Multiplanar 3D Screenshots (High-res) Single Multiplanar 0 0 Upsampling: 1 4 Options - - - - 30 - 30 - - - - - 30 - 30 - - - - Rotate 3D camera 45° around x-axis. - - - x - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - Rotate 3D camera 45° around y-axis. - + - y + Background Color: - + 30 30 30 30 - - Rotate 3D camera 45° around z-axis. - - z + Qt::Horizontal - 36 + 40 20 - - - - Background Color: - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - - - Qt::Vertical 20 31 diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg index da31b05f86..8002f7c6ec 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg @@ -1,49 +1,49 @@ image/svg+xml \ No newline at end of file + style="stroke:none;fill:#00ff00;fill-opacity:1" /> diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg index 8e87197c19..fa91872af4 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg @@ -1,62 +1,62 @@ image/svg+xml \ No newline at end of file + y="1301.3301" /> diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg index ab962c118b..23e71640e5 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg @@ -1,74 +1,74 @@ image/svg+xml \ No newline at end of file + style="fill:none;stroke:#00ff00;stroke-width:56.69291306;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml b/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml index 0f6f71c23d..6abe4aa718 100644 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml @@ -1,10 +1,10 @@ diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml b/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml index 98e852ca8a..54ddf557d0 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml @@ -1,20 +1,20 @@ - + Resampling an Image to an specific sizes diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui index da47359e1b..46da982a20 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui @@ -1,316 +1,286 @@ QmitkPreprocessingResamplingViewControls 0 0 448 980 Form - Resample multiple images + Resample all selected images - - true - - - 0 - - - 6 - - - 0 - - - 6 - - Select an Image in Data Manager + Select an image in the Data Manager true false Output image will be 3D Choose time step if 4D (Slider for both images) false false Output image will be 3D Qt::Vertical 254 403 Resample single image - - true - - - 0 - - - 6 - - - 0 - - - 0 - true 0 0 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 5 -100.000000000000000 100.000000000000000 1.000000000000000 true 0 0 5 -100.000000000000000 100.000000000000000 1.000000000000000 true 0 0 5 -100.000000000000000 100.000000000000000 1.000000000000000 false Resampling Parameter false false x-spacing false false y-spacing false false Hide Original Image true false z-spacing false Interpolation: true 0 0 QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
dsbParam1 dsbParam2 dsbParam3 cbParam4 cbHideOrig btnDoIt buttonExecuteOnMultipleImages leImage1
diff --git a/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg b/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg index fc92b414ed..d0e8f3e4ae 100644 --- a/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg +++ b/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg @@ -1,54 +1,54 @@ image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG index 85e7b4e2aa..88e58d95d8 100644 Binary files a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG and b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG differ diff --git a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml index 322e175fee..56282d66a3 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml @@ -1,94 +1,94 @@ Allows the segmentation of images using different tools. - + Edit segmentations using standard operations. diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui index b18eaa0099..ac4f331307 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui @@ -1,121 +1,121 @@ QmitkToFUtilViewControls 0 0 466 452 0 0 QmitkTemplate - - + + - - - - Qt::Vertical - - - - 20 - 311 - - - - - + 0 0 - + 0 0 - - - - + true 0 0 - + + + + + + + + Qt::Vertical + + + + 20 + 311 + + + + QmitkToFRecorderWidget QWidget
QmitkToFRecorderWidget.h
1
QmitkToFVisualisationSettingsWidget QWidget
QmitkToFVisualisationSettingsWidget.h
1
QmitkToFCompositeFilterWidget QWidget
QmitkToFCompositeFilterWidget.h
1
QmitkToFPointSetWidget QWidget
QmitkToFPointSetWidget.h
1
QmitkToFConnectionWidget QWidget
QmitkToFConnectionWidget.h
1
QmitkToFSurfaceGenerationWidget QWidget
QmitkToFSurfaceGenerationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg b/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg index 42903c095d..e86842ff3d 100644 --- a/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg +++ b/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:zoom="4" + inkscape:cx="216.70067" + inkscape:cy="104.11174" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke-width:1.00000525" + inkscape:connector-curvature="0" />